Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index c7ed01b..ac0797e 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -13,14 +13,17 @@
 The framework provides generic functions (mostly kernel API calls), such as:
 
 - Transport Stream URB handling in conjunction with dvb-demux-feed-control
-  (bulk and isoc (TODO) are supported)
+  (bulk and isoc are supported)
 - registering the device for the DVB-API
 - registering an I2C-adapter if applicable
 - remote-control/input-device handling
 - firmware requesting and loading (currently just for the Cypress USB
-  controller)
+  controllers)
 - other functions/methods which can be shared by several drivers (such as
   functions for bulk-control-commands)
+- TODO: a I2C-chunker. It creates device-specific chunks of register-accesses
+  depending on length of a register and the number of values that can be
+  multi-written and multi-read.
 
 The source code of the particular DVB USB devices does just the communication
 with the device via the bus. The connection between the DVB-API-functionality
@@ -36,93 +39,18 @@
 TODO: dynamic enabling and disabling of the pid-filter in regard to number of
 feeds requested.
 
-Supported devices USB1.1
+Supported devices
 ========================
 
-Produced and reselled by Twinhan:
----------------------------------
-- TwinhanDTV USB-Ter DVB-T Device (VP7041)
-	http://www.twinhan.com/product_terrestrial_3.asp
+See the LinuxTV DVB Wiki at www.linuxtv.org for a complete list of
+cards/drivers/firmwares:
 
-- TwinhanDTV Magic Box (VP7041e)
-	http://www.twinhan.com/product_terrestrial_4.asp
-
-- HAMA DVB-T USB device
-	http://www.hama.de/portal/articleId*110620/action*2598
-
-- CTS Portable (Chinese Television System) (2)
-	http://www.2cts.tv/ctsportable/
-
-- Unknown USB DVB-T device with vendor ID Hyper-Paltek
-
-
-Produced and reselled by KWorld:
---------------------------------
-- KWorld V-Stream XPERT DTV DVB-T USB
-	http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html
-
-- JetWay DTV DVB-T USB
-	http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm
-
-- ADSTech Instant TV DVB-T USB
-	http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333
-
-
-Others:
--------
-- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
-	http://82.161.246.249/products-tvbox.html
-
-- Compro Videomate DVB-U2000 - DVB-T USB (2)
-	http://www.comprousa.com/products/vmu2000.htm
-
-- Grandtec USB DVB-T
-	http://www.grand.com.tw/
-
-- AVerMedia AverTV DVBT USB
-	http://www.avermedia.com/
-
-- DiBcom USB DVB-T reference device (non-public)
-
-
-Supported devices USB2.0-only
-=============================
-- Twinhan MagicBox II
-	http://www.twinhan.com/product_terrestrial_7.asp
-
-- TwinhanDTV Alpha
-	http://www.twinhan.com/product_terrestrial_8.asp
-
-- DigitalNow TinyUSB 2 DVB-t Receiver
-	http://www.digitalnow.com.au/DigitalNow%20tinyUSB2%20Specifications.html
-
-- Hanftek UMT-010
-	http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
-
-
-Supported devices USB2.0 and USB1.1
-=============================
-- Typhoon/Yakumo/HAMA/Yuan DVB-T mobile USB2.0
-	http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
-	http://www.yuan.com.tw/en/products/vdo_ub300.html
-	http://www.hama.de/portal/articleId*114663/action*2563
-	http://www.anubisline.com/english/articlec.asp?id=50502&catid=002
-
-- Artec T1 USB TVBOX (FX2) (2)
-
-- Hauppauge WinTV NOVA-T USB2
-	http://www.hauppauge.com/
-
-- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
-
-- DiBcom USB2.0 DVB-T reference device (non-public)
-
-- AVerMedia AverTV A800 DVB-T USB2.0
-
-1) It is working almost - work-in-progress.
-2) No test reports received yet.
+http://www.linuxtv.org/wiki/index.php/DVB_USB
 
 0. History & News:
+  2005-06-30 - added support for WideView WT-220U (Thanks to Steve Chang)
+  2005-05-30 - added basic isochronous support to the dvb-usb-framework
+               added support for Conexant Hybrid reference design and Nebula DigiTV USB
   2005-04-17 - all dibusb devices ported to make use of the dvb-usb-framework
   2005-04-02 - re-enabled and improved remote control code.
   2005-03-31 - ported the Yakumo/Hama/Typhoon DVB-T USB2.0 device to dvb-usb.
@@ -137,7 +65,7 @@
   2005-01-31 - distorted streaming is gone for USB1.1 devices
   2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
              - first almost working version for HanfTek UMT-010
-             - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
+             - found out, that Yakumo/HAMA/Typhoon are predecessors of the HanfTek UMT-010
   2005-01-10 - refactoring completed, now everything is very delightful
              - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
                Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
@@ -187,25 +115,13 @@
 1. How to use?
 1.1. Firmware
 
-Most of the USB drivers need to download a firmware to start working.
+Most of the USB drivers need to download a firmware to the device before start
+working.
 
-for USB1.1 (AN2135) you need: dvb-usb-dibusb-5.0.0.11.fw
-for USB2.0 HanfTek: dvb-usb-umt-010-02.fw
-for USB2.0 DiBcom: dvb-usb-dibusb-6.0.0.8.fw
-for USB2.0 AVerMedia AverTV DVB-T USB2: dvb-usb-avertv-a800-01.fw
-for USB2.0 TwinhanDTV Alpha/MagicBox II: dvb-usb-vp7045-01.fw
+Have a look at the Wikipage for the DVB-USB-drivers to find out, which firmware
+you need for your device:
 
-The files can be found on http://www.linuxtv.org/download/firmware/ .
-
-We do not have the permission (yet) to publish the following firmware-files.
-You'll need to extract them from the windows drivers.
-
-You should be able to use "get_dvb_firmware dvb-usb" to get the firmware:
-
-for USB1.1 (AN2235) (a few Artec T1 devices): dvb-usb-dibusb-an2235-01.fw
-for USB2.0 Hauppauge: dvb-usb-nova-t-usb2-01.fw
-for USB2.0 ADSTech/Kworld USB2.0: dvb-usb-adstech-usb2-01.fw
-for USB2.0 Yakumo/Typhoon/Hama: dvb-usb-dtt200u-01.fw
+http://www.linuxtv.org/wiki/index.php/DVB_USB
 
 1.2. Compiling
 
@@ -289,6 +205,9 @@
    Gunnar Wittich and Joachim von Caron for their trust for providing
     root-shells on their machines to implement support for new devices.
 
+   Allan Third and Michael Hutchinson for their help to write the Nebula
+    digitv-driver.
+
    Glen Harris for bringing up, that there is a new dibusb-device and Jiun-Kuei
     Jung from AVerMedia who kindly provided a special firmware to get the device
     up and running in Linux.
@@ -296,7 +215,12 @@
    Jennifer Chen, Jeff and Jack from Twinhan for kindly supporting by
 	writing the vp7045-driver.
 
-   Some guys on the linux-dvb mailing list for encouraging me
+   Steve Chang from WideView for providing information for new devices and
+	firmware files.
+
+   Michael Paxton for submitting remote control keymaps.
+
+   Some guys on the linux-dvb mailing list for encouraging me.
 
    Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
     user-level firmware loader, which saves a lot of time
@@ -305,4 +229,4 @@
    Ulf Hermenau for helping me out with traditional chinese.
 
    André Smoktun and Christian Frömmel for supporting me with
-    hardware and listening to my problems very patient.
+    hardware and listening to my problems very patiently.
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index 3a32607..e6b8d05 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -1,66 +1,55 @@
-How to get the Nebula, PCTV and Twinhan DST cards working
-=========================================================
+How to get the Nebula Electronics DigiTV, Pinnacle PCTV Sat, Twinhan DST + clones working
+=========================================================================================
 
-This class of cards has a bt878a as the PCI interface, and
-require the bttv driver.
+1) General information
+======================
 
-Please pay close attention to the warning about the bttv module
-options below for the DST card.
+This class of cards has a bt878a chip as the PCI interface.
+The different card drivers require the bttv driver to provide the means
+to access the i2c bus and the gpio pins of the bt8xx chipset.
 
-1) General informations
-=======================
+2) Compilation rules for Kernel >= 2.6.12
+=========================================
 
-These drivers require the bttv driver to provide the means to access
-the i2c bus and the gpio pins of the bt8xx chipset.
+Enable the following options:
 
-Because of this, you need to enable
 "Device drivers" => "Multimedia devices"
-  => "Video For Linux" => "BT848 Video For Linux"
-
-Furthermore you need to enable
+ => "Video For Linux" => "BT848 Video For Linux"
 "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
-  => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
+ => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
 
-2) Loading Modules
-==================
+3) Loading Modules, described by two approaches
+===============================================
 
 In general you need to load the bttv driver, which will handle the gpio and
-i2c communication for us, plus the common dvb-bt8xx device driver.
-The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
-TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
+i2c communication for us, plus the common dvb-bt8xx device driver,
+which is called the backend.
+The frontends for Nebula DigiTV (nxt6000), Pinnacle PCTV Sat (cx24110),
+TwinHan DST + clones (dst and dst-ca) are loaded automatically by the backend.
+For further details about TwinHan DST + clones see /Documentation/dvb/ci.txt.
 
-3a) Nebula / Pinnacle PCTV
+3a) The manual approach
+-----------------------
+
+Loading modules:
+modprobe bttv
+modprobe dvb-bt8xx
+
+Unloading modules:
+modprobe -r dvb-bt8xx
+modprobe -r bttv
+
+3b) The automatic approach
 --------------------------
 
-   $ modprobe bttv (normally bttv is being loaded automatically by kmod)
-   $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
+If not already done by installation, place a line either in
+/etc/modules.conf or in /etc/modprobe.conf containing this text:
+alias char-major-81	bttv
 
+Then place a line in /etc/modules containing this text:
+dvb-bt8xx
 
-3b) TwinHan and Clones
---------------------------
-
-   $ modprobe bttv i2c_hw=1 card=0x71
-   $ modprobe dvb-bt8xx
-   $ modprobe dst
-
-The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which is necessary for TwinHan cards.
-
-If you're having an older card (blue color circuit) and card=0x71 locks
-your machine, try using 0x68, too. If that does not work, ask on the
-mailing list.
-
-The DST module takes a couple of useful parameters:
-
-a. verbose takes values 0 to 5. These values control the verbosity level.
-b. debug takes values 0 and 1. You can either disable or enable debugging.
-c. dst_addons takes values 0 and 0x20:
-- A value of 0 means it is a FTA card.
-- A value of 0x20 means it has a Conditional Access slot.
-
-The autodetected values are determined by the "response string"
-of the card, which you can see in your logs:
-e.g.: dst_get_device_id: Recognize [DSTMCI]
+Reboot your system and have fun!
 
 --
 Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 1d227ee..12dde43 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -119,3 +119,19 @@
 	will be available until removal of old names.
 Who:	Grant Coady <gcoady@gmail.com>
 
+---------------------------
+
+What:	PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
+When:	November 2005
+Files:	drivers/pcmcia/: pcmcia_ioctl.c
+Why:	With the 16-bit PCMCIA subsystem now behaving (almost) like a
+	normal hotpluggable bus, and with it using the default kernel
+	infrastructure (hotplug, driver core, sysfs) keeping the PCMCIA
+	control ioctl needed by cardmgr and cardctl from pcmcia-cs is
+	unnecessary, and makes further cleanups and integration of the
+	PCMCIA subsystem into the Linux kernel device driver model more
+	difficult. The features provided by cardmgr and cardctl are either
+	handled by the kernel itself now or are available in the new
+	pcmciautils package available at
+	http://kernel.org/pub/linux/utils/kernel/pcmcia/
+Who:	Dominik Brodowski <linux@brodo.de>
diff --git a/Documentation/infiniband/user_verbs.txt b/Documentation/infiniband/user_verbs.txt
new file mode 100644
index 0000000..f847501
--- /dev/null
+++ b/Documentation/infiniband/user_verbs.txt
@@ -0,0 +1,69 @@
+USERSPACE VERBS ACCESS
+
+  The ib_uverbs module, built by enabling CONFIG_INFINIBAND_USER_VERBS,
+  enables direct userspace access to IB hardware via "verbs," as
+  described in chapter 11 of the InfiniBand Architecture Specification.
+
+  To use the verbs, the libibverbs library, available from
+  <http://openib.org/>, is required.  libibverbs contains a
+  device-independent API for using the ib_uverbs interface.
+  libibverbs also requires appropriate device-dependent kernel and
+  userspace driver for your InfiniBand hardware.  For example, to use
+  a Mellanox HCA, you will need the ib_mthca kernel module and the
+  libmthca userspace driver be installed.
+
+User-kernel communication
+
+  Userspace communicates with the kernel for slow path, resource
+  management operations via the /dev/infiniband/uverbsN character
+  devices.  Fast path operations are typically performed by writing
+  directly to hardware registers mmap()ed into userspace, with no
+  system call or context switch into the kernel.
+
+  Commands are sent to the kernel via write()s on these device files.
+  The ABI is defined in drivers/infiniband/include/ib_user_verbs.h.
+  The structs for commands that require a response from the kernel
+  contain a 64-bit field used to pass a pointer to an output buffer.
+  Status is returned to userspace as the return value of the write()
+  system call.
+
+Resource management
+
+  Since creation and destruction of all IB resources is done by
+  commands passed through a file descriptor, the kernel can keep track
+  of which resources are attached to a given userspace context.  The
+  ib_uverbs module maintains idr tables that are used to translate
+  between kernel pointers and opaque userspace handles, so that kernel
+  pointers are never exposed to userspace and userspace cannot trick
+  the kernel into following a bogus pointer.
+
+  This also allows the kernel to clean up when a process exits and
+  prevent one process from touching another process's resources.
+
+Memory pinning
+
+  Direct userspace I/O requires that memory regions that are potential
+  I/O targets be kept resident at the same physical address.  The
+  ib_uverbs module manages pinning and unpinning memory regions via
+  get_user_pages() and put_page() calls.  It also accounts for the
+  amount of memory pinned in the process's locked_vm, and checks that
+  unprivileged processes do not exceed their RLIMIT_MEMLOCK limit.
+
+  Pages that are pinned multiple times are counted each time they are
+  pinned, so the value of locked_vm may be an overestimate of the
+  number of pages pinned by a process.
+
+/dev files
+
+  To create the appropriate character device files automatically with
+  udev, a rule like
+
+    KERNEL="uverbs*", NAME="infiniband/%k"
+
+  can be used.  This will create device nodes named
+
+    /dev/infiniband/uverbs0
+
+  and so on.  Since the InfiniBand userspace verbs should be safe for
+  use by non-privileged processes, it may be useful to add an
+  appropriate MODE or GROUP to the udev rule.
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index 881a37e..7a4a503 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -117,6 +117,7 @@
 Medion MD4220			??? (*)
 Samsung P35			vbetool needed (6)
 Sharp PC-AR10 (ATI rage)	none (1)
+Sony Vaio PCG-C1VRX/K		s3_bios (2)
 Sony Vaio PCG-F403		??? (*)
 Sony Vaio PCG-N505SN		??? (*)
 Sony Vaio vgn-s260		X or boot-radeon can init it (5)
diff --git a/MAINTAINERS b/MAINTAINERS
index 19a9a1c..37fb1e2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -370,6 +370,10 @@
 W:	http://atmelwlandriver.sourceforge.net/
 S:	Maintained
 
+AUDIT SUBSYSTEM
+L:	linux-audit@redhat.com (subscribers-only)
+S:	Maintained
+
 AX.25 NETWORK LAYER
 P:	Ralf Baechle
 M:	ralf@linux-mips.org
@@ -1803,8 +1807,9 @@
 S:	Maintained
 
 PCMCIA SUBSYSTEM
+P:	Linux PCMCIA Team
 L:	http://lists.infradead.org/mailman/listinfo/linux-pcmcia
-S:	Unmaintained
+S:	Maintained
 
 PCNET32 NETWORK DRIVER
 P:	Thomas Bogendörfer
@@ -2161,7 +2166,7 @@
 P:	David S. Miller
 M:	davem@davemloft.net
 P:	Eddie C. Dost
-M:	ecd@skynet.be
+M:	ecd@brainaid.de
 P:	Jakub Jelinek
 M:	jj@sunsite.ms.mff.cuni.cz
 P:	Anton Blanchard
diff --git a/Makefile b/Makefile
index 278d509..9cf07e7 100644
--- a/Makefile
+++ b/Makefile
@@ -792,6 +792,9 @@
 	$(Q)$(MAKE) $(build)=$(@D) $@
 %.o: %.c scripts FORCE
 	$(Q)$(MAKE) $(build)=$(@D) $@
+%.ko: scripts FORCE
+	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D) $(@:.ko=.o)
+	$(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
 %/:      scripts prepare FORCE
 	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D)
 %.lst: %.c scripts FORCE
@@ -1033,6 +1036,7 @@
 	@echo  '  modules_install - Install all modules'
 	@echo  '  dir/            - Build all files in dir and below'
 	@echo  '  dir/file.[ois]  - Build specified target only'
+	@echo  '  dir/file.ko     - Build module including final link'
 	@echo  '  rpm		  - Build a kernel as an RPM package'
 	@echo  '  tags/TAGS	  - Generate tags file for editors'
 	@echo  '  cscope	  - Generate cscope index'
@@ -1149,7 +1153,7 @@
 #(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
 #Adding $(srctree) adds about 20M on i386 to the size of the output file!
 
-ifeq ($(KBUILD_OUTPUT),)
+ifeq ($(src),$(obj))
 __srctree =
 else
 __srctree = $(srctree)/
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 620f2ca..8752751 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -223,7 +223,9 @@
 
 source "arch/arm/mach-sa1100/Kconfig"
 
-source "arch/arm/mach-omap/Kconfig"
+source "arch/arm/plat-omap/Kconfig"
+
+source "arch/arm/mach-omap1/Kconfig"
 
 source "arch/arm/mach-s3c2410/Kconfig"
 
@@ -514,7 +516,7 @@
 
 endmenu
 
-if (ARCH_SA1100 || ARCH_INTEGRATOR)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP1)
 
 menu "CPU Frequency scaling"
 
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index eb933dc..67f1453 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -91,7 +91,8 @@
  machine-$(CONFIG_ARCH_IOP3XX)	   := iop3xx
  machine-$(CONFIG_ARCH_IXP4XX)	   := ixp4xx
  machine-$(CONFIG_ARCH_IXP2000)    := ixp2000
- machine-$(CONFIG_ARCH_OMAP)	   := omap
+ machine-$(CONFIG_ARCH_OMAP1)	   := omap1
+  incdir-$(CONFIG_ARCH_OMAP)	   := omap
  machine-$(CONFIG_ARCH_S3C2410)	   := s3c2410
  machine-$(CONFIG_ARCH_LH7A40X)	   := lh7a40x
  machine-$(CONFIG_ARCH_VERSATILE)  := versatile
@@ -142,6 +143,9 @@
 core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
 core-$(CONFIG_VFP)		+= arch/arm/vfp/
 
+# If we have a common platform directory, then include it in the build.
+core-$(CONFIG_ARCH_OMAP)	+= arch/arm/plat-omap/
+
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
 drivers-$(CONFIG_ARCH_CLPS7500)	+= drivers/acorn/char/
 drivers-$(CONFIG_ARCH_L7200)	+= drivers/acorn/char/
diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig
index b8c51ee..f67ca01 100644
--- a/arch/arm/configs/enp2611_defconfig
+++ b/arch/arm/configs/enp2611_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-git6
-# Sat Jun 25 00:57:29 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul  7 16:41:21 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -137,6 +137,7 @@
 #
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -345,10 +346,9 @@
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
 # 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=y
 CONFIG_IP_PNP_BOOTP=y
@@ -363,17 +363,8 @@
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# TCP congestion control
-#
+# CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -931,4 +922,3 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-# CONFIG_TEXTSEARCH is not set
diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig
index 3cfbe2e..5c6c928 100644
--- a/arch/arm/configs/ixdp2400_defconfig
+++ b/arch/arm/configs/ixdp2400_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-git6
-# Sat Jun 25 00:58:38 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul  7 16:49:01 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -138,6 +138,7 @@
 #
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -346,10 +347,9 @@
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
 # 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=y
 CONFIG_IP_PNP_BOOTP=y
@@ -364,17 +364,8 @@
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# TCP congestion control
-#
+# CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -932,4 +923,3 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-# CONFIG_TEXTSEARCH is not set
diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig
index 5c87e8e..6dc40f6 100644
--- a/arch/arm/configs/ixdp2401_defconfig
+++ b/arch/arm/configs/ixdp2401_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-git6
-# Sat Jun 25 00:59:35 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul  7 16:49:08 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -138,6 +138,7 @@
 #
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -346,10 +347,9 @@
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
 # 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=y
 CONFIG_IP_PNP_BOOTP=y
@@ -364,17 +364,8 @@
 # CONFIG_INET_TUNNEL is not set
 CONFIG_IP_TCPDIAG=y
 # CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# TCP congestion control
-#
+# CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -933,4 +924,3 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-# CONFIG_TEXTSEARCH is not set
diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig
index 3cb561a..d2bb0b7 100644
--- a/arch/arm/configs/ixdp2800_defconfig
+++ b/arch/arm/configs/ixdp2800_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-git6
-# Sat Jun 25 01:00:27 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul  7 16:49:20 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -138,6 +138,7 @@
 #
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -346,10 +347,9 @@
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
 # 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=y
 CONFIG_IP_PNP_BOOTP=y
@@ -364,17 +364,8 @@
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# TCP congestion control
-#
+# CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -932,4 +923,3 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-# CONFIG_TEXTSEARCH is not set
diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig
index b1e162f..2d6f960 100644
--- a/arch/arm/configs/ixdp2801_defconfig
+++ b/arch/arm/configs/ixdp2801_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-git6
-# Sat Jun 25 01:01:18 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul  7 16:49:13 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -138,6 +138,7 @@
 #
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -346,10 +347,9 @@
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
 # 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=y
 CONFIG_IP_PNP_BOOTP=y
@@ -364,17 +364,8 @@
 # CONFIG_INET_TUNNEL is not set
 # CONFIG_IP_TCPDIAG is not set
 # CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# TCP congestion control
-#
+# CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -933,4 +924,3 @@
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-# CONFIG_TEXTSEARCH is not set
diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig
index 4e58d93..2495526 100644
--- a/arch/arm/configs/omap_h2_1610_defconfig
+++ b/arch/arm/configs/omap_h2_1610_defconfig
@@ -1,14 +1,13 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 17:52:41 2005
+# Linux kernel version: 2.6.13-rc2
+# Fri Jul  8 04:49:34 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
@@ -17,6 +16,7 @@
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -33,8 +33,9 @@
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -82,10 +83,28 @@
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_IMX is not set
 # CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
 
 #
 # TI OMAP Implementations
 #
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
 
 #
 # OMAP Core Type
@@ -93,7 +112,6 @@
 # CONFIG_ARCH_OMAP730 is not set
 # CONFIG_ARCH_OMAP1510 is not set
 CONFIG_ARCH_OMAP16XX=y
-CONFIG_ARCH_OMAP_OTG=y
 
 #
 # OMAP Board Type
@@ -101,21 +119,14 @@
 # CONFIG_MACH_OMAP_INNOVATOR is not set
 CONFIG_MACH_OMAP_H2=y
 # CONFIG_MACH_OMAP_H3 is not set
-# CONFIG_MACH_OMAP_H4 is not set
 # CONFIG_MACH_OMAP_OSK is not set
 # CONFIG_MACH_OMAP_GENERIC is not set
 
 #
-# OMAP Feature Selections
+# OMAP CPU Speed
 #
-CONFIG_OMAP_MUX=y
-# CONFIG_OMAP_MUX_DEBUG is not set
-CONFIG_OMAP_MUX_WARNINGS=y
-CONFIG_OMAP_MPU_TIMER=y
-# CONFIG_OMAP_32K_TIMER is not set
-CONFIG_OMAP_LL_DEBUG_UART1=y
-# CONFIG_OMAP_LL_DEBUG_UART2 is not set
-# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
 CONFIG_OMAP_ARM_192MHZ=y
 # CONFIG_OMAP_ARM_168MHZ is not set
 # CONFIG_OMAP_ARM_120MHZ is not set
@@ -145,6 +156,7 @@
 #
 # Bus support
 #
+CONFIG_ISA_DMA_API=y
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -154,7 +166,16 @@
 #
 # Kernel Features
 #
+# CONFIG_SMP is not set
 CONFIG_PREEMPT=y
+CONFIG_NO_IDLE_HZ=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE 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_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -167,6 +188,22 @@
 # CONFIG_XIP_KERNEL is not set
 
 #
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
 # Floating point emulation
 #
 
@@ -202,7 +239,6 @@
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
-CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -292,7 +328,6 @@
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -327,6 +362,7 @@
 # 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
@@ -356,6 +392,7 @@
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -375,12 +412,12 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
@@ -395,6 +432,8 @@
 # CONFIG_INET_TUNNEL is not set
 CONFIG_IP_TCPDIAG=y
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -442,6 +481,7 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -518,7 +558,6 @@
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_RAW is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -567,13 +606,11 @@
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
 # TPM devices
 #
-# CONFIG_TCG_TPM is not set
 
 #
 # I2C support
@@ -604,7 +641,9 @@
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_FSCPOS is not set
@@ -620,6 +659,7 @@
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -627,15 +667,21 @@
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_RTC8564 is not set
 CONFIG_ISP1301_OMAP=y
+CONFIG_TPS65010=y
+# 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
@@ -663,8 +709,10 @@
 # CONFIG_FB_CFB_COPYAREA is not set
 # CONFIG_FB_CFB_IMAGEBLIT is not set
 # CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -677,11 +725,13 @@
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
 # CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
 # CONFIG_FONT_PEARL_8x8 is not set
 # CONFIG_FONT_ACORN_8x8 is not set
 # CONFIG_FONT_MINI_4x6 is not set
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
 
 #
 # Logo configuration
@@ -729,14 +779,14 @@
 #
 CONFIG_USB_GADGET=y
 # CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=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_SA1100 is not set
 # CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_OMAP=y
 CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
 # CONFIG_USB_GADGET_DUALSPEED is not set
 # CONFIG_USB_ZERO is not set
 CONFIG_USB_ETH=y
@@ -755,6 +805,7 @@
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
@@ -791,7 +842,6 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
@@ -828,12 +878,14 @@
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 CONFIG_NFS_V4=y
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
 CONFIG_RPCSEC_GSS_KRB5=y
@@ -903,24 +955,11 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_PREEMPT=y
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_WAITQ is not set
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_USER is not set
 
 #
 # Security options
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index b713c44..835d450 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -41,7 +41,10 @@
  * This has a special calling convention; it doesn't
  * modify any of the usual registers, except for LR.
  */
+#define EXPORT_CRC_ALIAS(sym) __CRC_SYMBOL(sym, "")
+
 #define EXPORT_SYMBOL_ALIAS(sym,orig)		\
+ EXPORT_CRC_ALIAS(sym)				\
  const struct kernel_symbol __ksymtab_##sym	\
   __attribute__((section("__ksymtab"))) =	\
     { (unsigned long)&orig, #sym };
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 4b9d841..45b1865 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -23,7 +23,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/bitops.h>
-#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/mm.h>
 
 #include <asm/types.h>
@@ -125,19 +125,6 @@
 	}
 };
 
-static struct uart_port ixp2000_serial_port = {
-	.membase	= (char *)(IXP2000_UART_VIRT_BASE + 3),
-	.mapbase	= IXP2000_UART_PHYS_BASE + 3,
-	.irq		= IRQ_IXP2000_UART,
-	.flags		= UPF_SKIP_TEST,
-	.iotype		= UPIO_MEM,
-	.regshift	= 2,
-	.uartclk	= 50000000,
-	.line		= 0,
-	.type		= PORT_XSCALE,
-	.fifosize	= 16
-};
-
 void __init ixp2000_map_io(void)
 {
 	extern unsigned int processor_id;
@@ -157,12 +144,50 @@
 	}
 
 	iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
-	early_serial_setup(&ixp2000_serial_port);
 
 	/* Set slowport to 8-bit mode.  */
 	ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1);
 }
 
+
+/*************************************************************************
+ * Serial port support for IXP2000
+ *************************************************************************/
+static struct plat_serial8250_port ixp2000_serial_port[] = {
+	{
+		.mapbase	= IXP2000_UART_PHYS_BASE,
+		.membase	= (char *)(IXP2000_UART_VIRT_BASE + 3),
+		.irq		= IRQ_IXP2000_UART,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= 50000000,
+	},
+	{ },
+};
+
+static struct resource ixp2000_uart_resource = {
+	.start		= IXP2000_UART_PHYS_BASE,
+	.end		= IXP2000_UART_PHYS_BASE + 0xffff,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device ixp2000_serial_device = {
+	.name		= "serial8250",
+	.id		= 0,
+	.dev		= {
+		.platform_data		= ixp2000_serial_port,
+	},
+	.num_resources	= 1,
+	.resource	= &ixp2000_uart_resource,
+};
+
+void __init ixp2000_uart_init(void)
+{
+	platform_device_register(&ixp2000_serial_device);
+}
+
+
 /*************************************************************************
  * Timer-tick functions for IXP2000
  *************************************************************************/
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index b7ebf38..9aa54de 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -219,6 +219,7 @@
 static void __init enp2611_init_machine(void)
 {
 	platform_add_devices(enp2611_devices, ARRAY_SIZE(enp2611_devices));
+	ixp2000_uart_init();
 }
 
 
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 5e43807..a43369a 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -303,5 +303,6 @@
 	gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT);
 
 	platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices));
+	ixp2000_uart_init();
 }
 
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index c735887..43447da 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -370,6 +370,7 @@
 		((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1);
 
 	platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
+	ixp2000_uart_init();
 }
 
 
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index aa92e37..2b54436 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -453,8 +453,8 @@
 	local_write_config(PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
 
 	res[0].name = "PCI I/O Space";
-	res[0].start = 0x00001000;
-	res[0].end = 0xffff0000;
+	res[0].start = 0x00000000;
+	res[0].end = 0x0000ffff;
 	res[0].flags = IORESOURCE_IO;
 
 	res[1].name = "PCI Memory Space";
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index c6335f5..4ff4393 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -56,21 +56,24 @@
 	.flags	= IORESOURCE_MEM,
 };
 
-static struct plat_serial8250_port coyote_uart_data = {
-	.mapbase	= IXP4XX_UART2_BASE_PHYS,
-	.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
-	.irq		= IRQ_IXP4XX_UART2,
-	.flags		= UPF_BOOT_AUTOCONF,
-	.iotype		= UPIO_MEM,
-	.regshift	= 2,
-	.uartclk	= IXP4XX_UART_XTAL,
+static struct plat_serial8250_port coyote_uart_data[] = {
+	{
+		.mapbase	= IXP4XX_UART2_BASE_PHYS,
+		.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART2,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{ },
 };
 
 static struct platform_device coyote_uart = {
 	.name		= "serial8250",
 	.id		= 0,
 	.dev			= {
-		.platform_data	= &coyote_uart_data,
+		.platform_data	= coyote_uart_data,
 	},
 	.num_resources	= 1,
 	.resource	= &coyote_uart_resource,
@@ -87,10 +90,10 @@
 	*IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
 
 	if (machine_is_ixdpg425()) {
-		coyote_uart_data.membase =
+		coyote_uart_data[0].membase =
 			(char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET);
-		coyote_uart_data.mapbase = IXP4XX_UART1_BASE_PHYS;
-		coyote_uart_data.irq = IRQ_IXP4XX_UART1;
+		coyote_uart_data[0].mapbase = IXP4XX_UART1_BASE_PHYS;
+		coyote_uart_data[0].irq = IRQ_IXP4XX_UART1;
 	}
 
 
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index f2e9c0e..c2ba759 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -95,7 +95,8 @@
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= IXP4XX_UART_XTAL,
-	}
+	},
+	{ },
 };
 
 static struct platform_device ixdp425_uart = {
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
deleted file mode 100644
index 9e42efa..0000000
--- a/arch/arm/mach-omap/Kconfig
+++ /dev/null
@@ -1,221 +0,0 @@
-if ARCH_OMAP
-
-menu "TI OMAP Implementations"
-
-comment "OMAP Core Type"
-
-config ARCH_OMAP730
-	depends on ARCH_OMAP
-	bool "OMAP730 Based System"
-	select ARCH_OMAP_OTG
-
-config ARCH_OMAP1510
-	depends on ARCH_OMAP
-	default y
-	bool "OMAP1510 Based System"
-
-config ARCH_OMAP16XX
-	depends on ARCH_OMAP
-	bool "OMAP16XX Based System"
-	select ARCH_OMAP_OTG
-
-config ARCH_OMAP_OTG
-	bool
-
-comment "OMAP Board Type"
-
-config MACH_OMAP_INNOVATOR
-	bool "TI Innovator"
-	depends on ARCH_OMAP1510 || ARCH_OMAP16XX
-	help
-          TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
-          have such a board.
-
-config MACH_OMAP_H2
-	bool "TI H2 Support"
-	depends on ARCH_OMAP16XX
-    	help
-	  TI OMAP 1610/1611B H2 board support. Say Y here if you have such
-	  a board.
-
-config MACH_OMAP_H3
-	bool "TI H3 Support"
-	depends on ARCH_OMAP16XX
-    	help
-	  TI OMAP 1710 H3 board support. Say Y here if you have such
-	  a board.
-
-config MACH_OMAP_H4
-	bool "TI H4 Support"
-	depends on ARCH_OMAP16XX
-    	help
-	  TI OMAP 1610 H4 board support. Say Y here if you have such
-	  a board.
-
-config MACH_OMAP_OSK
-	bool "TI OSK Support"
-	depends on ARCH_OMAP16XX
-    	help
-	  TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
-          if you have such a board.
-
-config MACH_OMAP_PERSEUS2
-	bool "TI Perseus2"
-	depends on ARCH_OMAP730
-    	help
-	  Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
-	  a board.
-
-config MACH_VOICEBLUE
-	bool "Voiceblue"
-	depends on ARCH_OMAP1510
-	help
-	  Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such
-	  board.
-
-config MACH_NETSTAR
-	bool "NetStar"
-	depends on ARCH_OMAP1510
-	help
-	  Support for NetStar PBX. Say Y here if you have such a board.
-
-config MACH_OMAP_GENERIC
-	bool "Generic OMAP board"
-	depends on ARCH_OMAP1510 || ARCH_OMAP16XX
-	help
-          Support for generic OMAP-1510, 1610 or 1710 board with
-          no FPGA. Can be used as template for porting Linux to
-          custom OMAP boards. Say Y here if you have a custom
-          board.
-
-comment "OMAP Feature Selections"
-
-#config OMAP_BOOT_TAG
-#	bool "OMAP bootloader information passing"
-#        depends on ARCH_OMAP
-#        default n
-#        help
-#          Say Y, if you have a bootloader which passes information
-#          about your board and its peripheral configuration.
-
-config OMAP_MUX
-	bool "OMAP multiplexing support"
-        depends on ARCH_OMAP
-	default y
-        help
-          Pin multiplexing support for OMAP boards. If your bootloader
-          sets the multiplexing correctly, say N. Otherwise, or if unsure,
-          say Y.
-
-config OMAP_MUX_DEBUG
-	bool "Multiplexing debug output"
-        depends on OMAP_MUX
-        default n
-        help
-          Makes the multiplexing functions print out a lot of debug info.
-          This is useful if you want to find out the correct values of the
-          multiplexing registers.
-
-config OMAP_MUX_WARNINGS
-	bool "Warn about pins the bootloader didn't set up"
-        depends on OMAP_MUX
-        default y
-        help
-	  Choose Y here to warn whenever driver initialization logic needs
-	  to change the pin multiplexing setup.  When there are no warnings
-	  printed, it's safe to deselect OMAP_MUX for your product.
-
-choice
-        prompt "System timer"
-	default OMAP_MPU_TIMER
-
-config OMAP_MPU_TIMER
-	bool "Use mpu timer"
-	help
-	  Select this option if you want to use the OMAP mpu timer. This
-	  timer provides more intra-tick resolution than the 32KHz timer,
-	  but consumes more power.
-
-config OMAP_32K_TIMER
-	bool "Use 32KHz timer"
-	depends on ARCH_OMAP16XX
-	help
-	  Select this option if you want to enable the OMAP 32KHz timer.
-	  This timer saves power compared to the OMAP_MPU_TIMER, and has
-	  support for no tick during idle. The 32KHz timer provides less
-	  intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
-	  currently only available for OMAP-16xx.
-
-endchoice
-
-config OMAP_32K_TIMER_HZ
-       int "Kernel internal timer frequency for 32KHz timer"
-       range 32 1024
-       depends on OMAP_32K_TIMER
-       default "128"
-       help
-	  Kernel internal timer frequency should be a divisor of 32768,
-	  such as 64 or 128.
-
-choice
-	prompt "Low-level debug console UART"
-	depends on ARCH_OMAP
-	default OMAP_LL_DEBUG_UART1
-
-config OMAP_LL_DEBUG_UART1
-	bool "UART1"
-
-config OMAP_LL_DEBUG_UART2
-	bool "UART2"
-
-config OMAP_LL_DEBUG_UART3
-	bool "UART3"
-
-endchoice
-
-config OMAP_ARM_195MHZ
-	bool "OMAP ARM 195 MHz CPU"
-	depends on ARCH_OMAP730
-	help
-          Enable 195MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_192MHZ
-	bool "OMAP ARM 192 MHz CPU"
-	depends on ARCH_OMAP16XX
-	help
-          Enable 192MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_182MHZ
-	bool "OMAP ARM 182 MHz CPU"
-	depends on ARCH_OMAP730
-	help
-          Enable 182MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_168MHZ
-	bool "OMAP ARM 168 MHz CPU"
-	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
-	help
-          Enable 168MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_120MHZ
-	bool "OMAP ARM 120 MHz CPU"
-	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
-	help
-          Enable 120MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_60MHZ
-	bool "OMAP ARM 60 MHz CPU"
-	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
-        default y
-	help
-          Enable 60MHz clock for OMAP CPU. If unsure, say Y.
-
-config OMAP_ARM_30MHZ
-	bool "OMAP ARM 30 MHz CPU"
-	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
-	help
-          Enable 30MHz clock for OMAP CPU. If unsure, say N.
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
deleted file mode 100644
index 4cafb11..0000000
--- a/arch/arm/mach-omap/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Common support
-obj-y := common.o time.o irq.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
-obj-m :=
-obj-n :=
-obj-  :=
-led-y := leds.o
-
-# Specific board support
-obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o
-obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o
-obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
-obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o
-obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
-obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
-obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
-obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
-
-# OCPI interconnect support for 1710, 1610 and 5912
-obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
-
-# LEDs support
-led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o
-led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o
-obj-$(CONFIG_LEDS) += $(led-y)
-
-# Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
-
-ifeq ($(CONFIG_ARCH_OMAP1510),y)
-# Innovator-1510 FPGA
-obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o
-endif
-
-# kgdb support
-obj-$(CONFIG_KGDB_SERIAL)	+= kgdb-serial.o
diff --git a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c
deleted file mode 100644
index 265cde4..0000000
--- a/arch/arm/mach-omap/common.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * linux/arch/arm/mach-omap/common.c
- *
- * Code common to all OMAP machines.
- *
- * 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/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-
-#include <asm/hardware.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-#include <asm/hardware/clock.h>
-#include <asm/io.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/board.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/fpga.h>
-
-#include "clock.h"
-
-#define DEBUG 1
-
-struct omap_id {
-	u16	jtag_id;	/* Used to determine OMAP type */
-	u8	die_rev;	/* Processor revision */
-	u32	omap_id;	/* OMAP revision */
-	u32	type;		/* Cpu id bits [31:08], cpu class bits [07:00] */
-};
-
-/* Register values to detect the OMAP version */
-static struct omap_id omap_ids[] __initdata = {
-	{ .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
-	{ .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
-	{ .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
-	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
-	{ .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
-	{ .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
-	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
-	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
-	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
-	{ .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
-	{ .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
-	{ .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
-	{ .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
-	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
-	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
-	{ .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
-	{ .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
-	{ .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
-};
-
-/*
- * Get OMAP type from PROD_ID.
- * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
- * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
- * Undocumented register in TEST BLOCK is used as fallback; This seems to
- * work on 1510, 1610 & 1710. The official way hopefully will work in future
- * processors.
- */
-static u16 __init omap_get_jtag_id(void)
-{
-	u32 prod_id, omap_id;
-
-	prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
-	omap_id = omap_readl(OMAP32_ID_1);
-
-	/* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */
-	if (((prod_id >> 20) == 0) || (prod_id == omap_id))
-		prod_id = 0;
-	else
-		prod_id &= 0xffff;
-
-	if (prod_id)
-		return prod_id;
-
-	/* Use OMAP32_ID_1 as fallback */
-	prod_id = ((omap_id >> 12) & 0xffff);
-
-	return prod_id;
-}
-
-/*
- * Get OMAP revision from DIE_REV.
- * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
- * Undocumented register in the TEST BLOCK is used as fallback.
- * REVISIT: This does not seem to work on 1510
- */
-static u8 __init omap_get_die_rev(void)
-{
-	u32 die_rev;
-
-	die_rev = omap_readl(OMAP_DIE_ID_1);
-
-	/* Check for broken OMAP_DIE_ID on early 1710 */
-	if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
-		die_rev = 0;
-
-	die_rev = (die_rev >> 17) & 0xf;
-	if (die_rev)
-		return die_rev;
-
-	die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
-
-	return die_rev;
-}
-
-static void __init omap_check_revision(void)
-{
-	int i;
-	u16 jtag_id;
-	u8 die_rev;
-	u32 omap_id;
-	u8 cpu_type;
-
-	jtag_id = omap_get_jtag_id();
-	die_rev = omap_get_die_rev();
-	omap_id = omap_readl(OMAP32_ID_0);
-
-#ifdef DEBUG
-	printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
-	printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
-		omap_readl(OMAP_DIE_ID_1),
-	       (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
-	printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
-	printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
-		omap_readl(OMAP_PRODUCTION_ID_1),
-		omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
-	printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
-	printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
-	printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
-#endif
-
-	system_serial_high = omap_readl(OMAP_DIE_ID_0);
-	system_serial_low = omap_readl(OMAP_DIE_ID_1);
-
-	/* First check only the major version in a safe way */
-	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
-		if (jtag_id == (omap_ids[i].jtag_id)) {
-			system_rev = omap_ids[i].type;
-			break;
-		}
-	}
-
-	/* Check if we can find the die revision */
-	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
-		if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
-			system_rev = omap_ids[i].type;
-			break;
-		}
-	}
-
-	/* Finally check also the omap_id */
-	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
-		if (jtag_id == omap_ids[i].jtag_id
-		    && die_rev == omap_ids[i].die_rev
-		    && omap_id == omap_ids[i].omap_id) {
-			system_rev = omap_ids[i].type;
-			break;
-		}
-	}
-
-	/* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
-	cpu_type = system_rev >> 24;
-
-	switch (cpu_type) {
-	case 0x07:
-		system_rev |= 0x07;
-		break;
-	case 0x15:
-		system_rev |= 0x15;
-		break;
-	case 0x16:
-	case 0x17:
-		system_rev |= 0x16;
-		break;
-	case 0x24:
-		system_rev |= 0x24;
-		break;
-	default:
-		printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
-	}
-
-	printk("OMAP%04x", system_rev >> 16);
-	if ((system_rev >> 8) & 0xff)
-		printk("%x", (system_rev >> 8) & 0xff);
-	printk(" revision %i handled as %02xxx id: %08x%08x\n",
-	       die_rev, system_rev & 0xff, system_serial_low,
-	       system_serial_high);
-}
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP I/O mapping
- *
- * The machine specific code may provide the extra mapping besides the
- * default mapping provided here.
- * ----------------------------------------------------------------------------
- */
-
-static struct map_desc omap_io_desc[] __initdata = {
- { IO_VIRT,      	IO_PHYS,             IO_SIZE,        	   MT_DEVICE },
-};
-
-#ifdef CONFIG_ARCH_OMAP730
-static struct map_desc omap730_io_desc[] __initdata = {
- { OMAP730_DSP_BASE,    OMAP730_DSP_START,    OMAP730_DSP_SIZE,    MT_DEVICE },
- { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE },
- { OMAP730_SRAM_BASE,   OMAP730_SRAM_START,   OMAP730_SRAM_SIZE,   MT_DEVICE }
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP1510
-static struct map_desc omap1510_io_desc[] __initdata = {
- { OMAP1510_DSP_BASE,    OMAP1510_DSP_START,    OMAP1510_DSP_SIZE,    MT_DEVICE },
- { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE },
- { OMAP1510_SRAM_BASE,   OMAP1510_SRAM_START,   OMAP1510_SRAM_SIZE,   MT_DEVICE }
-};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP16XX)
-static struct map_desc omap1610_io_desc[] __initdata = {
- { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
- { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
- { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP1610_SRAM_SIZE,   MT_DEVICE }
-};
-
-static struct map_desc omap5912_io_desc[] __initdata = {
- { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
- { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
-/*
- * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page
- * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped.
- * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte
- * can be used.
- */
- { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP5912_SRAM_SIZE + 0x800,   MT_DEVICE }
-};
-#endif
-
-static int initialized = 0;
-
-static void __init _omap_map_io(void)
-{
-	initialized = 1;
-
-	/* We have to initialize the IO space mapping before we can run
-	 * cpu_is_omapxxx() macros. */
-	iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
-	omap_check_revision();
-
-#ifdef CONFIG_ARCH_OMAP730
-	if (cpu_is_omap730()) {
-		iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
-	}
-#endif
-#ifdef CONFIG_ARCH_OMAP1510
-	if (cpu_is_omap1510()) {
-		iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
-	}
-#endif
-#if defined(CONFIG_ARCH_OMAP16XX)
-	if (cpu_is_omap1610() || cpu_is_omap1710()) {
-		iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
-	}
-	if (cpu_is_omap5912()) {
-		iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc));
-	}
-#endif
-
-	/* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
-	 * on a Posted Write in the TIPB Bridge".
-	 */
-	omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL);
-	omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL);
-
-	/* Must init clocks early to assure that timer interrupt works
-	 */
-	clk_init();
-}
-
-/*
- * This should only get called from board specific init
- */
-void omap_map_io(void)
-{
-	if (!initialized)
-		_omap_map_io();
-}
-
-static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
-					  int offset)
-{
-	offset <<= up->regshift;
-	return (unsigned int)__raw_readb(up->membase + offset);
-}
-
-static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
-				    int value)
-{
-	offset <<= p->regshift;
-	__raw_writeb(value, p->membase + offset);
-}
-
-/*
- * Internal UARTs need to be initialized for the 8250 autoconfig to work
- * properly. Note that the TX watermark initialization may not be needed
- * once the 8250.c watermark handling code is merged.
- */
-static void __init omap_serial_reset(struct plat_serial8250_port *p)
-{
-	omap_serial_outp(p, UART_OMAP_MDR1, 0x07);	/* disable UART */
-	omap_serial_outp(p, UART_OMAP_SCR, 0x08);	/* TX watermark */
-	omap_serial_outp(p, UART_OMAP_MDR1, 0x00);	/* enable UART */
-
-	if (!cpu_is_omap1510()) {
-		omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
-		while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
-	}
-}
-
-static struct plat_serial8250_port serial_platform_data[] = {
-	{
-		.membase	= (char*)IO_ADDRESS(OMAP_UART1_BASE),
-		.mapbase	= (unsigned long)OMAP_UART1_BASE,
-		.irq		= INT_UART1,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP16XX_BASE_BAUD * 16,
-	},
-	{
-		.membase	= (char*)IO_ADDRESS(OMAP_UART2_BASE),
-		.mapbase	= (unsigned long)OMAP_UART2_BASE,
-		.irq		= INT_UART2,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP16XX_BASE_BAUD * 16,
-	},
-	{
-		.membase	= (char*)IO_ADDRESS(OMAP_UART3_BASE),
-		.mapbase	= (unsigned long)OMAP_UART3_BASE,
-		.irq		= INT_UART3,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP16XX_BASE_BAUD * 16,
-	},
-	{ },
-};
-
-static struct platform_device serial_device = {
-	.name			= "serial8250",
-	.id			= 0,
-	.dev			= {
-		.platform_data	= serial_platform_data,
-	},
-};
-
-/*
- * Note that on Innovator-1510 UART2 pins conflict with USB2.
- * By default UART2 does not work on Innovator-1510 if you have
- * USB OHCI enabled. To use UART2, you must disable USB2 first.
- */
-void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
-{
-	int i;
-
-	if (cpu_is_omap730()) {
-		serial_platform_data[0].regshift = 0;
-		serial_platform_data[1].regshift = 0;
-		serial_platform_data[0].irq = INT_730_UART_MODEM_1;
-		serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
-	}
-
-	if (cpu_is_omap1510()) {
-		serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
-		serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
-		serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
-	}
-
-	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
-		unsigned char reg;
-
-		if (ports[i] == 0) {
-			serial_platform_data[i].membase = 0;
-			serial_platform_data[i].mapbase = 0;
-			continue;
-		}
-
-		switch (i) {
-		case 0:
-			if (cpu_is_omap1510()) {
-				omap_cfg_reg(UART1_TX);
-				omap_cfg_reg(UART1_RTS);
-				if (machine_is_omap_innovator()) {
-					reg = fpga_read(OMAP1510_FPGA_POWER);
-					reg |= OMAP1510_FPGA_PCR_COM1_EN;
-					fpga_write(reg, OMAP1510_FPGA_POWER);
-					udelay(10);
-				}
-			}
-			break;
-		case 1:
-			if (cpu_is_omap1510()) {
-				omap_cfg_reg(UART2_TX);
-				omap_cfg_reg(UART2_RTS);
-				if (machine_is_omap_innovator()) {
-					reg = fpga_read(OMAP1510_FPGA_POWER);
-					reg |= OMAP1510_FPGA_PCR_COM2_EN;
-					fpga_write(reg, OMAP1510_FPGA_POWER);
-					udelay(10);
-				}
-			}
-			break;
-		case 2:
-			if (cpu_is_omap1510()) {
-				omap_cfg_reg(UART3_TX);
-				omap_cfg_reg(UART3_RX);
-			}
-			if (cpu_is_omap1710()) {
-				clk_enable(clk_get(0, "uart3_ck"));
-			}
-			break;
-		}
-		omap_serial_reset(&serial_platform_data[i]);
-	}
-}
-
-static int __init omap_init(void)
-{
-	return platform_device_register(&serial_device);
-}
-arch_initcall(omap_init);
-
-#define NO_LENGTH_CHECK 0xffffffff
-
-extern int omap_bootloader_tag_len;
-extern u8 omap_bootloader_tag[];
-
-struct omap_board_config_kernel *omap_board_config;
-int omap_board_config_size = 0;
-
-static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
-{
-	struct omap_board_config_kernel *kinfo = NULL;
-	int i;
-
-#ifdef CONFIG_OMAP_BOOT_TAG
-	struct omap_board_config_entry *info = NULL;
-
-	if (omap_bootloader_tag_len > 4)
-		info = (struct omap_board_config_entry *) omap_bootloader_tag;
-	while (info != NULL) {
-		u8 *next;
-
-		if (info->tag == tag) {
-			if (skip == 0)
-				break;
-			skip--;
-		}
-
-		if ((info->len & 0x03) != 0) {
-			/* We bail out to avoid an alignment fault */
-			printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
-			       info->len, info->tag);
-			return NULL;
-		}
-		next = (u8 *) info + sizeof(*info) + info->len;
-		if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
-			info = NULL;
-		else
-			info = (struct omap_board_config_entry *) next;
-	}
-	if (info != NULL) {
-		/* Check the length as a lame attempt to check for
-		 * binary inconsistancy. */
-		if (len != NO_LENGTH_CHECK) {
-			/* Word-align len */
-			if (len & 0x03)
-				len = (len + 3) & ~0x03;
-			if (info->len != len) {
-				printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
-				       tag, len, info->len);
-				return NULL;
-			}
-		}
-		if (len_out != NULL)
-			*len_out = info->len;
-		return info->data;
-	}
-#endif
-	/* Try to find the config from the board-specific structures
-	 * in the kernel. */
-	for (i = 0; i < omap_board_config_size; i++) {
-		if (omap_board_config[i].tag == tag) {
-			kinfo = &omap_board_config[i];
-			break;
-		}
-	}
-	if (kinfo == NULL)
-		return NULL;
-	return kinfo->data;
-}
-
-const void *__omap_get_config(u16 tag, size_t len, int nr)
-{
-        return get_config(tag, len, nr, NULL);
-}
-EXPORT_SYMBOL(__omap_get_config);
-
-const void *omap_get_var_config(u16 tag, size_t *len)
-{
-        return get_config(tag, NO_LENGTH_CHECK, 0, len);
-}
-EXPORT_SYMBOL(omap_get_var_config);
-
-static int __init omap_add_serial_console(void)
-{
-	const struct omap_uart_config *info;
-
-	info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
-	if (info != NULL && info->console_uart) {
-		static char speed[11], *opt = NULL;
-
-		if (info->console_speed) {
-			snprintf(speed, sizeof(speed), "%u", info->console_speed);
-			opt = speed;
-		}
-		return add_preferred_console("ttyS", info->console_uart - 1, opt);
-	}
-	return 0;
-}
-console_initcall(omap_add_serial_console);
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
new file mode 100644
index 0000000..7408ac9
--- /dev/null
+++ b/arch/arm/mach-omap1/Kconfig
@@ -0,0 +1,144 @@
+comment "OMAP Core Type"
+	depends on ARCH_OMAP1
+
+config ARCH_OMAP730
+	depends on ARCH_OMAP1
+	bool "OMAP730 Based System"
+	select ARCH_OMAP_OTG
+
+config ARCH_OMAP1510
+	depends on ARCH_OMAP1
+	default y
+	bool "OMAP1510 Based System"
+
+config ARCH_OMAP16XX
+	depends on ARCH_OMAP1
+	bool "OMAP16xx Based System"
+	select ARCH_OMAP_OTG
+
+comment "OMAP Board Type"
+	depends on ARCH_OMAP1
+
+config MACH_OMAP_INNOVATOR
+	bool "TI Innovator"
+	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX)
+	help
+          TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
+          have such a board.
+
+config MACH_OMAP_H2
+	bool "TI H2 Support"
+	depends on ARCH_OMAP1 && ARCH_OMAP16XX
+    	help
+	  TI OMAP 1610/1611B H2 board support. Say Y here if you have such
+	  a board.
+
+config MACH_OMAP_H3
+	bool "TI H3 Support"
+	depends on ARCH_OMAP1 && ARCH_OMAP16XX
+    	help
+	  TI OMAP 1710 H3 board support. Say Y here if you have such
+	  a board.
+
+config MACH_OMAP_OSK
+	bool "TI OSK Support"
+	depends on ARCH_OMAP1 && ARCH_OMAP16XX
+    	help
+	  TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
+          if you have such a board.
+
+config MACH_OMAP_PERSEUS2
+	bool "TI Perseus2"
+	depends on ARCH_OMAP1 && ARCH_OMAP730
+    	help
+	  Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
+	  a board.
+
+config MACH_VOICEBLUE
+	bool "Voiceblue"
+	depends on ARCH_OMAP1 && ARCH_OMAP1510
+	help
+	  Support for Voiceblue GSM/VoIP gateway. Say Y here if you have
+	  such a board.
+
+config MACH_NETSTAR
+	bool "NetStar"
+	depends on ARCH_OMAP1 && ARCH_OMAP1510
+	help
+	  Support for NetStar PBX. Say Y here if you have such a board.
+
+config MACH_OMAP_GENERIC
+	bool "Generic OMAP board"
+	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX)
+	help
+          Support for generic OMAP-1510, 1610 or 1710 board with
+          no FPGA. Can be used as template for porting Linux to
+          custom OMAP boards. Say Y here if you have a custom
+          board.
+
+comment "OMAP CPU Speed"
+	depends on ARCH_OMAP1
+
+config OMAP_CLOCKS_SET_BY_BOOTLOADER
+	bool "OMAP clocks set by bootloader"
+	depends on ARCH_OMAP1
+	help
+	  Enable this option to prevent the kernel from overriding the clock
+	  frequencies programmed by bootloader for MPU, DSP, MMUs, TC,
+	  internal LCD controller and MPU peripherals.
+
+config OMAP_ARM_216MHZ
+	bool "OMAP ARM 216 MHz CPU (1710 only)"
+        depends on ARCH_OMAP1 && ARCH_OMAP16XX
+        help
+          Enable 216 MHz clock for OMAP1710 CPU. If unsure, say N.
+
+config OMAP_ARM_195MHZ
+	bool "OMAP ARM 195 MHz CPU"
+	depends on ARCH_OMAP1 && ARCH_OMAP730
+	help
+          Enable 195MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_192MHZ
+	bool "OMAP ARM 192 MHz CPU"
+	depends on ARCH_OMAP1 && ARCH_OMAP16XX
+	help
+          Enable 192MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_182MHZ
+	bool "OMAP ARM 182 MHz CPU"
+	depends on ARCH_OMAP1 && ARCH_OMAP730
+	help
+          Enable 182MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_168MHZ
+	bool "OMAP ARM 168 MHz CPU"
+	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+	help
+          Enable 168MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_150MHZ
+	bool "OMAP ARM 150 MHz CPU"
+	depends on ARCH_OMAP1 && ARCH_OMAP1510
+	help
+	  Enable 150MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_120MHZ
+	bool "OMAP ARM 120 MHz CPU"
+	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+	help
+          Enable 120MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_60MHZ
+	bool "OMAP ARM 60 MHz CPU"
+	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+        default y
+	help
+          Enable 60MHz clock for OMAP CPU. If unsure, say Y.
+
+config OMAP_ARM_30MHZ
+	bool "OMAP ARM 30 MHz CPU"
+	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+	help
+          Enable 30MHz clock for OMAP CPU. If unsure, say N.
+
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
new file mode 100644
index 0000000..d386fd9
--- /dev/null
+++ b/arch/arm/mach-omap1/Makefile
@@ -0,0 +1,30 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := io.o id.o irq.o time.o serial.o
+led-y := leds.o
+
+# Specific board support
+obj-$(CONFIG_MACH_OMAP_H2)		+= board-h2.o
+obj-$(CONFIG_MACH_OMAP_INNOVATOR)	+= board-innovator.o
+obj-$(CONFIG_MACH_OMAP_GENERIC)		+= board-generic.o
+obj-$(CONFIG_MACH_OMAP_PERSEUS2)	+= board-perseus2.o
+obj-$(CONFIG_MACH_OMAP_OSK)		+= board-osk.o
+obj-$(CONFIG_MACH_OMAP_H3)		+= board-h3.o
+obj-$(CONFIG_MACH_VOICEBLUE)		+= board-voiceblue.o
+obj-$(CONFIG_MACH_NETSTAR)		+= board-netstar.o
+
+ifeq ($(CONFIG_ARCH_OMAP1510),y)
+# Innovator-1510 FPGA
+obj-$(CONFIG_MACH_OMAP_INNOVATOR)	+= fpga.o
+endif
+
+# LEDs support
+led-$(CONFIG_MACH_OMAP_H2)		+= leds-h2p2-debug.o
+led-$(CONFIG_MACH_OMAP_INNOVATOR)	+= leds-innovator.o
+led-$(CONFIG_MACH_OMAP_PERSEUS2)	+= leds-h2p2-debug.o
+led-$(CONFIG_MACH_OMAP_OSK)		+= leds-osk.o
+obj-$(CONFIG_LEDS)			+= $(led-y)
+
diff --git a/arch/arm/mach-omap/Makefile.boot b/arch/arm/mach-omap1/Makefile.boot
similarity index 98%
rename from arch/arm/mach-omap/Makefile.boot
rename to arch/arm/mach-omap1/Makefile.boot
index fee1a6a..292d56c 100644
--- a/arch/arm/mach-omap/Makefile.boot
+++ b/arch/arm/mach-omap1/Makefile.boot
@@ -1,4 +1,3 @@
    zreladdr-y		:= 0x10008000
 params_phys-y		:= 0x10000100
 initrd_phys-y		:= 0x10800000
-
diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap1/board-generic.c
similarity index 95%
rename from arch/arm/mach-omap/board-generic.c
rename to arch/arm/mach-omap1/board-generic.c
index 384bc7c..122796e 100644
--- a/arch/arm/mach-omap/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/board-generic.c
+ * linux/arch/arm/mach-omap1/board-generic.c
  *
  * Modified from board-innovator1510.c
  *
@@ -26,8 +26,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/board.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 static int __initdata generic_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
 
@@ -84,7 +83,7 @@
 
 static void __init omap_generic_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io()
 }
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
diff --git a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap1/board-h2.c
similarity index 97%
rename from arch/arm/mach-omap/board-h2.c
rename to arch/arm/mach-omap1/board-h2.c
index f37c76a..f4983ee 100644
--- a/arch/arm/mach-omap/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/board-h2.c
+ * linux/arch/arm/mach-omap1/board-h2.c
  *
  * Board specific inits for OMAP-1610 H2
  *
@@ -35,8 +35,7 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 extern int omap_gpio_init(void);
 
@@ -172,7 +171,7 @@
 
 static void __init h2_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io();
 	omap_serial_init(h2_serial_ports);
 }
 
diff --git a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap1/board-h3.c
similarity index 97%
rename from arch/arm/mach-omap/board-h3.c
rename to arch/arm/mach-omap1/board-h3.c
index 705e485..7cd419d 100644
--- a/arch/arm/mach-omap/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/board-h3.c
+ * linux/arch/arm/mach-omap1/board-h3.c
  *
  * This file contains OMAP1710 H3 specific code.
  *
@@ -37,8 +37,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 extern int omap_gpio_init(void);
 
@@ -190,7 +189,7 @@
 
 static void __init h3_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io();
 	omap_serial_init(h3_serial_ports);
 }
 
diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
similarity index 98%
rename from arch/arm/mach-omap/board-innovator.c
rename to arch/arm/mach-omap1/board-innovator.c
index 523363f..91de60a 100644
--- a/arch/arm/mach-omap/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/board-innovator.c
+ * linux/arch/arm/mach-omap1/board-innovator.c
  *
  * Board specific inits for OMAP-1510 and OMAP-1610 Innovator
  *
@@ -33,8 +33,7 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 static int __initdata innovator_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
 
@@ -252,7 +251,7 @@
 
 static void __init innovator_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io();
 
 #ifdef CONFIG_ARCH_OMAP1510
 	if (cpu_is_omap1510()) {
diff --git a/arch/arm/mach-omap/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
similarity index 98%
rename from arch/arm/mach-omap/board-netstar.c
rename to arch/arm/mach-omap1/board-netstar.c
index 8c65373..6750b20 100644
--- a/arch/arm/mach-omap/board-netstar.c
+++ b/arch/arm/mach-omap1/board-netstar.c
@@ -26,8 +26,7 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 extern void __init omap_init_time(void);
 extern int omap_gpio_init(void);
@@ -100,7 +99,7 @@
 
 static void __init netstar_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io();
 	omap_serial_init(omap_serial_ports);
 }
 
diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap1/board-osk.c
similarity index 97%
rename from arch/arm/mach-omap/board-osk.c
rename to arch/arm/mach-omap1/board-osk.c
index cb43343..6844e53 100644
--- a/arch/arm/mach-omap/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/board-osk.c
+ * linux/arch/arm/mach-omap1/board-osk.c
  *
  * Board specific init for OMAP5912 OSK
  *
@@ -39,8 +39,7 @@
 #include <asm/arch/usb.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 static struct map_desc osk5912_io_desc[] __initdata = {
 { OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE,
@@ -153,7 +152,7 @@
 
 static void __init osk_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io();
 	iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc));
 	omap_serial_init(osk_serial_ports);
 }
diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
similarity index 97%
rename from arch/arm/mach-omap/board-perseus2.c
rename to arch/arm/mach-omap1/board-perseus2.c
index d534204..2133173 100644
--- a/arch/arm/mach-omap/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/board-perseus2.c
+ * linux/arch/arm/mach-omap1/board-perseus2.c
  *
  * Modified from board-generic.c
  *
@@ -27,8 +27,7 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 static struct resource smc91x_resources[] = {
 	[0] = {
@@ -140,7 +139,7 @@
 
 static void __init omap_perseus2_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io();
 	iotable_init(omap_perseus2_io_desc,
 		     ARRAY_SIZE(omap_perseus2_io_desc));
 
diff --git a/arch/arm/mach-omap/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
similarity index 98%
rename from arch/arm/mach-omap/board-voiceblue.c
rename to arch/arm/mach-omap1/board-voiceblue.c
index 6b0c500..e422819 100644
--- a/arch/arm/mach-omap/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/board-voiceblue.c
+ * linux/arch/arm/mach-omap1/board-voiceblue.c
  *
  * Modified from board-generic.c
  *
@@ -31,8 +31,7 @@
 #include <asm/arch/tc.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
 
 extern void omap_init_time(void);
 extern int omap_gpio_init(void);
@@ -170,7 +169,7 @@
 
 static void __init voiceblue_map_io(void)
 {
-	omap_map_io();
+	omap_map_common_io();
 	omap_serial_init(omap_serial_ports);
 }
 
diff --git a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap1/fpga.c
similarity index 100%
rename from arch/arm/mach-omap/fpga.c
rename to arch/arm/mach-omap1/fpga.c
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
new file mode 100644
index 0000000..986c3b7
--- /dev/null
+++ b/arch/arm/mach-omap1/id.c
@@ -0,0 +1,188 @@
+/*
+ * linux/arch/arm/mach-omap1/id.c
+ *
+ * OMAP1 CPU identification code
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+struct omap_id {
+	u16	jtag_id;	/* Used to determine OMAP type */
+	u8	die_rev;	/* Processor revision */
+	u32	omap_id;	/* OMAP revision */
+	u32	type;		/* Cpu id bits [31:08], cpu class bits [07:00] */
+};
+
+/* Register values to detect the OMAP version */
+static struct omap_id omap_ids[] __initdata = {
+	{ .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
+	{ .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
+	{ .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
+	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
+	{ .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
+	{ .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
+	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
+	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+	{ .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
+	{ .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
+	{ .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
+	{ .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
+	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
+	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
+	{ .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
+	{ .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
+	{ .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
+};
+
+/*
+ * Get OMAP type from PROD_ID.
+ * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
+ * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
+ * Undocumented register in TEST BLOCK is used as fallback; This seems to
+ * work on 1510, 1610 & 1710. The official way hopefully will work in future
+ * processors.
+ */
+static u16 __init omap_get_jtag_id(void)
+{
+	u32 prod_id, omap_id;
+
+	prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
+	omap_id = omap_readl(OMAP32_ID_1);
+
+	/* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */
+	if (((prod_id >> 20) == 0) || (prod_id == omap_id))
+		prod_id = 0;
+	else
+		prod_id &= 0xffff;
+
+	if (prod_id)
+		return prod_id;
+
+	/* Use OMAP32_ID_1 as fallback */
+	prod_id = ((omap_id >> 12) & 0xffff);
+
+	return prod_id;
+}
+
+/*
+ * Get OMAP revision from DIE_REV.
+ * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
+ * Undocumented register in the TEST BLOCK is used as fallback.
+ * REVISIT: This does not seem to work on 1510
+ */
+static u8 __init omap_get_die_rev(void)
+{
+	u32 die_rev;
+
+	die_rev = omap_readl(OMAP_DIE_ID_1);
+
+	/* Check for broken OMAP_DIE_ID on early 1710 */
+	if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
+		die_rev = 0;
+
+	die_rev = (die_rev >> 17) & 0xf;
+	if (die_rev)
+		return die_rev;
+
+	die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
+
+	return die_rev;
+}
+
+void __init omap_check_revision(void)
+{
+	int i;
+	u16 jtag_id;
+	u8 die_rev;
+	u32 omap_id;
+	u8 cpu_type;
+
+	jtag_id = omap_get_jtag_id();
+	die_rev = omap_get_die_rev();
+	omap_id = omap_readl(OMAP32_ID_0);
+
+#ifdef DEBUG
+	printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
+	printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
+		omap_readl(OMAP_DIE_ID_1),
+	       (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
+	printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
+	printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
+		omap_readl(OMAP_PRODUCTION_ID_1),
+		omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
+	printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
+	printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
+	printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
+#endif
+
+	system_serial_high = omap_readl(OMAP_DIE_ID_0);
+	system_serial_low = omap_readl(OMAP_DIE_ID_1);
+
+	/* First check only the major version in a safe way */
+	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+		if (jtag_id == (omap_ids[i].jtag_id)) {
+			system_rev = omap_ids[i].type;
+			break;
+		}
+	}
+
+	/* Check if we can find the die revision */
+	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+		if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
+			system_rev = omap_ids[i].type;
+			break;
+		}
+	}
+
+	/* Finally check also the omap_id */
+	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+		if (jtag_id == omap_ids[i].jtag_id
+		    && die_rev == omap_ids[i].die_rev
+		    && omap_id == omap_ids[i].omap_id) {
+			system_rev = omap_ids[i].type;
+			break;
+		}
+	}
+
+	/* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
+	cpu_type = system_rev >> 24;
+
+	switch (cpu_type) {
+	case 0x07:
+		system_rev |= 0x07;
+		break;
+	case 0x15:
+		system_rev |= 0x15;
+		break;
+	case 0x16:
+	case 0x17:
+		system_rev |= 0x16;
+		break;
+	case 0x24:
+		system_rev |= 0x24;
+		break;
+	default:
+		printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
+	}
+
+	printk("OMAP%04x", system_rev >> 16);
+	if ((system_rev >> 8) & 0xff)
+		printk("%x", (system_rev >> 8) & 0xff);
+	printk(" revision %i handled as %02xxx id: %08x%08x\n",
+	       die_rev, system_rev & 0xff, system_serial_low,
+	       system_serial_high);
+}
+
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
new file mode 100644
index 0000000..207df0f
--- /dev/null
+++ b/arch/arm/mach-omap1/io.c
@@ -0,0 +1,115 @@
+/*
+ * linux/arch/arm/mach-omap1/io.c
+ *
+ * OMAP1 I/O mapping code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach/map.h>
+#include <asm/io.h>
+#include <asm/arch/tc.h>
+
+extern int clk_init(void);
+extern void omap_check_revision(void);
+
+/*
+ * The machine specific code may provide the extra mapping besides the
+ * default mapping provided here.
+ */
+static struct map_desc omap_io_desc[] __initdata = {
+ { IO_VIRT,      	IO_PHYS,             IO_SIZE,        	   MT_DEVICE },
+};
+
+#ifdef CONFIG_ARCH_OMAP730
+static struct map_desc omap730_io_desc[] __initdata = {
+ { OMAP730_DSP_BASE,    OMAP730_DSP_START,    OMAP730_DSP_SIZE,    MT_DEVICE },
+ { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE },
+ { OMAP730_SRAM_BASE,   OMAP730_SRAM_START,   OMAP730_SRAM_SIZE,   MT_DEVICE }
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct map_desc omap1510_io_desc[] __initdata = {
+ { OMAP1510_DSP_BASE,    OMAP1510_DSP_START,    OMAP1510_DSP_SIZE,    MT_DEVICE },
+ { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE },
+ { OMAP1510_SRAM_BASE,   OMAP1510_SRAM_START,   OMAP1510_SRAM_SIZE,   MT_DEVICE }
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+static struct map_desc omap1610_io_desc[] __initdata = {
+ { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+ { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP1610_SRAM_SIZE,   MT_DEVICE }
+};
+
+static struct map_desc omap5912_io_desc[] __initdata = {
+ { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+/*
+ * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page
+ * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped.
+ * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte
+ * can be used.
+ */
+ { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP5912_SRAM_SIZE + 0x800,   MT_DEVICE }
+};
+#endif
+
+static int initialized = 0;
+
+static void __init _omap_map_io(void)
+{
+	initialized = 1;
+
+	/* We have to initialize the IO space mapping before we can run
+	 * cpu_is_omapxxx() macros. */
+	iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
+	omap_check_revision();
+
+#ifdef CONFIG_ARCH_OMAP730
+	if (cpu_is_omap730()) {
+		iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
+	}
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
+	}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (cpu_is_omap1610() || cpu_is_omap1710()) {
+		iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
+	}
+	if (cpu_is_omap5912()) {
+		iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc));
+	}
+#endif
+
+	/* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
+	 * on a Posted Write in the TIPB Bridge".
+	 */
+	omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL);
+	omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL);
+
+	/* Must init clocks early to assure that timer interrupt works
+	 */
+	clk_init();
+}
+
+/*
+ * This should only get called from board specific init
+ */
+void omap_map_common_io(void)
+{
+	if (!initialized)
+		_omap_map_io();
+}
diff --git a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap1/irq.c
similarity index 94%
rename from arch/arm/mach-omap/irq.c
rename to arch/arm/mach-omap1/irq.c
index f01c992..a11b6d8 100644
--- a/arch/arm/mach-omap/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -56,6 +56,7 @@
 struct omap_irq_bank {
 	unsigned long base_reg;
 	unsigned long trigger_map;
+	unsigned long wake_enable;
 };
 
 static unsigned int irq_bank_count = 0;
@@ -105,6 +106,19 @@
 	omap_ack_irq(irq);
 }
 
+static int omap_wake_irq(unsigned int irq, unsigned int enable)
+{
+	int bank = IRQ_BANK(irq);
+
+	if (enable)
+		irq_banks[bank].wake_enable |= IRQ_BIT(irq);
+	else
+		irq_banks[bank].wake_enable &= ~IRQ_BIT(irq);
+
+	return 0;
+}
+
+
 /*
  * Allows tuning the IRQ type and priority
  *
@@ -145,7 +159,7 @@
 static struct omap_irq_bank omap1610_irq_banks[] = {
 	{ .base_reg = OMAP_IH1_BASE, 		.trigger_map = 0xb3fefe8f },
 	{ .base_reg = OMAP_IH2_BASE, 		.trigger_map = 0xfdb7c1fd },
-	{ .base_reg = OMAP_IH2_BASE + 0x100,	.trigger_map = 0xfffff7ff },
+	{ .base_reg = OMAP_IH2_BASE + 0x100,	.trigger_map = 0xffffb7ff },
 	{ .base_reg = OMAP_IH2_BASE + 0x200,	.trigger_map = 0xffffffff },
 };
 #endif
@@ -154,6 +168,7 @@
 	.ack    = omap_mask_ack_irq,
 	.mask   = omap_mask_irq,
 	.unmask = omap_unmask_irq,
+	.wake	= omap_wake_irq,
 };
 
 void __init omap_init_irq(void)
diff --git a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
similarity index 100%
rename from arch/arm/mach-omap/leds-h2p2-debug.c
rename to arch/arm/mach-omap1/leds-h2p2-debug.c
diff --git a/arch/arm/mach-omap/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
similarity index 100%
rename from arch/arm/mach-omap/leds-innovator.c
rename to arch/arm/mach-omap1/leds-innovator.c
diff --git a/arch/arm/mach-omap/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
similarity index 98%
rename from arch/arm/mach-omap/leds-osk.c
rename to arch/arm/mach-omap1/leds-osk.c
index f5177f4..4a0e8b9 100644
--- a/arch/arm/mach-omap/leds-osk.c
+++ b/arch/arm/mach-omap1/leds-osk.c
@@ -129,14 +129,11 @@
 
 #ifdef	CONFIG_FB_OMAP
 
-#ifdef CONFIG_LEDS_TIMER
 	case led_timer:
 		hw_led_state ^= TIMER_LED;
 		mistral_setled();
 		break;
-#endif
 
-#ifdef CONFIG_LEDS_CPU
 	case led_idle_start:
 		hw_led_state |= IDLE_LED;
 		mistral_setled();
@@ -146,7 +143,6 @@
 		hw_led_state &= ~IDLE_LED;
 		mistral_setled();
 		break;
-#endif
 
 #endif	/* CONFIG_FB_OMAP */
 
diff --git a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap1/leds.c
similarity index 100%
rename from arch/arm/mach-omap/leds.c
rename to arch/arm/mach-omap1/leds.c
diff --git a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap1/leds.h
similarity index 100%
rename from arch/arm/mach-omap/leds.h
rename to arch/arm/mach-omap1/leds.h
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
new file mode 100644
index 0000000..214e5d1
--- /dev/null
+++ b/arch/arm/mach-omap1/serial.c
@@ -0,0 +1,200 @@
+/*
+ * linux/arch/arm/mach-omap1/id.c
+ *
+ * OMAP1 CPU identification code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+
+static struct clk * uart1_ck = NULL;
+static struct clk * uart2_ck = NULL;
+static struct clk * uart3_ck = NULL;
+
+static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
+					  int offset)
+{
+	offset <<= up->regshift;
+	return (unsigned int)__raw_readb(up->membase + offset);
+}
+
+static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
+				    int value)
+{
+	offset <<= p->regshift;
+	__raw_writeb(value, p->membase + offset);
+}
+
+/*
+ * Internal UARTs need to be initialized for the 8250 autoconfig to work
+ * properly. Note that the TX watermark initialization may not be needed
+ * once the 8250.c watermark handling code is merged.
+ */
+static void __init omap_serial_reset(struct plat_serial8250_port *p)
+{
+	omap_serial_outp(p, UART_OMAP_MDR1, 0x07);	/* disable UART */
+	omap_serial_outp(p, UART_OMAP_SCR, 0x08);	/* TX watermark */
+	omap_serial_outp(p, UART_OMAP_MDR1, 0x00);	/* enable UART */
+
+	if (!cpu_is_omap1510()) {
+		omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
+		while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
+	}
+}
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	{
+		.membase	= (char*)IO_ADDRESS(OMAP_UART1_BASE),
+		.mapbase	= (unsigned long)OMAP_UART1_BASE,
+		.irq		= INT_UART1,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	},
+	{
+		.membase	= (char*)IO_ADDRESS(OMAP_UART2_BASE),
+		.mapbase	= (unsigned long)OMAP_UART2_BASE,
+		.irq		= INT_UART2,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	},
+	{
+		.membase	= (char*)IO_ADDRESS(OMAP_UART3_BASE),
+		.mapbase	= (unsigned long)OMAP_UART3_BASE,
+		.irq		= INT_UART3,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	},
+	{ },
+};
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= 0,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+};
+
+/*
+ * Note that on Innovator-1510 UART2 pins conflict with USB2.
+ * By default UART2 does not work on Innovator-1510 if you have
+ * USB OHCI enabled. To use UART2, you must disable USB2 first.
+ */
+void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
+{
+	int i;
+
+	if (cpu_is_omap730()) {
+		serial_platform_data[0].regshift = 0;
+		serial_platform_data[1].regshift = 0;
+		serial_platform_data[0].irq = INT_730_UART_MODEM_1;
+		serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
+	}
+
+	if (cpu_is_omap1510()) {
+		serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
+		serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
+		serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
+	}
+
+	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+		unsigned char reg;
+
+		if (ports[i] == 0) {
+			serial_platform_data[i].membase = NULL;
+			serial_platform_data[i].mapbase = 0;
+			continue;
+		}
+
+		switch (i) {
+		case 0:
+			uart1_ck = clk_get(NULL, "uart1_ck");
+			if (IS_ERR(uart1_ck))
+				printk("Could not get uart1_ck\n");
+			else {
+				clk_use(uart1_ck);
+				if (cpu_is_omap1510())
+					clk_set_rate(uart1_ck, 12000000);
+			}
+			if (cpu_is_omap1510()) {
+				omap_cfg_reg(UART1_TX);
+				omap_cfg_reg(UART1_RTS);
+				if (machine_is_omap_innovator()) {
+					reg = fpga_read(OMAP1510_FPGA_POWER);
+					reg |= OMAP1510_FPGA_PCR_COM1_EN;
+					fpga_write(reg, OMAP1510_FPGA_POWER);
+					udelay(10);
+				}
+			}
+			break;
+		case 1:
+			uart2_ck = clk_get(NULL, "uart2_ck");
+			if (IS_ERR(uart2_ck))
+				printk("Could not get uart2_ck\n");
+			else {
+				clk_use(uart2_ck);
+				if (cpu_is_omap1510())
+					clk_set_rate(uart2_ck, 12000000);
+				else
+					clk_set_rate(uart2_ck, 48000000);
+			}
+			if (cpu_is_omap1510()) {
+				omap_cfg_reg(UART2_TX);
+				omap_cfg_reg(UART2_RTS);
+				if (machine_is_omap_innovator()) {
+					reg = fpga_read(OMAP1510_FPGA_POWER);
+					reg |= OMAP1510_FPGA_PCR_COM2_EN;
+					fpga_write(reg, OMAP1510_FPGA_POWER);
+					udelay(10);
+				}
+			}
+			break;
+		case 2:
+			uart3_ck = clk_get(NULL, "uart3_ck");
+			if (IS_ERR(uart3_ck))
+				printk("Could not get uart3_ck\n");
+			else {
+				clk_use(uart3_ck);
+				if (cpu_is_omap1510())
+					clk_set_rate(uart3_ck, 12000000);
+			}
+			if (cpu_is_omap1510()) {
+				omap_cfg_reg(UART3_TX);
+				omap_cfg_reg(UART3_RX);
+			}
+			break;
+		}
+		omap_serial_reset(&serial_platform_data[i]);
+	}
+}
+
+static int __init omap_init(void)
+{
+	return platform_device_register(&serial_device);
+}
+arch_initcall(omap_init);
diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap1/time.c
similarity index 94%
rename from arch/arm/mach-omap/time.c
rename to arch/arm/mach-omap1/time.c
index dd34e9f..d540539 100644
--- a/arch/arm/mach-omap/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/time.c
+ * linux/arch/arm/mach-omap1/time.c
  *
  * OMAP Timers
  *
@@ -58,17 +58,9 @@
  * MPU timer
  * ---------------------------------------------------------------------------
  */
-#define OMAP_MPU_TIMER1_BASE		(0xfffec500)
-#define OMAP_MPU_TIMER2_BASE		(0xfffec600)
-#define OMAP_MPU_TIMER3_BASE		(0xfffec700)
 #define OMAP_MPU_TIMER_BASE		OMAP_MPU_TIMER1_BASE
 #define OMAP_MPU_TIMER_OFFSET		0x100
 
-#define MPU_TIMER_FREE			(1 << 6)
-#define MPU_TIMER_CLOCK_ENABLE		(1 << 5)
-#define MPU_TIMER_AR			(1 << 1)
-#define MPU_TIMER_ST			(1 << 0)
-
 /* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c,
  * converted to use kHz by Kevin Hilman */
 /* convert from cycles(64bits) => nanoseconds (64bits)
@@ -255,6 +247,13 @@
 #define OMAP_32K_TIMER_TCR		0x04
 
 #define OMAP_32K_TICKS_PER_HZ		(32768 / HZ)
+#if (32768 % HZ) != 0
+/* We cannot ignore modulo.
+ * Potential error can be as high as several percent.
+ */
+#define OMAP_32K_TICK_MODULO		(32768 % HZ)
+static unsigned modulo_count = 0; /* Counts 1/HZ units */
+#endif
 
 /*
  * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
@@ -331,6 +330,19 @@
 	now = omap_32k_sync_timer_read();
 
 	while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+#ifdef OMAP_32K_TICK_MODULO
+		/* Modulo addition may put omap_32k_last_tick ahead of now
+		 * and cause unwanted repetition of the while loop.
+		 */
+		if (unlikely(now - omap_32k_last_tick == ~0))
+			break;
+
+		modulo_count += OMAP_32K_TICK_MODULO;
+		if (modulo_count > HZ) {
+			++omap_32k_last_tick;
+			modulo_count -= HZ;
+		}
+#endif
 		omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
 		timer_tick(regs);
 	}
@@ -407,7 +419,7 @@
  * Timer initialization
  * ---------------------------------------------------------------------------
  */
-void __init omap_timer_init(void)
+static void __init omap_timer_init(void)
 {
 #if defined(CONFIG_OMAP_MPU_TIMER)
 	omap_init_mpu_timer();
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 95606b4..afbbeb6 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -101,7 +101,7 @@
 
 # ARM925T
 config CPU_ARM925T
- 	bool "Support ARM925T processor" if ARCH_OMAP
+ 	bool "Support ARM925T processor" if ARCH_OMAP1
  	depends on ARCH_OMAP1510
  	default y if ARCH_OMAP1510
 	select CPU_32v4
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index c3bd503..b19f00e 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -399,7 +399,7 @@
 		ecc_mask = 0;
 	}
 
-	if (cpu_arch <= CPU_ARCH_ARMv5) {
+	if (cpu_arch <= CPU_ARCH_ARMv5TEJ) {
 		for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
 			if (mem_types[i].prot_l1)
 				mem_types[i].prot_l1 |= PMD_BIT4;
@@ -584,7 +584,7 @@
 		pmdval = (i << PGDIR_SHIFT) |
 			 PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
 			 PMD_TYPE_SECT;
-		if (cpu_arch <= CPU_ARCH_ARMv5)
+		if (cpu_arch <= CPU_ARCH_ARMv5TEJ)
 			pmdval |= PMD_BIT4;
 		pmd = pmd_off(pgd, i << PGDIR_SHIFT);
 		pmd[0] = __pmd(pmdval);
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index e3d8510..352db98 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -200,7 +200,7 @@
 	mcr	p15, 0, r4, c2, c0, 1		@ load TTB1
 #ifdef CONFIG_VFP
 	mrc	p15, 0, r0, c1, c0, 2
-	orr	r0, r0, #(3 << 20)
+	orr	r0, r0, #(0xf << 20)
 	mcr	p15, 0, r0, c1, c0, 2		@ Enable full access to VFP
 #endif
 	mrc	p15, 0, r0, c1, c0, 0		@ read control register
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
new file mode 100644
index 0000000..3453658
--- /dev/null
+++ b/arch/arm/plat-omap/Kconfig
@@ -0,0 +1,112 @@
+if ARCH_OMAP
+
+menu "TI OMAP Implementations"
+
+config ARCH_OMAP_OTG
+	bool
+
+choice
+	prompt "OMAP System Type"
+	default ARCH_OMAP1
+
+config ARCH_OMAP1
+	bool "TI OMAP1"
+
+config ARCH_OMAP2
+	bool "TI OMAP2"
+
+endchoice
+
+comment "OMAP Feature Selections"
+
+config OMAP_RESET_CLOCKS
+	bool "Reset unused clocks during boot"
+	depends on ARCH_OMAP
+	default n
+	help
+	  Say Y if you want to reset unused clocks during boot.
+	  This option saves power, but assumes all drivers are
+	  using the clock framework. Broken drivers that do not
+	  yet use clock framework may not work with this option.
+	  If you are booting from another operating system, you
+	  probably do not want this option enabled until your
+	  device drivers work properly.
+
+config OMAP_MUX
+	bool "OMAP multiplexing support"
+        depends on ARCH_OMAP
+	default y
+        help
+          Pin multiplexing support for OMAP boards. If your bootloader
+          sets the multiplexing correctly, say N. Otherwise, or if unsure,
+          say Y.
+
+config OMAP_MUX_DEBUG
+	bool "Multiplexing debug output"
+        depends on OMAP_MUX
+        default n
+        help
+          Makes the multiplexing functions print out a lot of debug info.
+          This is useful if you want to find out the correct values of the
+          multiplexing registers.
+
+config OMAP_MUX_WARNINGS
+	bool "Warn about pins the bootloader didn't set up"
+        depends on OMAP_MUX
+        default y
+        help
+	  Choose Y here to warn whenever driver initialization logic needs
+	  to change the pin multiplexing setup.  When there are no warnings
+	  printed, it's safe to deselect OMAP_MUX for your product.
+
+choice
+        prompt "System timer"
+	default OMAP_MPU_TIMER
+
+config OMAP_MPU_TIMER
+	bool "Use mpu timer"
+	help
+	  Select this option if you want to use the OMAP mpu timer. This
+	  timer provides more intra-tick resolution than the 32KHz timer,
+	  but consumes more power.
+
+config OMAP_32K_TIMER
+	bool "Use 32KHz timer"
+	depends on ARCH_OMAP16XX
+	help
+	  Select this option if you want to enable the OMAP 32KHz timer.
+	  This timer saves power compared to the OMAP_MPU_TIMER, and has
+	  support for no tick during idle. The 32KHz timer provides less
+	  intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
+	  currently only available for OMAP-16xx.
+
+endchoice
+
+config OMAP_32K_TIMER_HZ
+       int "Kernel internal timer frequency for 32KHz timer"
+       range 32 1024
+       depends on OMAP_32K_TIMER
+       default "128"
+       help
+	  Kernel internal timer frequency should be a divisor of 32768,
+	  such as 64 or 128.
+
+choice
+	prompt "Low-level debug console UART"
+	depends on ARCH_OMAP
+	default OMAP_LL_DEBUG_UART1
+
+config OMAP_LL_DEBUG_UART1
+	bool "UART1"
+
+config OMAP_LL_DEBUG_UART2
+	bool "UART2"
+
+config OMAP_LL_DEBUG_UART3
+	bool "UART3"
+
+endchoice
+
+endmenu
+
+endif
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
new file mode 100644
index 0000000..531e11a
--- /dev/null
+++ b/arch/arm/plat-omap/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
+obj-m :=
+obj-n :=
+obj-  :=
+
+# OCPI interconnect support for 1710, 1610 and 5912
+obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
+
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
+obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
diff --git a/arch/arm/mach-omap/clock.c b/arch/arm/plat-omap/clock.c
similarity index 74%
rename from arch/arm/mach-omap/clock.c
rename to arch/arm/plat-omap/clock.c
index e91186b..59d91b3 100644
--- a/arch/arm/mach-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/mach-omap/clock.c
+ *  linux/arch/arm/plat-omap/clock.c
  *
  *  Copyright (C) 2004 Nokia corporation
  *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 
+#include <asm/io.h>
 #include <asm/semaphore.h>
 #include <asm/hardware/clock.h>
 #include <asm/arch/board.h>
@@ -25,6 +26,8 @@
 static DECLARE_MUTEX(clocks_sem);
 static DEFINE_SPINLOCK(clockfw_lock);
 static void propagate_rate(struct clk *  clk);
+/* UART clock function */
+static int set_uart_rate(struct clk * clk, unsigned long rate);
 /* External clock (MCLK & BCLK) functions */
 static int set_ext_clk_rate(struct clk *  clk, unsigned long rate);
 static long round_ext_clk_rate(struct clk *  clk, unsigned long rate);
@@ -34,7 +37,7 @@
 static long round_to_table_rate(struct clk *  clk, unsigned long rate);
 void clk_setdpll(__u16, __u16);
 
-struct mpu_rate rate_table[] = {
+static struct mpu_rate rate_table[] = {
 	/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
 	 * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
 	 */
@@ -48,7 +51,7 @@
 	{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
 	{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
 	{  96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
-	{  48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */
+	{  48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/8/4/4/8/8 */
 	{  24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
 #endif
 #if defined(CONFIG_OMAP_ARM_182MHZ)
@@ -58,7 +61,7 @@
 	{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
 #endif
 #if defined(CONFIG_OMAP_ARM_150MHZ)
-	{ 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
+	{ 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */
 #endif
 #if defined(CONFIG_OMAP_ARM_120MHZ)
 	{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
@@ -76,19 +79,11 @@
 };
 
 
-static void ckctl_recalc(struct clk *  clk)
-{
-	int dsor;
-
-	/* Calculate divisor encoded as 2-bit exponent */
-	dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
-	if (unlikely(clk->rate == clk->parent->rate / dsor))
-		return; /* No change, quick exit */
-	clk->rate = clk->parent->rate / dsor;
-
-	if (unlikely(clk->flags & RATE_PROPAGATES))
-		propagate_rate(clk);
-}
+static void ckctl_recalc(struct clk *  clk);
+int __clk_enable(struct clk *clk);
+void __clk_disable(struct clk *clk);
+void __clk_unuse(struct clk *clk);
+int __clk_use(struct clk *clk);
 
 
 static void followparent_recalc(struct clk *  clk)
@@ -102,6 +97,14 @@
 	clk->rate = clk->parent->rate / 14;
 }
 
+static void uart_recalc(struct clk * clk)
+{
+	unsigned int val = omap_readl(clk->enable_reg);
+	if (val & clk->enable_bit)
+		clk->rate = 48000000;
+	else
+		clk->rate = 12000000;
+}
 
 static struct clk ck_ref = {
 	.name		= "ck_ref",
@@ -138,7 +141,7 @@
 static struct clk armper_ck = {
 	.name		= "armper_ck",
 	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+	.flags		= CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
 			  RATE_CKCTL,
 	.enable_reg	= ARM_IDLECT2,
 	.enable_bit	= EN_PERCK,
@@ -185,7 +188,7 @@
 static struct clk arminth_ck16xx = {
 	.name		= "arminth_ck",
 	.parent		= &arm_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 	/* Note: On 16xx the frequency can be divided by 2 by programming
 	 * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
@@ -214,6 +217,38 @@
 	.recalc		= &ckctl_recalc,
 };
 
+static struct clk dspper_ck = {
+	.name		= "dspper_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+	.enable_reg	= DSP_IDLECT2,
+	.enable_bit	= EN_PERCK,
+	.rate_offset	= CKCTL_PERDIV_OFFSET,
+	.recalc		= &followparent_recalc,
+	//.recalc		= &ckctl_recalc,
+};
+
+static struct clk dspxor_ck = {
+	.name		= "dspxor_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+	.enable_reg	= DSP_IDLECT2,
+	.enable_bit	= EN_XORPCK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dsptim_ck = {
+	.name		= "dsptim_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+	.enable_reg	= DSP_IDLECT2,
+	.enable_bit	= EN_DSPTIMCK,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk tc_ck = {
 	.name		= "tc_ck",
 	.parent		= &ck_dpll1,
@@ -226,7 +261,7 @@
 static struct clk arminth_ck1510 = {
 	.name		= "arminth_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510,
+	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 	/* Note: On 1510 the frequency follows TC_CK
 	 *
@@ -237,7 +272,7 @@
 static struct clk tipb_ck = {
 	.name		= "tibp_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510,
+	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
@@ -271,14 +306,15 @@
 static struct clk dma_ck = {
 	.name		= "dma_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
 static struct clk dma_lcdfree_ck = {
 	.name		= "dma_lcdfree_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
@@ -303,14 +339,14 @@
 static struct clk rhea1_ck = {
 	.name		= "rhea1_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
 static struct clk rhea2_ck = {
 	.name		= "rhea2_ck",
 	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
 	.recalc		= &followparent_recalc,
 };
 
@@ -325,43 +361,55 @@
 	.recalc		= &ckctl_recalc,
 };
 
-static struct clk uart1_ck = {
+static struct clk uart1_1510 = {
+	.name		= "uart1_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 29,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &set_uart_rate,
+	.recalc		= &uart_recalc,
+};
+
+static struct clk uart1_16xx = {
 	.name		= "uart1_ck",
 	/* Direct from ULPD, no parent */
 	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
+	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
 	.enable_reg	= MOD_CONF_CTRL_0,
 	.enable_bit	= 29,
-	/* (Only on 1510)
-	 * The "enable bit" actually chooses between 48MHz and 12MHz.
-	 */
 };
 
 static struct clk uart2_ck = {
 	.name		= "uart2_ck",
 	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT,
 	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 30,
-	/* (for both 1510 and 16xx)
-	 * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
-	 */
+	.enable_bit	= 30,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &set_uart_rate,
+	.recalc		= &uart_recalc,
 };
 
-static struct clk uart3_ck = {
+static struct clk uart3_1510 = {
+	.name		= "uart3_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 31,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &set_uart_rate,
+	.recalc		= &uart_recalc,
+};
+
+static struct clk uart3_16xx = {
 	.name		= "uart3_ck",
 	/* Direct from ULPD, no parent */
 	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
+	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
 	.enable_reg	= MOD_CONF_CTRL_0,
 	.enable_bit	= 31,
-	/* (Only on 1510)
-	 * The "enable bit" actually chooses between 48MHz and 12MHz.
-	 */
 };
 
 static struct clk usb_clko = {	/* 6 MHz output on W4_USB_CLKO */
@@ -480,6 +528,9 @@
 	/* CK_GEN2 clocks */
 	&dsp_ck,
 	&dspmmu_ck,
+	&dspper_ck,
+	&dspxor_ck,
+	&dsptim_ck,
 	/* CK_GEN3 clocks */
 	&tc_ck,
 	&tipb_ck,
@@ -494,9 +545,11 @@
 	&rhea2_ck,
 	&lcd_ck,
 	/* ULPD clocks */
-	&uart1_ck,
+	&uart1_1510,
+	&uart1_16xx,
 	&uart2_ck,
-	&uart3_ck,
+	&uart3_1510,
+	&uart3_16xx,
 	&usb_clko,
 	&usb_hhc_ck1510, &usb_hhc_ck16xx,
 	&mclk_1510,  &mclk_16xx,
@@ -547,14 +600,34 @@
 		return 0;
 	}
 
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_use(&api_ck);
+	}
+
 	if (clk->flags & ENABLE_REG_32BIT) {
-		regval32 = omap_readl(clk->enable_reg);
-		regval32 |= (1 << clk->enable_bit);
-		omap_writel(regval32, clk->enable_reg);
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval32 = __raw_readl(clk->enable_reg);
+			regval32 |= (1 << clk->enable_bit);
+			__raw_writel(regval32, clk->enable_reg);
+		} else {
+			regval32 = omap_readl(clk->enable_reg);
+			regval32 |= (1 << clk->enable_bit);
+			omap_writel(regval32, clk->enable_reg);
+		}
 	} else {
-		regval16 = omap_readw(clk->enable_reg);
-		regval16 |= (1 << clk->enable_bit);
-		omap_writew(regval16, clk->enable_reg);
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval16 = __raw_readw(clk->enable_reg);
+			regval16 |= (1 << clk->enable_bit);
+			__raw_writew(regval16, clk->enable_reg);
+		} else {
+			regval16 = omap_readw(clk->enable_reg);
+			regval16 |= (1 << clk->enable_bit);
+			omap_writew(regval16, clk->enable_reg);
+		}
+	}
+
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_unuse(&api_ck);
 	}
 
 	return 0;
@@ -569,14 +642,34 @@
 	if (clk->enable_reg == 0)
 		return;
 
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_use(&api_ck);
+	}
+
 	if (clk->flags & ENABLE_REG_32BIT) {
-		regval32 = omap_readl(clk->enable_reg);
-		regval32 &= ~(1 << clk->enable_bit);
-		omap_writel(regval32, clk->enable_reg);
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval32 = __raw_readl(clk->enable_reg);
+			regval32 &= ~(1 << clk->enable_bit);
+			__raw_writel(regval32, clk->enable_reg);
+		} else {
+			regval32 = omap_readl(clk->enable_reg);
+			regval32 &= ~(1 << clk->enable_bit);
+			omap_writel(regval32, clk->enable_reg);
+		}
 	} else {
-		regval16 = omap_readw(clk->enable_reg);
-		regval16 &= ~(1 << clk->enable_bit);
-		omap_writew(regval16, clk->enable_reg);
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval16 = __raw_readw(clk->enable_reg);
+			regval16 &= ~(1 << clk->enable_bit);
+			__raw_writew(regval16, clk->enable_reg);
+		} else {
+			regval16 = omap_readw(clk->enable_reg);
+			regval16 &= ~(1 << clk->enable_bit);
+			omap_writew(regval16, clk->enable_reg);
+		}
+	}
+
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		__clk_unuse(&api_ck);
 	}
 }
 
@@ -766,6 +859,33 @@
 	return dsor_exp;
 }
 
+
+static void ckctl_recalc(struct clk *  clk)
+{
+	int dsor;
+
+	/* Calculate divisor encoded as 2-bit exponent */
+	if (clk->flags & DSP_DOMAIN_CLOCK) {
+		/* The clock control bits are in DSP domain,
+		 * so api_ck is needed for access.
+		 * Note that DSP_CKCTL virt addr = phys addr, so
+		 * we must use __raw_readw() instead of omap_readw().
+		 */
+		__clk_use(&api_ck);
+		dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
+		__clk_unuse(&api_ck);
+	} else {
+		dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+	}
+	if (unlikely(clk->rate == clk->parent->rate / dsor))
+		return; /* No change, quick exit */
+	clk->rate = clk->parent->rate / dsor;
+
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
+}
+
+
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
 	int dsor_exp;
@@ -826,6 +946,9 @@
 	if (!ptr->rate)
 		return -EINVAL;
 
+	if (!ptr->rate)
+		return -EINVAL;
+
 	if (unlikely(ck_dpll1.rate == 0)) {
 		omap_writew(ptr->dpllctl_val, DPLL_CTL);
 		ck_dpll1.rate = ptr->pll_rate;
@@ -921,6 +1044,23 @@
 	return dsor;
 }
 
+/* Only needed on 1510 */
+static int set_uart_rate(struct clk * clk, unsigned long rate)
+{
+	unsigned int val;
+
+	val = omap_readl(clk->enable_reg);
+	if (rate == 12000000)
+		val &= ~(1 << clk->enable_bit);
+	else if (rate == 48000000)
+		val |= (1 << clk->enable_bit);
+	else
+		return -EINVAL;
+	omap_writel(val, clk->enable_reg);
+	clk->rate = rate;
+
+	return 0;
+}
 
 static int set_ext_clk_rate(struct clk *  clk, unsigned long rate)
 {
@@ -985,7 +1125,18 @@
 }
 EXPORT_SYMBOL(clk_unregister);
 
-
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+/*
+ * Resets some clocks that may be left on from bootloader,
+ * but leaves serial clocks on. See also omap_late_clk_reset().
+ */
+static inline void omap_early_clk_reset(void)
+{
+	//omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
+}
+#else
+#define omap_early_clk_reset()	{}
+#endif
 
 int __init clk_init(void)
 {
@@ -993,6 +1144,8 @@
 	const struct omap_clock_config *info;
 	int crystal_type = 0; /* Default 12 MHz */
 
+	omap_early_clk_reset();
+
 	for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
 		if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) {
 			clk_register(*clkp);
@@ -1023,9 +1176,42 @@
 		ck_ref.rate = 19200000;
 #endif
 
+	printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+	       omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+	       omap_readw(ARM_CKCTL));
+
 	/* We want to be in syncronous scalable mode */
 	omap_writew(0x1000, ARM_SYSST);
 
+#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
+	/* Use values set by bootloader. Determine PLL rate and recalculate
+	 * dependent clocks as if kernel had changed PLL or divisors.
+	 */
+	{
+		unsigned pll_ctl_val = omap_readw(DPLL_CTL);
+
+		ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
+		if (pll_ctl_val & 0x10) {
+			/* PLL enabled, apply multiplier and divisor */
+			if (pll_ctl_val & 0xf80)
+				ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
+			ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
+		} else {
+			/* PLL disabled, apply bypass divisor */
+			switch (pll_ctl_val & 0xc) {
+			case 0:
+				break;
+			case 0x4:
+				ck_dpll1.rate /= 2;
+				break;
+			default:
+				ck_dpll1.rate /= 4;
+				break;
+			}
+		}
+	}
+	propagate_rate(&ck_dpll1);
+#else
 	/* Find the highest supported frequency and enable it */
 	if (select_table_rate(&virtual_ck_mpu, ~0)) {
 		printk(KERN_ERR "System frequencies not set. Check your config.\n");
@@ -1034,12 +1220,13 @@
 		omap_writew(0x1005, ARM_CKCTL);
 		ck_dpll1.rate = 60000000;
 		propagate_rate(&ck_dpll1);
-		printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n",
-		       ck_ref.rate, ck_dpll1.rate, arm_ck.rate);
 	}
-
+#endif
 	/* Cache rates for clocks connected to ck_ref (not dpll1) */
 	propagate_rate(&ck_ref);
+	printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
+	       ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+	       ck_dpll1.rate, arm_ck.rate);
 
 #ifdef CONFIG_MACH_OMAP_PERSEUS2
 	/* Select slicer output as OMAP input clock */
@@ -1074,3 +1261,63 @@
 
 	return 0;
 }
+
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+
+static int __init omap_late_clk_reset(void)
+{
+	/* Turn off all unused clocks */
+	struct clk *p;
+	__u32 regval32;
+
+	omap_writew(0, SOFT_REQ_REG);
+	omap_writew(0, SOFT_REQ_REG2);
+
+	list_for_each_entry(p, &clocks, node) {
+		if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
+			p->enable_reg == 0)
+			continue;
+
+		/* Assume no DSP clocks have been activated by bootloader */
+		if (p->flags & DSP_DOMAIN_CLOCK)
+			continue;
+
+		/* Is the clock already disabled? */
+		if (p->flags & ENABLE_REG_32BIT) {
+			if (p->flags & VIRTUAL_IO_ADDRESS)
+				regval32 = __raw_readl(p->enable_reg);
+			else
+				regval32 = omap_readl(p->enable_reg);
+		} else {
+			if (p->flags & VIRTUAL_IO_ADDRESS)
+				regval32 = __raw_readw(p->enable_reg);
+			else
+				regval32 = omap_readw(p->enable_reg);
+		}
+
+		if ((regval32 & (1 << p->enable_bit)) == 0)
+			continue;
+
+		/* FIXME: This clock seems to be necessary but no-one
+		 * has asked for its activation. */
+		if (p == &tc2_ck         // FIX: pm.c (SRAM), CCP, Camera
+		    || p == &ck_dpll1out // FIX: SoSSI, SSR
+		    || p == &arm_gpio_ck // FIX: GPIO code for 1510
+		    ) {
+			printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+			       p->name);
+			continue;
+		}
+
+		printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
+		__clk_disable(p);
+		printk(" done\n");
+	}
+
+	return 0;
+}
+
+late_initcall(omap_late_clk_reset);
+
+#endif
diff --git a/arch/arm/mach-omap/clock.h b/arch/arm/plat-omap/clock.h
similarity index 89%
rename from arch/arm/mach-omap/clock.h
rename to arch/arm/plat-omap/clock.h
index 08c0ddd..a89e1e8 100644
--- a/arch/arm/mach-omap/clock.h
+++ b/arch/arm/plat-omap/clock.h
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/mach-omap/clock.h
+ *  linux/arch/arm/plat-omap/clock.h
  *
  *  Copyright (C) 2004 Nokia corporation
  *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
@@ -52,6 +52,8 @@
 #define CLOCK_IN_OMAP16XX	64
 #define CLOCK_IN_OMAP1510	128
 #define CLOCK_IN_OMAP730	256
+#define DSP_DOMAIN_CLOCK	512
+#define VIRTUAL_IO_ADDRESS	1024
 
 /* ARM_CKCTL bit shifts */
 #define CKCTL_PERDIV_OFFSET	0
@@ -63,6 +65,8 @@
 /*#define ARM_TIMXO		12*/
 #define EN_DSPCK		13
 /*#define ARM_INTHCK_SEL	14*/ /* Divide-by-2 for mpu inth_ck */
+/* DSP_CKCTL bit shifts */
+#define CKCTL_DSPPERDIV_OFFSET	0
 
 /* ARM_IDLECT1 bit shifts */
 /*#define IDLWDT_ARM	0*/
@@ -96,6 +100,9 @@
 #define EN_TC1_CK	2
 #define EN_TC2_CK	4
 
+/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */
+#define EN_DSPTIMCK	5
+
 /* Various register defines for clock controls scattered around OMAP chip */
 #define USB_MCLK_EN_BIT		4	/* In ULPD_CLKC_CTRL */
 #define USB_HOST_HHC_UHOST_EN	9	/* In MOD_CONF_CTRL_0 */
@@ -103,7 +110,8 @@
 #define COM_ULPD_PLL_CLK_REQ	1	/* In COM_CLK_DIV_CTRL_SEL */
 #define SWD_CLK_DIV_CTRL_SEL	0xfffe0874
 #define COM_CLK_DIV_CTRL_SEL	0xfffe0878
-
+#define SOFT_REQ_REG		0xfffe0834
+#define SOFT_REQ_REG2		0xfffe0880
 
 int clk_register(struct clk *clk);
 void clk_unregister(struct clk *clk);
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
new file mode 100644
index 0000000..ea967a8
--- /dev/null
+++ b/arch/arm/plat-omap/common.c
@@ -0,0 +1,135 @@
+/*
+ * linux/arch/arm/plat-omap/common.c
+ *
+ * Code common to all OMAP machines.
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/hardware.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/clock.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+
+#include "clock.h"
+
+#define NO_LENGTH_CHECK 0xffffffff
+
+extern int omap_bootloader_tag_len;
+extern u8 omap_bootloader_tag[];
+
+struct omap_board_config_kernel *omap_board_config;
+int omap_board_config_size = 0;
+
+static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
+{
+	struct omap_board_config_kernel *kinfo = NULL;
+	int i;
+
+#ifdef CONFIG_OMAP_BOOT_TAG
+	struct omap_board_config_entry *info = NULL;
+
+	if (omap_bootloader_tag_len > 4)
+		info = (struct omap_board_config_entry *) omap_bootloader_tag;
+	while (info != NULL) {
+		u8 *next;
+
+		if (info->tag == tag) {
+			if (skip == 0)
+				break;
+			skip--;
+		}
+
+		if ((info->len & 0x03) != 0) {
+			/* We bail out to avoid an alignment fault */
+			printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
+			       info->len, info->tag);
+			return NULL;
+		}
+		next = (u8 *) info + sizeof(*info) + info->len;
+		if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
+			info = NULL;
+		else
+			info = (struct omap_board_config_entry *) next;
+	}
+	if (info != NULL) {
+		/* Check the length as a lame attempt to check for
+		 * binary inconsistancy. */
+		if (len != NO_LENGTH_CHECK) {
+			/* Word-align len */
+			if (len & 0x03)
+				len = (len + 3) & ~0x03;
+			if (info->len != len) {
+				printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
+				       tag, len, info->len);
+				return NULL;
+			}
+		}
+		if (len_out != NULL)
+			*len_out = info->len;
+		return info->data;
+	}
+#endif
+	/* Try to find the config from the board-specific structures
+	 * in the kernel. */
+	for (i = 0; i < omap_board_config_size; i++) {
+		if (omap_board_config[i].tag == tag) {
+			kinfo = &omap_board_config[i];
+			break;
+		}
+	}
+	if (kinfo == NULL)
+		return NULL;
+	return kinfo->data;
+}
+
+const void *__omap_get_config(u16 tag, size_t len, int nr)
+{
+        return get_config(tag, len, nr, NULL);
+}
+EXPORT_SYMBOL(__omap_get_config);
+
+const void *omap_get_var_config(u16 tag, size_t *len)
+{
+        return get_config(tag, NO_LENGTH_CHECK, 0, len);
+}
+EXPORT_SYMBOL(omap_get_var_config);
+
+static int __init omap_add_serial_console(void)
+{
+	const struct omap_serial_console_config *info;
+
+	info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+			       struct omap_serial_console_config);
+	if (info != NULL && info->console_uart) {
+		static char speed[11], *opt = NULL;
+
+		if (info->console_speed) {
+			snprintf(speed, sizeof(speed), "%u", info->console_speed);
+			opt = speed;
+		}
+		return add_preferred_console("ttyS", info->console_uart - 1, opt);
+	}
+	return 0;
+}
+console_initcall(omap_add_serial_console);
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
new file mode 100644
index 0000000..409aac2
--- /dev/null
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -0,0 +1,128 @@
+/*
+ *  linux/arch/arm/plat-omap/cpu-omap.c
+ *
+ *  CPU frequency scaling for OMAP
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Tony Lindgren <tony@atomide.com>
+ *
+ *  Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/hardware/clock.h>
+
+/* TODO: Add support for SDRAM timing changes */
+
+int omap_verify_speed(struct cpufreq_policy *policy)
+{
+	struct clk * mpu_clk;
+
+	if (policy->cpu)
+		return -EINVAL;
+
+	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+				     policy->cpuinfo.max_freq);
+	mpu_clk = clk_get(NULL, "mpu");
+	if (IS_ERR(mpu_clk))
+		return PTR_ERR(mpu_clk);
+	policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
+	policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
+	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+				     policy->cpuinfo.max_freq);
+	clk_put(mpu_clk);
+
+	return 0;
+}
+
+unsigned int omap_getspeed(unsigned int cpu)
+{
+	struct clk * mpu_clk;
+	unsigned long rate;
+
+	if (cpu)
+		return 0;
+
+	mpu_clk = clk_get(NULL, "mpu");
+	if (IS_ERR(mpu_clk))
+		return 0;
+	rate = clk_get_rate(mpu_clk) / 1000;
+	clk_put(mpu_clk);
+
+	return rate;
+}
+
+static int omap_target(struct cpufreq_policy *policy,
+		       unsigned int target_freq,
+		       unsigned int relation)
+{
+	struct clk * mpu_clk;
+	struct cpufreq_freqs freqs;
+	int ret = 0;
+
+	mpu_clk = clk_get(NULL, "mpu");
+	if (IS_ERR(mpu_clk))
+		return PTR_ERR(mpu_clk);
+
+	freqs.old = omap_getspeed(0);
+	freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
+	freqs.cpu = 0;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	ret = clk_set_rate(mpu_clk, target_freq * 1000);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	clk_put(mpu_clk);
+
+	return ret;
+}
+
+static int __init omap_cpu_init(struct cpufreq_policy *policy)
+{
+	struct clk * mpu_clk;
+
+	mpu_clk = clk_get(NULL, "mpu");
+	if (IS_ERR(mpu_clk))
+		return PTR_ERR(mpu_clk);
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+	policy->cur = policy->min = policy->max = omap_getspeed(0);
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
+	policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, 216000000) / 1000;
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	clk_put(mpu_clk);
+
+	return 0;
+}
+
+static struct cpufreq_driver omap_driver = {
+	.flags		= CPUFREQ_STICKY,
+	.verify		= omap_verify_speed,
+	.target		= omap_target,
+	.get		= omap_getspeed,
+	.init		= omap_cpu_init,
+	.name		= "omap",
+};
+
+static int __init omap_cpufreq_init(void)
+{
+	return cpufreq_register_driver(&omap_driver);
+}
+
+arch_initcall(omap_cpufreq_init);
diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/plat-omap/dma.c
similarity index 97%
rename from arch/arm/mach-omap/dma.c
rename to arch/arm/plat-omap/dma.c
index 7a9ebe8..c0a5c2f 100644
--- a/arch/arm/mach-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/omap/dma.c
+ * linux/arch/arm/plat-omap/dma.c
  *
  * Copyright (C) 2003 Nokia Corporation
  * Author: Juha Yrjölä <juha.yrjola@nokia.com>
@@ -794,10 +794,6 @@
 	w = omap_readw(OMAP1610_DMA_LCD_CTRL);
 	/* Always set the source port as SDRAM for now*/
 	w &= ~(0x03 << 6);
-	if (lcd_dma.ext_ctrl)
-		w |= 1 << 8;
-	else
-		w &= ~(1 << 8);
 	if (lcd_dma.callback != NULL)
 		w |= 1 << 1;            /* Block interrupt enable */
 	else
@@ -889,9 +885,15 @@
 	 */
 	if (enable_1510_mode || !lcd_dma.ext_ctrl)
 		return;
+
+	w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+	w |= 1 << 8;
+	omap_writew(w, OMAP1610_DMA_LCD_CTRL);
+
 	w = omap_readw(OMAP1610_DMA_LCD_CCR);
 	w |= 1 << 7;
 	omap_writew(w, OMAP1610_DMA_LCD_CCR);
+
 	lcd_dma.active = 1;
 }
 
@@ -922,10 +924,19 @@
 
 void omap_stop_lcd_dma(void)
 {
+	u16 w;
+
 	lcd_dma.active = 0;
-	if (!enable_1510_mode && lcd_dma.ext_ctrl)
-		omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~(1 << 7),
-			    OMAP1610_DMA_LCD_CCR);
+	if (enable_1510_mode || !lcd_dma.ext_ctrl)
+		return;
+
+	w = omap_readw(OMAP1610_DMA_LCD_CCR);
+	w &= ~(1 << 7);
+	omap_writew(w, OMAP1610_DMA_LCD_CCR);
+
+	w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+	w &= ~(1 << 8);
+	omap_writew(w, OMAP1610_DMA_LCD_CTRL);
 }
 
 /*
@@ -972,6 +983,25 @@
 			     (OMAP_DMA_CDSA_U(lch) << 16));
 }
 
+int omap_dma_running(void)
+{
+	int lch;
+
+	/* Check if LCD DMA is running */
+	if (cpu_is_omap16xx())
+		if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
+			return 1;
+
+	for (lch = 0; lch < dma_chan_count; lch++) {
+		u16 w;
+
+		w = omap_readw(OMAP_DMA_CCR(lch));
+		if (w & OMAP_DMA_CCR_EN)
+			return 1;
+	}
+	return 0;
+}
+
 static int __init omap_init_dma(void)
 {
 	int ch, r;
diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/plat-omap/gpio.c
similarity index 99%
rename from arch/arm/mach-omap/gpio.c
rename to arch/arm/plat-omap/gpio.c
index 9045dfd..1c85b4e 100644
--- a/arch/arm/mach-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/mach-omap/gpio.c
+ *  linux/arch/arm/plat-omap/gpio.c
  *
  * Support functions for OMAP GPIO
  *
diff --git a/arch/arm/mach-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
similarity index 87%
rename from arch/arm/mach-omap/mcbsp.c
rename to arch/arm/plat-omap/mcbsp.c
index 7c4ad77..43567d5 100644
--- a/arch/arm/mach-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/omap/mcbsp.c
+ * linux/arch/arm/plat-omap/mcbsp.c
  *
  * Copyright (C) 2004 Nokia Corporation
  * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
@@ -66,6 +66,7 @@
 static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
 static struct clk *mcbsp_dsp_ck = 0;
 static struct clk *mcbsp_api_ck = 0;
+static struct clk *mcbsp_dspxor_ck = 0;
 
 
 static void omap_mcbsp_dump_reg(u8 id)
@@ -175,7 +176,7 @@
 		return 0;
 	}
 
-	if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+	if (cpu_is_omap1510() || cpu_is_omap16xx()) {
 		if (id > OMAP_MAX_MCBSP_COUNT) {
 			printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
 			return -1;
@@ -191,15 +192,12 @@
 
 static void omap_mcbsp_dsp_request(void)
 {
-	if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
-		omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)),
-			    ARM_RSTCT1);
-		clk_enable(mcbsp_dsp_ck);
-		clk_enable(mcbsp_api_ck);
+	if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+		clk_use(mcbsp_dsp_ck);
+		clk_use(mcbsp_api_ck);
 
 		/* enable 12MHz clock to mcbsp 1 & 3 */
-		__raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
-			     DSP_IDLECT2);
+		clk_use(mcbsp_dspxor_ck);
 		__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
 			     DSP_RSTCT2);
 	}
@@ -207,10 +205,13 @@
 
 static void omap_mcbsp_dsp_free(void)
 {
-	/* Useless for now */
+	if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+		clk_unuse(mcbsp_dspxor_ck);
+		clk_unuse(mcbsp_dsp_ck);
+		clk_unuse(mcbsp_api_ck);
+	}
 }
 
-
 int omap_mcbsp_request(unsigned int id)
 {
 	int err;
@@ -350,6 +351,73 @@
 }
 
 
+/* polled mcbsp i/o operations */
+int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
+{
+	u32 base = mcbsp[id].io_base;
+	writew(buf, base + OMAP_MCBSP_REG_DXR1);
+	/* if frame sync error - clear the error */
+	if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) {
+		/* clear error */
+		writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR),
+		       base + OMAP_MCBSP_REG_SPCR2);
+		/* resend */
+		return -1;
+	} else {
+		/* wait for transmit confirmation */
+		int attemps = 0;
+		while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) {
+			if (attemps++ > 1000) {
+				writew(readw(base + OMAP_MCBSP_REG_SPCR2) &
+				       (~XRST),
+				       base + OMAP_MCBSP_REG_SPCR2);
+				udelay(10);
+				writew(readw(base + OMAP_MCBSP_REG_SPCR2) |
+				       (XRST),
+				       base + OMAP_MCBSP_REG_SPCR2);
+				udelay(10);
+				printk(KERN_ERR
+				       " Could not write to McBSP Register\n");
+				return -2;
+			}
+		}
+	}
+	return 0;
+}
+
+int omap_mcbsp_pollread(unsigned int id, u16 * buf)
+{
+	u32 base = mcbsp[id].io_base;
+	/* if frame sync error - clear the error */
+	if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) {
+		/* clear error */
+		writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR),
+		       base + OMAP_MCBSP_REG_SPCR1);
+		/* resend */
+		return -1;
+	} else {
+		/* wait for recieve confirmation */
+		int attemps = 0;
+		while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) {
+			if (attemps++ > 1000) {
+				writew(readw(base + OMAP_MCBSP_REG_SPCR1) &
+				       (~RRST),
+				       base + OMAP_MCBSP_REG_SPCR1);
+				udelay(10);
+				writew(readw(base + OMAP_MCBSP_REG_SPCR1) |
+				       (RRST),
+				       base + OMAP_MCBSP_REG_SPCR1);
+				udelay(10);
+				printk(KERN_ERR
+				       " Could not read from McBSP Register\n");
+				return -2;
+			}
+		}
+	}
+	*buf = readw(base + OMAP_MCBSP_REG_DRR1);
+	return 0;
+}
+
 /*
  * IRQ based word transmission.
  */
@@ -625,10 +693,15 @@
 		return PTR_ERR(mcbsp_dsp_ck);
 	}
 	mcbsp_api_ck = clk_get(0, "api_ck");
-	if (IS_ERR(mcbsp_dsp_ck)) {
+	if (IS_ERR(mcbsp_api_ck)) {
 		printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");
 		return PTR_ERR(mcbsp_api_ck);
 	}
+	mcbsp_dspxor_ck = clk_get(0, "dspxor_ck");
+	if (IS_ERR(mcbsp_dspxor_ck)) {
+		printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n");
+		return PTR_ERR(mcbsp_dspxor_ck);
+	}
 
 #ifdef CONFIG_ARCH_OMAP730
 	if (cpu_is_omap730()) {
@@ -643,7 +716,7 @@
 	}
 #endif
 #if defined(CONFIG_ARCH_OMAP16XX)
-	if (cpu_is_omap1610() || cpu_is_omap1710()) {
+	if (cpu_is_omap16xx()) {
 		mcbsp_info = mcbsp_1610;
 		mcbsp_count = ARRAY_SIZE(mcbsp_1610);
 	}
diff --git a/arch/arm/mach-omap/mux.c b/arch/arm/plat-omap/mux.c
similarity index 90%
rename from arch/arm/mach-omap/mux.c
rename to arch/arm/plat-omap/mux.c
index bcf3c6e..ea7b955 100644
--- a/arch/arm/mach-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/mux.c
+ * linux/arch/arm/plat-omap/mux.c
  *
  * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h
  *
@@ -53,19 +53,13 @@
 		return -EINVAL;
 	}
 
-	cfg = &reg_cfg_table[reg_cfg];
-
-	/*
-	 * We do a pretty long section here with lock on, but pin muxing
-	 * should only happen on driver init for each driver, so it's not time
-	 * critical.
-	 */
-	spin_lock_irqsave(&mux_spin_lock, flags);
+	cfg = (reg_cfg_set *)&reg_cfg_table[reg_cfg];
 
 	/* Check the mux register in question */
 	if (cfg->mux_reg) {
 		unsigned	tmp1, tmp2;
 
+		spin_lock_irqsave(&mux_spin_lock, flags);
 		reg_orig = omap_readl(cfg->mux_reg);
 
 		/* The mux registers always seem to be 3 bits long */
@@ -80,11 +74,13 @@
 			warn = 1;
 
 		omap_writel(reg, cfg->mux_reg);
+		spin_unlock_irqrestore(&mux_spin_lock, flags);
 	}
 
 	/* Check for pull up or pull down selection on 1610 */
 	if (!cpu_is_omap1510()) {
 		if (cfg->pu_pd_reg && cfg->pull_val) {
+			spin_lock_irqsave(&mux_spin_lock, flags);
 			pu_pd_orig = omap_readl(cfg->pu_pd_reg);
 			mask = 1 << cfg->pull_bit;
 
@@ -100,11 +96,13 @@
 				pu_pd = pu_pd_orig & ~mask;
 			}
 			omap_writel(pu_pd, cfg->pu_pd_reg);
+			spin_unlock_irqrestore(&mux_spin_lock, flags);
 		}
 	}
 
 	/* Check for an associated pull down register */
 	if (cfg->pull_reg) {
+		spin_lock_irqsave(&mux_spin_lock, flags);
 		pull_orig = omap_readl(cfg->pull_reg);
 		mask = 1 << cfg->pull_bit;
 
@@ -121,6 +119,7 @@
 		}
 
 		omap_writel(pull, cfg->pull_reg);
+		spin_unlock_irqrestore(&mux_spin_lock, flags);
 	}
 
 	if (warn) {
@@ -149,8 +148,6 @@
 	}
 #endif
 
-	spin_unlock_irqrestore(&mux_spin_lock, flags);
-
 #ifdef CONFIG_OMAP_MUX_ERRORS
 	return warn ? -ETXTBSY : 0;
 #else
diff --git a/arch/arm/mach-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c
similarity index 98%
rename from arch/arm/mach-omap/ocpi.c
rename to arch/arm/plat-omap/ocpi.c
index c9ced13..1fb16f9 100644
--- a/arch/arm/mach-omap/ocpi.c
+++ b/arch/arm/plat-omap/ocpi.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/ocpi.c
+ * linux/arch/arm/plat-omap/ocpi.c
  *
  * Minimal OCP bus support for omap16xx
  *
diff --git a/arch/arm/mach-omap/pm.c b/arch/arm/plat-omap/pm.c
similarity index 99%
rename from arch/arm/mach-omap/pm.c
rename to arch/arm/plat-omap/pm.c
index 6b03ccd..e6536b1 100644
--- a/arch/arm/mach-omap/pm.c
+++ b/arch/arm/plat-omap/pm.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/pm.c
+ * linux/arch/arm/plat-omap/pm.c
  *
  * OMAP Power Management Routines
  *
diff --git a/arch/arm/mach-omap/sleep.S b/arch/arm/plat-omap/sleep.S
similarity index 99%
rename from arch/arm/mach-omap/sleep.S
rename to arch/arm/plat-omap/sleep.S
index 4d426d1..279490c 100644
--- a/arch/arm/mach-omap/sleep.S
+++ b/arch/arm/plat-omap/sleep.S
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/sleep.S
+ * linux/arch/arm/plat-omap/sleep.S
  *
  * Low-level OMAP1510/1610 sleep/wakeUp support
  *
diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/plat-omap/usb.c
similarity index 99%
rename from arch/arm/mach-omap/usb.c
rename to arch/arm/plat-omap/usb.c
index fd483ff..25bc4a8 100644
--- a/arch/arm/mach-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-omap/usb.c -- platform level USB initialization
+ * arch/arm/plat-omap/usb.c -- platform level USB initialization
  *
  * Copyright (C) 2004 Texas Instruments, Inc.
  *
@@ -326,7 +326,7 @@
 static struct resource ohci_resources[] = {
 	{
 		.start	= OMAP_OHCI_BASE,
-		.end	= OMAP_OHCI_BASE + 4096,
+		.end	= OMAP_OHCI_BASE + 4096 - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
diff --git a/arch/frv/defconfig b/arch/frv/defconfig
new file mode 100644
index 0000000..b6e4ca5
--- /dev/null
+++ b/arch/frv/defconfig
@@ -0,0 +1,627 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11.8
+# Fri May 13 17:16:03 2005
+#
+CONFIG_FRV=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_GENERIC_CALIBRATE_DELAY is not set
+# CONFIG_GENERIC_HARDIRQS is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Fujitsu FR-V system setup
+#
+CONFIG_MMU=y
+CONFIG_FRV_OUTOFLINE_ATOMIC_OPS=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_FRV_DEFL_CACHE_WBACK is not set
+# CONFIG_FRV_DEFL_CACHE_WBEHIND is not set
+CONFIG_FRV_DEFL_CACHE_WTHRU=y
+# CONFIG_FRV_DEFL_CACHE_DISABLED is not set
+
+#
+# CPU core support
+#
+CONFIG_CPU_FR451=y
+CONFIG_CPU_FR451_COMPILE=y
+CONFIG_FRV_L1_CACHE_SHIFT=5
+CONFIG_MB93091_VDK=y
+# CONFIG_MB93093_PDK is not set
+CONFIG_MB93090_MB00=y
+# CONFIG_MB93091_NO_MB is not set
+# CONFIG_GPREL_DATA_8 is not set
+CONFIG_GPREL_DATA_4=y
+# CONFIG_GPREL_DATA_NONE is not set
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Executable formats
+#
+# CONFIG_BINFMT_ELF is not set
+CONFIG_BINFMT_ELF_FDPIC=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_FORK_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_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 is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_KGDBOE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE 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_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISER4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE 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_KCORE is not set
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_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_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=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_GDBSTUB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 2203a9d..4553ffd 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -435,6 +435,11 @@
 	if (c == &boot_cpu_data)
 		sysenter_setup();
 	enable_sep_cpu();
+
+	if (c == &boot_cpu_data)
+		mtrr_bp_init();
+	else
+		mtrr_ap_init();
 }
 
 #ifdef CONFIG_X86_HT
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 96a75d0..a2c33c1 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -25,7 +25,7 @@
 /*
  * Alignment at which movsl is preferred for bulk memory copies.
  */
-struct movsl_mask movsl_mask;
+struct movsl_mask movsl_mask __read_mostly;
 #endif
 
 void __devinit early_intel_workaround(struct cpuinfo_x86 *c)
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index 64d91f7..169ac8e 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -67,13 +67,6 @@
 	mtrr_state.enabled = (lo & 0xc00) >> 10;
 }
 
-/*  Free resources associated with a struct mtrr_state  */
-void __init finalize_mtrr_state(void)
-{
-	kfree(mtrr_state.var_ranges);
-	mtrr_state.var_ranges = NULL;
-}
-
 /*  Some BIOS's are fucked and don't set all MTRRs the same!  */
 void __init mtrr_state_warn(void)
 {
@@ -334,6 +327,9 @@
 */
 {
 	unsigned long flags;
+	struct mtrr_var_range *vr;
+
+	vr = &mtrr_state.var_ranges[reg];
 
 	local_irq_save(flags);
 	prepare_set();
@@ -342,11 +338,15 @@
 		/* The invalid bit is kept in the mask, so we simply clear the
 		   relevant mask register to disable a range. */
 		mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
+		memset(vr, 0, sizeof(struct mtrr_var_range));
 	} else {
-		mtrr_wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
-		      (base & size_and_mask) >> (32 - PAGE_SHIFT));
-		mtrr_wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
-		      (-size & size_and_mask) >> (32 - PAGE_SHIFT));
+		vr->base_lo = base << PAGE_SHIFT | type;
+		vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT);
+		vr->mask_lo = -size << PAGE_SHIFT | 0x800;
+		vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT);
+
+		mtrr_wrmsr(MTRRphysBase_MSR(reg), vr->base_lo, vr->base_hi);
+		mtrr_wrmsr(MTRRphysMask_MSR(reg), vr->mask_lo, vr->mask_hi);
 	}
 
 	post_set();
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index d66b09e..764cac6 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -332,6 +332,8 @@
 
 	error = -EINVAL;
 
+	/* No CPU hotplug when we change MTRR entries */
+	lock_cpu_hotplug();
 	/*  Search for existing MTRR  */
 	down(&main_lock);
 	for (i = 0; i < num_var_ranges; ++i) {
@@ -372,6 +374,7 @@
 	error = i;
  out:
 	up(&main_lock);
+	unlock_cpu_hotplug();
 	return error;
 }
 
@@ -461,6 +464,8 @@
 		return -ENXIO;
 
 	max = num_var_ranges;
+	/* No CPU hotplug when we change MTRR entries */
+	lock_cpu_hotplug();
 	down(&main_lock);
 	if (reg < 0) {
 		/*  Search for existing MTRR  */
@@ -501,6 +506,7 @@
 	error = reg;
  out:
 	up(&main_lock);
+	unlock_cpu_hotplug();
 	return error;
 }
 /**
@@ -544,21 +550,9 @@
 	centaur_init_mtrr();
 }
 
-static void __init init_other_cpus(void)
-{
-	if (use_intel())
-		get_mtrr_state();
-
-	/* bring up the other processors */
-	set_mtrr(~0U,0,0,0);
-
-	if (use_intel()) {
-		finalize_mtrr_state();
-		mtrr_state_warn();
-	}
-}
-
-
+/* The suspend/resume methods are only for CPU without MTRR. CPU using generic
+ * MTRR driver doesn't require this
+ */
 struct mtrr_value {
 	mtrr_type	ltype;
 	unsigned long	lbase;
@@ -611,13 +605,13 @@
 
 
 /**
- * mtrr_init - initialize mtrrs on the boot CPU
+ * mtrr_bp_init - initialize mtrrs on the boot CPU
  *
  * This needs to be called early; before any of the other CPUs are 
  * initialized (i.e. before smp_init()).
  * 
  */
-static int __init mtrr_init(void)
+void __init mtrr_bp_init(void)
 {
 	init_ifs();
 
@@ -674,12 +668,48 @@
 	if (mtrr_if) {
 		set_num_var_ranges();
 		init_table();
-		init_other_cpus();
-
-		return sysdev_driver_register(&cpu_sysdev_class,
-					      &mtrr_sysdev_driver);
+		if (use_intel())
+			get_mtrr_state();
 	}
-	return -ENXIO;
 }
 
-subsys_initcall(mtrr_init);
+void mtrr_ap_init(void)
+{
+	unsigned long flags;
+
+	if (!mtrr_if || !use_intel())
+		return;
+	/*
+	 * Ideally we should hold main_lock here to avoid mtrr entries changed,
+	 * but this routine will be called in cpu boot time, holding the lock
+	 * breaks it. This routine is called in two cases: 1.very earily time
+	 * of software resume, when there absolutely isn't mtrr entry changes;
+	 * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
+	 * prevent mtrr entry changes
+	 */
+	local_irq_save(flags);
+
+	mtrr_if->set_all();
+
+	local_irq_restore(flags);
+}
+
+static int __init mtrr_init_finialize(void)
+{
+	if (!mtrr_if)
+		return 0;
+	if (use_intel())
+		mtrr_state_warn();
+	else {
+		/* The CPUs haven't MTRR and seemes not support SMP. They have
+		 * specific drivers, we use a tricky method to support
+		 * suspend/resume for them.
+		 * TBD: is there any system with such CPU which supports
+		 * suspend/resume?  if no, we should remove the code.
+		 */
+		sysdev_driver_register(&cpu_sysdev_class,
+			&mtrr_sysdev_driver);
+	}
+	return 0;
+}
+subsys_initcall(mtrr_init_finialize);
diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
index de13512..99c9f26 100644
--- a/arch/i386/kernel/cpu/mtrr/mtrr.h
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h
@@ -91,7 +91,6 @@
 
 extern unsigned int num_var_ranges;
 
-void finalize_mtrr_state(void);
 void mtrr_state_warn(void);
 char *mtrr_attrib_to_str(int x);
 void mtrr_wrmsr(unsigned, unsigned, unsigned);
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index d66bf48..8ac8e9f 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -68,21 +68,21 @@
 #endif
 
 /* Package ID of each logical CPU */
-int phys_proc_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID};
+int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
 EXPORT_SYMBOL(phys_proc_id);
 
 /* Core ID of each logical CPU */
-int cpu_core_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID};
+int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
 EXPORT_SYMBOL(cpu_core_id);
 
-cpumask_t cpu_sibling_map[NR_CPUS];
+cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_sibling_map);
 
-cpumask_t cpu_core_map[NR_CPUS];
+cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_core_map);
 
 /* bitmap of online cpus */
-cpumask_t cpu_online_map;
+cpumask_t cpu_online_map __read_mostly;
 EXPORT_SYMBOL(cpu_online_map);
 
 cpumask_t cpu_callin_map;
@@ -100,7 +100,7 @@
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
 EXPORT_SYMBOL(cpu_data);
 
-u8 x86_cpu_to_apicid[NR_CPUS] =
+u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly =
 			{ [0 ... NR_CPUS-1] = 0xff };
 EXPORT_SYMBOL(x86_cpu_to_apicid);
 
@@ -550,10 +550,10 @@
 #ifdef CONFIG_NUMA
 
 /* which logical CPUs are on which nodes */
-cpumask_t node_2_cpu_mask[MAX_NUMNODES] =
+cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly =
 				{ [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
 /* which node each logical CPU is on */
-int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 };
+int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
 EXPORT_SYMBOL(cpu_2_node);
 
 /* set up a mapping between cpu and node. */
@@ -581,7 +581,7 @@
 
 #endif /* CONFIG_NUMA */
 
-u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
 
 static void map_cpu_to_logical_apicid(void)
 {
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 2854c35..0ee9dee 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -91,7 +91,7 @@
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
 
-struct timer_opts *cur_timer = &timer_none;
+struct timer_opts *cur_timer __read_mostly = &timer_none;
 
 /*
  * This is a special lock that is owned by the CPU and holds the index
diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
index d766e09..ef8dac5 100644
--- a/arch/i386/kernel/timers/timer_hpet.c
+++ b/arch/i386/kernel/timers/timer_hpet.c
@@ -18,7 +18,7 @@
 #include "mach_timer.h"
 #include <asm/hpet.h>
 
-static unsigned long hpet_usec_quotient;	/* convert hpet clks to usec */
+static unsigned long __read_mostly hpet_usec_quotient;	/* convert hpet clks to usec */
 static unsigned long tsc_hpet_quotient;		/* convert tsc to hpet clks */
 static unsigned long hpet_last; 	/* hpet counter value at last tick*/
 static unsigned long last_tsc_low;	/* lsb 32 bits of Time Stamp Counter */
@@ -180,7 +180,7 @@
 /************************************************************/
 
 /* tsc timer_opts struct */
-static struct timer_opts timer_hpet = {
+static struct timer_opts timer_hpet __read_mostly = {
 	.name = 		"hpet",
 	.mark_offset =		mark_offset_hpet,
 	.get_offset =		get_offset_hpet,
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 7e01a52..761972f 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -57,6 +57,9 @@
 	*(.data.cacheline_aligned)
   }
 
+  /* rarely changed data like cpu maps */
+  . = ALIGN(32);
+  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) }
   _edata = .;			/* End of data section */
 
   . = ALIGN(THREAD_SIZE);	/* init_task */
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
index 6b25afc..f379b8d 100644
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -228,7 +228,8 @@
 void iounmap(volatile void __iomem *addr)
 {
 	struct vm_struct *p;
-	if ((void __force *) addr <= high_memory) 
+
+	if ((void __force *)addr <= high_memory)
 		return;
 
 	/*
@@ -241,9 +242,10 @@
 		return;
 
 	write_lock(&vmlist_lock);
-	p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
+	p = __remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr));
 	if (!p) { 
 		printk(KERN_WARNING "iounmap: bad address %p\n", addr);
+		dump_stack();
 		goto out_unlock;
 	}
 
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
index 0e6b45b..c547c1a 100644
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -137,6 +137,7 @@
 
 	fix_processor_context();
 	do_fpu_end();
+	mtrr_ap_init();
 }
 
 void restore_processor_state(void)
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index b2e2f65..e1fb68d 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_IOSAPIC)		+= iosapic.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_SMP)		+= smp.o smpboot.o domain.o
+obj-$(CONFIG_NUMA)		+= numa.o
 obj-$(CONFIG_PERFMON)		+= perfmon_default_smpl.o
 obj-$(CONFIG_IA64_CYCLONE)	+= cyclone.o
 obj-$(CONFIG_IA64_MCA_RECOVERY)	+= mca_recovery.o
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index cda06f8..542256e 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -640,9 +640,11 @@
 			if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id())
 				node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu];
 	}
-	build_cpu_to_node_map();
 # endif
 #endif
+#ifdef CONFIG_ACPI_NUMA
+	build_cpu_to_node_map();
+#endif
 	/* Make boot-up look pretty */
 	printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
 	return 0;
diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c
new file mode 100644
index 0000000..a68ce66
--- /dev/null
+++ b/arch/ia64/kernel/numa.c
@@ -0,0 +1,57 @@
+/*
+ * 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
+ *
+ * ia64 kernel NUMA specific stuff
+ *
+ * Copyright (C) 2002 Erich Focht <efocht@ess.nec.de>
+ * Copyright (C) 2004 Silicon Graphics, Inc.
+ *   Jesse Barnes <jbarnes@sgi.com>
+ */
+#include <linux/config.h>
+#include <linux/topology.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+#include <asm/smp.h>
+
+u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_to_node_map);
+
+cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
+
+/**
+ * build_cpu_to_node_map - setup cpu to node and node to cpumask arrays
+ *
+ * Build cpu to node mapping and initialize the per node cpu masks using
+ * info from the node_cpuid array handed to us by ACPI.
+ */
+void __init build_cpu_to_node_map(void)
+{
+	int cpu, i, node;
+
+	for(node=0; node < MAX_NUMNODES; node++)
+		cpus_clear(node_to_cpu_mask[node]);
+
+	for(cpu = 0; cpu < NR_CPUS; ++cpu) {
+		node = -1;
+		for (i = 0; i < NR_CPUS; ++i)
+			if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) {
+				node = node_cpuid[i].nid;
+				break;
+			}
+		cpu_to_node_map[cpu] = (node >= 0) ? node : 0;
+		if (node >= 0)
+			cpu_set(cpu, node_to_cpu_mask[node]);
+	}
+}
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index edd9f07..b8a0a7d 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -143,6 +143,7 @@
 
 		__copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16);
 		psr->mfh = 0;	/* drop signal handler's fph contents... */
+		preempt_disable();
 		if (psr->dfh)
 			ia64_drop_fpu(current);
 		else {
@@ -150,6 +151,7 @@
 			__ia64_load_fpu(current->thread.fph);
 			ia64_set_local_fpu_owner(current);
 		}
+		preempt_enable();
 	}
 	return err;
 }
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 623b0a5..7d72c0d 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -525,47 +525,6 @@
 	}
 }
 
-#ifdef CONFIG_NUMA
-
-/* on which node is each logical CPU (one cacheline even for 64 CPUs) */
-u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned;
-EXPORT_SYMBOL(cpu_to_node_map);
-/* which logical CPUs are on which nodes */
-cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
-
-/*
- * Build cpu to node mapping and initialize the per node cpu masks.
- */
-void __init
-build_cpu_to_node_map (void)
-{
-	int cpu, i, node;
-
-	for(node=0; node<MAX_NUMNODES; node++)
-		cpus_clear(node_to_cpu_mask[node]);
-	for(cpu = 0; cpu < NR_CPUS; ++cpu) {
-		/*
-		 * All Itanium NUMA platforms I know use ACPI, so maybe we
-		 * can drop this ifdef completely.                    [EF]
-		 */
-#ifdef CONFIG_ACPI_NUMA
-		node = -1;
-		for (i = 0; i < NR_CPUS; ++i)
-			if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) {
-				node = node_cpuid[i].nid;
-				break;
-			}
-#else
-#		error Fixme: Dunno how to build CPU-to-node map.
-#endif
-		cpu_to_node_map[cpu] = (node >= 0) ? node : 0;
-		if (node >= 0)
-			cpu_set(cpu, node_to_cpu_mask[node]);
-	}
-}
-
-#endif /* CONFIG_NUMA */
-
 /*
  * Cycle through the APs sending Wakeup IPIs to boot each.
  */
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index e7e520d..4440c83 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -90,14 +90,16 @@
 		.lock_owner_depth =	0
 	};
 	static int die_counter;
+	int cpu = get_cpu();
 
-	if (die.lock_owner != smp_processor_id()) {
+	if (die.lock_owner != cpu) {
 		console_verbose();
 		spin_lock_irq(&die.lock);
-		die.lock_owner = smp_processor_id();
+		die.lock_owner = cpu;
 		die.lock_owner_depth = 0;
 		bust_spinlocks(1);
 	}
+	put_cpu();
 
 	if (++die.lock_owner_depth < 3) {
 		printk("%s[%d]: %s %ld [%d]\n",
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index f3fd528..b5c90e5 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -44,150 +44,7 @@
 };
 
 static struct early_node_data mem_data[MAX_NUMNODES] __initdata;
-
-/**
- * reassign_cpu_only_nodes - called from find_memory to move CPU-only nodes to a memory node
- *
- * This function will move nodes with only CPUs (no memory)
- * to a node with memory which is at the minimum numa_slit distance.
- * Any reassigments will result in the compression of the nodes
- * and renumbering the nid values where appropriate.
- * The static declarations below are to avoid large stack size which
- * makes the code not re-entrant.
- */
-static void __init reassign_cpu_only_nodes(void)
-{
-	struct node_memblk_s *p;
-	int i, j, k, nnode, nid, cpu, cpunid, pxm;
-	u8 cslit, slit;
-	static DECLARE_BITMAP(nodes_with_mem, MAX_NUMNODES) __initdata;
-	static u8 numa_slit_fix[MAX_NUMNODES * MAX_NUMNODES] __initdata;
-	static int node_flip[MAX_NUMNODES] __initdata;
-	static int old_nid_map[NR_CPUS] __initdata;
-
-	for (nnode = 0, p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++)
-		if (!test_bit(p->nid, (void *) nodes_with_mem)) {
-			set_bit(p->nid, (void *) nodes_with_mem);
-			nnode++;
-		}
-
-	/*
-	 * All nids with memory.
-	 */
-	if (nnode == num_online_nodes())
-		return;
-
-	/*
-	 * Change nids and attempt to migrate CPU-only nodes
-	 * to the best numa_slit (closest neighbor) possible.
-	 * For reassigned CPU nodes a nid can't be arrived at
-	 * until after this loop because the target nid's new
-	 * identity might not have been established yet. So
-	 * new nid values are fabricated above num_online_nodes() and
-	 * mapped back later to their true value.
-	 */
-	/* MCD - This code is a bit complicated, but may be unnecessary now.
-	 * We can now handle much more interesting node-numbering.
-	 * The old requirement that 0 <= nid <= numnodes <= MAX_NUMNODES
-	 * and that there be no holes in the numbering 0..numnodes
-	 * has become simply 0 <= nid <= MAX_NUMNODES.
-	 */
-	nid = 0;
-	for_each_online_node(i)  {
-		if (test_bit(i, (void *) nodes_with_mem)) {
-			/*
-			 * Save original nid value for numa_slit
-			 * fixup and node_cpuid reassignments.
-			 */
-			node_flip[nid] = i;
-
-			if (i == nid) {
-				nid++;
-				continue;
-			}
-
-			for (p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++)
-				if (p->nid == i)
-					p->nid = nid;
-
-			cpunid = nid;
-			nid++;
-		} else
-			cpunid = MAX_NUMNODES;
-
-		for (cpu = 0; cpu < NR_CPUS; cpu++)
-			if (node_cpuid[cpu].nid == i) {
-				/*
-				 * For nodes not being reassigned just
-				 * fix the cpu's nid and reverse pxm map
-				 */
-				if (cpunid < MAX_NUMNODES) {
-					pxm = nid_to_pxm_map[i];
-					pxm_to_nid_map[pxm] =
-					          node_cpuid[cpu].nid = cpunid;
-					continue;
-				}
-
-				/*
-				 * For nodes being reassigned, find best node by
-				 * numa_slit information and then make a temporary
-				 * nid value based on current nid and num_online_nodes().
-				 */
-				slit = 0xff;
-				k = 2*num_online_nodes();
-				for_each_online_node(j) {
-					if (i == j)
-						continue;
-					else if (test_bit(j, (void *) nodes_with_mem)) {
-						cslit = numa_slit[i * num_online_nodes() + j];
-						if (cslit < slit) {
-							k = num_online_nodes() + j;
-							slit = cslit;
-						}
-					}
-				}
-
-				/* save old nid map so we can update the pxm */
-				old_nid_map[cpu] = node_cpuid[cpu].nid;
-				node_cpuid[cpu].nid = k;
-			}
-	}
-
-	/*
-	 * Fixup temporary nid values for CPU-only nodes.
-	 */
-	for (cpu = 0; cpu < NR_CPUS; cpu++)
-		if (node_cpuid[cpu].nid == (2*num_online_nodes())) {
-			pxm = nid_to_pxm_map[old_nid_map[cpu]];
-			pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = nnode - 1;
-		} else {
-			for (i = 0; i < nnode; i++) {
-				if (node_flip[i] != (node_cpuid[cpu].nid - num_online_nodes()))
-					continue;
-
-				pxm = nid_to_pxm_map[old_nid_map[cpu]];
-				pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = i;
-				break;
-			}
-		}
-
-	/*
-	 * Fix numa_slit by compressing from larger
-	 * nid array to reduced nid array.
-	 */
-	for (i = 0; i < nnode; i++)
-		for (j = 0; j < nnode; j++)
-			numa_slit_fix[i * nnode + j] =
-				numa_slit[node_flip[i] * num_online_nodes() + node_flip[j]];
-
-	memcpy(numa_slit, numa_slit_fix, sizeof (numa_slit));
-
-	nodes_clear(node_online_map);
-	for (i = 0; i < nnode; i++)
-		node_set_online(i);
-
-	return;
-}
+static nodemask_t memory_less_mask __initdata;
 
 /*
  * To prevent cache aliasing effects, align per-node structures so that they
@@ -233,28 +90,6 @@
 }
 
 /**
- * early_nr_phys_cpus_node - return number of physical cpus on a given node
- * @node: node to check
- *
- * Count the number of physical cpus on @node.  These are cpus that actually
- * exist.  We can't use nr_cpus_node() yet because
- * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
- * called yet.
- */
-static int early_nr_phys_cpus_node(int node)
-{
-	int cpu, n = 0;
-
-	for (cpu = 0; cpu < NR_CPUS; cpu++)
-		if (node == node_cpuid[cpu].nid)
-			if ((cpu == 0) || node_cpuid[cpu].phys_id)
-				n++;
-
-	return n;
-}
-
-
-/**
  * early_nr_cpus_node - return number of cpus on a given node
  * @node: node to check
  *
@@ -262,7 +97,7 @@
  * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
  * called yet.  Note that node 0 will also count all non-existent cpus.
  */
-static int early_nr_cpus_node(int node)
+static int __init early_nr_cpus_node(int node)
 {
 	int cpu, n = 0;
 
@@ -274,6 +109,85 @@
 }
 
 /**
+ * compute_pernodesize - compute size of pernode data
+ * @node: the node id.
+ */
+static unsigned long __init compute_pernodesize(int node)
+{
+	unsigned long pernodesize = 0, cpus;
+
+	cpus = early_nr_cpus_node(node);
+	pernodesize += PERCPU_PAGE_SIZE * cpus;
+	pernodesize += node * L1_CACHE_BYTES;
+	pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));
+	pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+	pernodesize = PAGE_ALIGN(pernodesize);
+	return pernodesize;
+}
+
+/**
+ * per_cpu_node_setup - setup per-cpu areas on each node
+ * @cpu_data: per-cpu area on this node
+ * @node: node to setup
+ *
+ * Copy the static per-cpu data into the region we just set aside and then
+ * setup __per_cpu_offset for each CPU on this node.  Return a pointer to
+ * the end of the area.
+ */
+static void *per_cpu_node_setup(void *cpu_data, int node)
+{
+#ifdef CONFIG_SMP
+	int cpu;
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		if (node == node_cpuid[cpu].nid) {
+			memcpy(__va(cpu_data), __phys_per_cpu_start,
+			       __per_cpu_end - __per_cpu_start);
+			__per_cpu_offset[cpu] = (char*)__va(cpu_data) -
+				__per_cpu_start;
+			cpu_data += PERCPU_PAGE_SIZE;
+		}
+	}
+#endif
+	return cpu_data;
+}
+
+/**
+ * fill_pernode - initialize pernode data.
+ * @node: the node id.
+ * @pernode: physical address of pernode data
+ * @pernodesize: size of the pernode data
+ */
+static void __init fill_pernode(int node, unsigned long pernode,
+	unsigned long pernodesize)
+{
+	void *cpu_data;
+	int cpus = early_nr_cpus_node(node);
+	struct bootmem_data *bdp = &mem_data[node].bootmem_data;
+
+	mem_data[node].pernode_addr = pernode;
+	mem_data[node].pernode_size = pernodesize;
+	memset(__va(pernode), 0, pernodesize);
+
+	cpu_data = (void *)pernode;
+	pernode += PERCPU_PAGE_SIZE * cpus;
+	pernode += node * L1_CACHE_BYTES;
+
+	mem_data[node].pgdat = __va(pernode);
+	pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+	mem_data[node].node_data = __va(pernode);
+	pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+
+	mem_data[node].pgdat->bdata = bdp;
+	pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+	cpu_data = per_cpu_node_setup(cpu_data, node);
+
+	return;
+}
+
+/**
  * find_pernode_space - allocate memory for memory map and per-node structures
  * @start: physical start of range
  * @len: length of range
@@ -304,9 +218,8 @@
 static int __init find_pernode_space(unsigned long start, unsigned long len,
 				     int node)
 {
-	unsigned long epfn, cpu, cpus, phys_cpus;
+	unsigned long epfn;
 	unsigned long pernodesize = 0, pernode, pages, mapsize;
-	void *cpu_data;
 	struct bootmem_data *bdp = &mem_data[node].bootmem_data;
 
 	epfn = (start + len) >> PAGE_SHIFT;
@@ -329,49 +242,12 @@
 	 * Calculate total size needed, incl. what's necessary
 	 * for good alignment and alias prevention.
 	 */
-	cpus = early_nr_cpus_node(node);
-	phys_cpus = early_nr_phys_cpus_node(node);
-	pernodesize += PERCPU_PAGE_SIZE * cpus;
-	pernodesize += node * L1_CACHE_BYTES;
-	pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));
-	pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
-	pernodesize = PAGE_ALIGN(pernodesize);
+	pernodesize = compute_pernodesize(node);
 	pernode = NODEDATA_ALIGN(start, node);
 
 	/* Is this range big enough for what we want to store here? */
-	if (start + len > (pernode + pernodesize + mapsize)) {
-		mem_data[node].pernode_addr = pernode;
-		mem_data[node].pernode_size = pernodesize;
-		memset(__va(pernode), 0, pernodesize);
-
-		cpu_data = (void *)pernode;
-		pernode += PERCPU_PAGE_SIZE * cpus;
-		pernode += node * L1_CACHE_BYTES;
-
-		mem_data[node].pgdat = __va(pernode);
-		pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
-
-		mem_data[node].node_data = __va(pernode);
-		pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
-
-		mem_data[node].pgdat->bdata = bdp;
-		pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
-
-		/*
-		 * Copy the static per-cpu data into the region we
-		 * just set aside and then setup __per_cpu_offset
-		 * for each CPU on this node.
-		 */
-		for (cpu = 0; cpu < NR_CPUS; cpu++) {
-			if (node == node_cpuid[cpu].nid) {
-				memcpy(__va(cpu_data), __phys_per_cpu_start,
-				       __per_cpu_end - __per_cpu_start);
-				__per_cpu_offset[cpu] = (char*)__va(cpu_data) -
-					__per_cpu_start;
-				cpu_data += PERCPU_PAGE_SIZE;
-			}
-		}
-	}
+	if (start + len > (pernode + pernodesize + mapsize))
+		fill_pernode(node, pernode, pernodesize);
 
 	return 0;
 }
@@ -411,6 +287,9 @@
 	for_each_online_node(node) {
 		pg_data_t *pdp = mem_data[node].pgdat;
 
+		if (node_isset(node, memory_less_mask))
+			continue;
+
 		bdp = pdp->bdata;
 
 		/* First the bootmem_map itself */
@@ -436,8 +315,8 @@
  */
 static void __init initialize_pernode_data(void)
 {
-	int cpu, node;
 	pg_data_t *pgdat_list[MAX_NUMNODES];
+	int cpu, node;
 
 	for_each_online_node(node)
 		pgdat_list[node] = mem_data[node].pgdat;
@@ -447,12 +326,99 @@
 		memcpy(mem_data[node].node_data->pg_data_ptrs, pgdat_list,
 		       sizeof(pgdat_list));
 	}
-
+#ifdef CONFIG_SMP
 	/* Set the node_data pointer for each per-cpu struct */
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		node = node_cpuid[cpu].nid;
 		per_cpu(cpu_info, cpu).node_data = mem_data[node].node_data;
 	}
+#else
+	{
+		struct cpuinfo_ia64 *cpu0_cpu_info;
+		cpu = 0;
+		node = node_cpuid[cpu].nid;
+		cpu0_cpu_info = (struct cpuinfo_ia64 *)(__phys_per_cpu_start +
+			((char *)&per_cpu__cpu_info - __per_cpu_start));
+		cpu0_cpu_info->node_data = mem_data[node].node_data;
+	}
+#endif /* CONFIG_SMP */
+}
+
+/**
+ * memory_less_node_alloc - * attempt to allocate memory on the best NUMA slit
+ * 	node but fall back to any other node when __alloc_bootmem_node fails
+ *	for best.
+ * @nid: node id
+ * @pernodesize: size of this node's pernode data
+ * @align: alignment to use for this node's pernode data
+ */
+static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize,
+	unsigned long align)
+{
+	void *ptr = NULL;
+	u8 best = 0xff;
+	int bestnode = -1, node;
+
+	for_each_online_node(node) {
+		if (node_isset(node, memory_less_mask))
+			continue;
+		else if (node_distance(nid, node) < best) {
+			best = node_distance(nid, node);
+			bestnode = node;
+		}
+	}
+
+	ptr = __alloc_bootmem_node(mem_data[bestnode].pgdat,
+		pernodesize, align, __pa(MAX_DMA_ADDRESS));
+
+	if (!ptr)
+		panic("NO memory for memory less node\n");
+	return ptr;
+}
+
+/**
+ * pgdat_insert - insert the pgdat into global pgdat_list
+ * @pgdat: the pgdat for a node.
+ */
+static void __init pgdat_insert(pg_data_t *pgdat)
+{
+	pg_data_t *prev = NULL, *next;
+
+	for_each_pgdat(next)
+		if (pgdat->node_id < next->node_id)
+			break;
+		else
+			prev = next;
+
+	if (prev) {
+		prev->pgdat_next = pgdat;
+		pgdat->pgdat_next = next;
+	} else {
+		pgdat->pgdat_next = pgdat_list;
+		pgdat_list = pgdat;
+	}
+
+	return;
+}
+
+/**
+ * memory_less_nodes - allocate and initialize CPU only nodes pernode
+ *	information.
+ */
+static void __init memory_less_nodes(void)
+{
+	unsigned long pernodesize;
+	void *pernode;
+	int node;
+
+	for_each_node_mask(node, memory_less_mask) {
+		pernodesize = compute_pernodesize(node);
+		pernode = memory_less_node_alloc(node, pernodesize,
+			(node) ? (node * PERCPU_PAGE_SIZE) : (1024*1024));
+		fill_pernode(node, __pa(pernode), pernodesize);
+	}
+
+	return;
 }
 
 /**
@@ -472,16 +438,19 @@
 		node_set_online(0);
 	}
 
+	nodes_or(memory_less_mask, memory_less_mask, node_online_map);
 	min_low_pfn = -1;
 	max_low_pfn = 0;
 
-	if (num_online_nodes() > 1)
-		reassign_cpu_only_nodes();
-
 	/* These actually end up getting called by call_pernode_memory() */
 	efi_memmap_walk(filter_rsvd_memory, build_node_maps);
 	efi_memmap_walk(filter_rsvd_memory, find_pernode_space);
 
+	for_each_online_node(node)
+		if (mem_data[node].bootmem_data.node_low_pfn) {
+			node_clear(node, memory_less_mask);
+			mem_data[node].min_pfn = ~0UL;
+		}
 	/*
 	 * Initialize the boot memory maps in reverse order since that's
 	 * what the bootmem allocator expects
@@ -492,17 +461,14 @@
 
 		if (!node_online(node))
 			continue;
+		else if (node_isset(node, memory_less_mask))
+			continue;
 
 		bdp = &mem_data[node].bootmem_data;
 		pernode = mem_data[node].pernode_addr;
 		pernodesize = mem_data[node].pernode_size;
 		map = pernode + pernodesize;
 
-		/* Sanity check... */
-		if (!pernode)
-			panic("pernode space for node %d "
-			      "could not be allocated!", node);
-
 		init_bootmem_node(mem_data[node].pgdat,
 				  map>>PAGE_SHIFT,
 				  bdp->node_boot_start>>PAGE_SHIFT,
@@ -512,6 +478,7 @@
 	efi_memmap_walk(filter_rsvd_memory, free_node_bootmem);
 
 	reserve_pernode_space();
+	memory_less_nodes();
 	initialize_pernode_data();
 
 	max_pfn = max_low_pfn;
@@ -519,6 +486,7 @@
 	find_initrd();
 }
 
+#ifdef CONFIG_SMP
 /**
  * per_cpu_init - setup per-cpu variables
  *
@@ -529,15 +497,15 @@
 {
 	int cpu;
 
-	if (smp_processor_id() == 0) {
-		for (cpu = 0; cpu < NR_CPUS; cpu++) {
-			per_cpu(local_per_cpu_offset, cpu) =
-				__per_cpu_offset[cpu];
-		}
-	}
+	if (smp_processor_id() != 0)
+		return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
 
 	return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
 }
+#endif /* CONFIG_SMP */
 
 /**
  * show_mem - give short summary of memory stats
@@ -680,12 +648,13 @@
 
 	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-	/* so min() will work in count_node_pages */
-	for_each_online_node(node)
-		mem_data[node].min_pfn = ~0UL;
-
 	efi_memmap_walk(filter_rsvd_memory, count_node_pages);
 
+	vmalloc_end -= PAGE_ALIGN(max_low_pfn * sizeof(struct page));
+	vmem_map = (struct page *) vmalloc_end;
+	efi_memmap_walk(create_mem_map_page_table, NULL);
+	printk("Virtual mem_map starts at 0x%p\n", vmem_map);
+
 	for_each_online_node(node) {
 		memset(zones_size, 0, sizeof(zones_size));
 		memset(zholes_size, 0, sizeof(zholes_size));
@@ -719,15 +688,6 @@
 				 mem_data[node].num_dma_physpages);
 		}
 
-		if (node == 0) {
-			vmalloc_end -=
-				PAGE_ALIGN(max_low_pfn * sizeof(struct page));
-			vmem_map = (struct page *) vmalloc_end;
-
-			efi_memmap_walk(create_mem_map_page_table, NULL);
-			printk("Virtual mem_map starts at 0x%p\n", vmem_map);
-		}
-
 		pfn_offset = mem_data[node].min_pfn;
 
 		NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset;
@@ -735,5 +695,11 @@
 				    pfn_offset, zholes_size);
 	}
 
+	/*
+	 * Make memory less nodes become a member of the known nodes.
+	 */
+	for_each_node_mask(node, memory_less_mask)
+		pgdat_insert(mem_data[node].pgdat);
+
 	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 }
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 4eb2f52..65f9958 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -597,7 +597,8 @@
 	kclist_add(&kcore_kernel, _stext, _end - _stext);
 
 	for_each_pgdat(pgdat)
-		totalram_pages += free_all_bootmem_node(pgdat);
+		if (pgdat->bdata->node_bootmem_map)
+			totalram_pages += free_all_bootmem_node(pgdat);
 
 	reserved_pages = 0;
 	efi_memmap_walk(count_reserved_pages, &reserved_pages);
diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h
index 868e7ec..580a1c0 100644
--- a/arch/ia64/sn/include/xtalk/hubdev.h
+++ b/arch/ia64/sn/include/xtalk/hubdev.h
@@ -8,6 +8,8 @@
 #ifndef _ASM_IA64_SN_XTALK_HUBDEV_H
 #define _ASM_IA64_SN_XTALK_HUBDEV_H
 
+#include "xtalk/xwidgetdev.h"
+
 #define HUB_WIDGET_ID_MAX 0xf
 #define DEV_PER_WIDGET (2*2*8)
 #define IIO_ITTE_WIDGET_BITS    4       /* size of widget field */
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 783eb43..a67f39e 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -9,21 +9,28 @@
 #include <linux/bootmem.h>
 #include <linux/nodemask.h>
 #include <asm/sn/types.h>
-#include <asm/sn/sn_sal.h>
 #include <asm/sn/addrs.h>
+#include <asm/sn/geo.h>
+#include <asm/sn/io.h>
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
-#include "xtalk/xwidgetdev.h"
-#include <asm/sn/geo.h>
-#include "xtalk/hubdev.h"
-#include <asm/sn/io.h>
 #include <asm/sn/simulator.h>
+#include <asm/sn/sn_sal.h>
 #include <asm/sn/tioca_provider.h>
+#include "xtalk/hubdev.h"
+#include "xtalk/xwidgetdev.h"
 
-char master_baseio_wid;
 nasid_t master_nasid = INVALID_NASID;	/* Partition Master */
 
+static struct list_head sn_sysdata_list;
+
+/* sysdata list struct */
+struct sysdata_el {
+	struct list_head entry;
+	void *sysdata;
+};
+
 struct slab_info {
 	struct hubdev_info hubdev;
 };
@@ -138,23 +145,6 @@
 }
 
 /*
- * sn_alloc_pci_sysdata() - This routine allocates a pci controller
- *	which is expected as the pci_dev and pci_bus sysdata by the Linux
- *	PCI infrastructure.
- */
-static inline struct pci_controller *sn_alloc_pci_sysdata(void)
-{
-	struct pci_controller *pci_sysdata;
-
-	pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL);
-	if (!pci_sysdata)
-		BUG();
-
-	memset(pci_sysdata, 0, sizeof(*pci_sysdata));
-	return pci_sysdata;
-}
-
-/*
  * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 
  *	each node in the system.
  */
@@ -221,22 +211,34 @@
 
 }
 
+void sn_pci_unfixup_slot(struct pci_dev *dev)
+{
+	struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
+
+	sn_irq_unfixup(dev);
+	pci_dev_put(host_pci_dev);
+	pci_dev_put(dev);
+}
+
 /*
  * sn_pci_fixup_slot() - This routine sets up a slot's resources
  * consistent with the Linux PCI abstraction layer.  Resources acquired
  * from our PCI provider include PIO maps to BAR space and interrupt
  * objects.
  */
-static void sn_pci_fixup_slot(struct pci_dev *dev)
+void sn_pci_fixup_slot(struct pci_dev *dev)
 {
 	int idx;
 	int segment = 0;
-	uint64_t size;
-	struct sn_irq_info *sn_irq_info;
-	struct pci_dev *host_pci_dev;
 	int status = 0;
 	struct pcibus_bussoft *bs;
+ 	struct pci_bus *host_pci_bus;
+ 	struct pci_dev *host_pci_dev;
+ 	struct sn_irq_info *sn_irq_info;
+ 	unsigned long size;
+ 	unsigned int bus_no, devfn;
 
+	pci_dev_get(dev); /* for the sysdata pointer */
 	dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
 	if (SN_PCIDEV_INFO(dev) <= 0)
 		BUG();		/* Cannot afford to run out of memory */
@@ -253,7 +255,7 @@
 				     (u64) __pa(SN_PCIDEV_INFO(dev)),
 				     (u64) __pa(sn_irq_info));
 	if (status)
-		BUG();		/* Cannot get platform pci device information information */
+		BUG(); /* Cannot get platform pci device information */
 
 	/* Copy over PIO Mapped Addresses */
 	for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
@@ -275,15 +277,21 @@
 			dev->resource[idx].parent = &iomem_resource;
 	}
 
-	/* set up host bus linkages */
-	bs = SN_PCIBUS_BUSSOFT(dev->bus);
-	host_pci_dev =
-	    pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32,
-			  SN_PCIDEV_INFO(dev)->
-			  pdi_slot_host_handle & 0xffffffff);
+	/*
+	 * Using the PROMs values for the PCI host bus, get the Linux
+ 	 * PCI host_pci_dev struct and set up host bus linkages
+ 	 */
+
+ 	bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
+ 	devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
+ 	host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
+ 	host_pci_dev = pci_get_slot(host_pci_bus, devfn);
+
+	SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
 	SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
-	    SN_PCIDEV_INFO(host_pci_dev);
+	    					SN_PCIDEV_INFO(host_pci_dev);
 	SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
+	bs = SN_PCIBUS_BUSSOFT(dev->bus);
 	SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs;
 
 	if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
@@ -297,6 +305,9 @@
 		SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
 		dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
 		sn_irq_fixup(dev, sn_irq_info);
+	} else {
+		SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL;
+		kfree(sn_irq_info);
 	}
 }
 
@@ -304,55 +315,57 @@
  * sn_pci_controller_fixup() - This routine sets up a bus's resources
  * consistent with the Linux PCI abstraction layer.
  */
-static void sn_pci_controller_fixup(int segment, int busnum)
+void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
 {
 	int status = 0;
 	int nasid, cnode;
-	struct pci_bus *bus;
 	struct pci_controller *controller;
 	struct pcibus_bussoft *prom_bussoft_ptr;
 	struct hubdev_info *hubdev_info;
 	void *provider_soft;
 	struct sn_pcibus_provider *provider;
 
-	status =
-	    sal_get_pcibus_info((u64) segment, (u64) busnum,
-				(u64) ia64_tpa(&prom_bussoft_ptr));
-	if (status > 0) {
-		return;		/* bus # does not exist */
-	}
-
+ 	status = sal_get_pcibus_info((u64) segment, (u64) busnum,
+ 				     (u64) ia64_tpa(&prom_bussoft_ptr));
+ 	if (status > 0)
+		return;		/*bus # does not exist */
 	prom_bussoft_ptr = __va(prom_bussoft_ptr);
-	controller = sn_alloc_pci_sysdata();
-	/* controller non-zero is BUG'd in sn_alloc_pci_sysdata */
 
-	bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+ 	controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+ 	if (!controller)
+ 		BUG();
+
 	if (bus == NULL) {
-		return;		/* error, or bus already scanned */
+ 		bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+ 		if (bus == NULL)
+ 			return;	/* error, or bus already scanned */
+ 		bus->sysdata = NULL;
 	}
 
+	if (bus->sysdata)
+		goto error_return; /* sysdata already alloc'd */
+
 	/*
 	 * Per-provider fixup.  Copies the contents from prom to local
 	 * area and links SN_PCIBUS_BUSSOFT().
 	 */
 
-	if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) {
+	if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES)
 		return;		/* unsupported asic type */
-	}
+
+	if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
+		goto error_return; /* no further fixup necessary */
 
 	provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
-	if (provider == NULL) {
+	if (provider == NULL)
 		return;		/* no provider registerd for this asic */
-	}
 
 	provider_soft = NULL;
-	if (provider->bus_fixup) {
+	if (provider->bus_fixup)
 		provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr);
-	}
 
-	if (provider_soft == NULL) {
+	if (provider_soft == NULL)
 		return;		/* fixup failed or not applicable */
-	}
 
 	/*
 	 * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
@@ -361,12 +374,47 @@
 
 	bus->sysdata = controller;
 	PCI_CONTROLLER(bus)->platform_data = provider_soft;
-
 	nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
 	cnode = nasid_to_cnodeid(nasid);
 	hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
 	SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
 	    &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
+
+	return;
+
+error_return:
+
+	kfree(controller);
+	return;
+}
+
+void sn_bus_store_sysdata(struct pci_dev *dev)
+{
+	struct sysdata_el *element;
+
+	element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL);
+	if (!element) {
+		dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
+		return;
+	}
+	element->sysdata = dev->sysdata;
+	list_add(&element->entry, &sn_sysdata_list);
+}
+
+void sn_bus_free_sysdata(void)
+{
+	struct sysdata_el *element;
+	struct list_head *list;
+
+sn_sysdata_free_start:
+	list_for_each(list, &sn_sysdata_list) {
+		element = list_entry(list, struct sysdata_el, entry);
+		list_del(&element->entry);
+		kfree(element->sysdata);
+		kfree(element);
+		goto sn_sysdata_free_start;
+	}
+	return;
 }
 
 /*
@@ -403,20 +451,17 @@
 	 */
 	ia64_max_iommu_merge_mask = ~PAGE_MASK;
 	sn_fixup_ionodes();
-	sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL);
-	if (sn_irq <= 0)
-		BUG();		/* Canno afford to run out of memory. */
-	memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS);
-
+	sn_irq_lh_init();
+	INIT_LIST_HEAD(&sn_sysdata_list);
 	sn_init_cpei_timer();
 
 #ifdef CONFIG_PROC_FS
 	register_sn_procfs();
 #endif
 
-	for (i = 0; i < PCI_BUSES_TO_SCAN; i++) {
-		sn_pci_controller_fixup(0, i);
-	}
+	/* busses are not known yet ... */
+	for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+		sn_pci_controller_fixup(0, i, NULL);
 
 	/*
 	 * Generic Linux PCI Layer has created the pci_bus and pci_dev 
@@ -425,9 +470,8 @@
 	 */
 
 	while ((pci_dev =
-		pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+		pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL)
 		sn_pci_fixup_slot(pci_dev);
-	}
 
 	sn_ioif_inited = 1;	/* sn I/O infrastructure now initialized */
 
@@ -469,3 +513,8 @@
 }
 
 subsys_initcall(sn_pci_init);
+EXPORT_SYMBOL(sn_pci_fixup_slot);
+EXPORT_SYMBOL(sn_pci_unfixup_slot);
+EXPORT_SYMBOL(sn_pci_controller_fixup);
+EXPORT_SYMBOL(sn_bus_store_sysdata);
+EXPORT_SYMBOL(sn_bus_free_sysdata);
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 0f4e8138..84d276a 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -9,13 +9,13 @@
  */
 
 #include <linux/irq.h>
-#include <asm/sn/intr.h>
+#include <linux/spinlock.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
-#include "xtalk/xwidgetdev.h"
+#include <asm/sn/intr.h>
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
 #include <asm/sn/shub_mmr.h>
 #include <asm/sn/sn_sal.h>
 
@@ -25,7 +25,8 @@
 
 extern int sn_force_interrupt_flag;
 extern int sn_ioif_inited;
-struct sn_irq_info **sn_irq;
+static struct list_head **sn_irq_lh;
+static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
 
 static inline uint64_t sn_intr_alloc(nasid_t local_nasid, int local_widget,
 				     u64 sn_irq_info,
@@ -101,7 +102,7 @@
 		nasid = get_nasid();
 		event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
 				       (nasid, SH_EVENT_OCCURRED));
-		/* If the UART bit is set here, we may have received an 
+		/* If the UART bit is set here, we may have received an
 		 * interrupt from the UART that the driver missed.  To
 		 * make sure, we IPI ourselves to force us to look again.
 		 */
@@ -115,82 +116,84 @@
 		force_interrupt(irq);
 }
 
+static void sn_irq_info_free(struct rcu_head *head);
+
 static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
 {
-	struct sn_irq_info *sn_irq_info = sn_irq[irq];
-	struct sn_irq_info *tmp_sn_irq_info;
+	struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
 	int cpuid, cpuphys;
-	nasid_t t_nasid;	/* nasid to target */
-	int t_slice;		/* slice to target */
-
-	/* allocate a temp sn_irq_info struct to get new target info */
-	tmp_sn_irq_info = kmalloc(sizeof(*tmp_sn_irq_info), GFP_KERNEL);
-	if (!tmp_sn_irq_info)
-		return;
 
 	cpuid = first_cpu(mask);
 	cpuphys = cpu_physical_id(cpuid);
-	t_nasid = cpuid_to_nasid(cpuid);
-	t_slice = cpuid_to_slice(cpuid);
 
-	while (sn_irq_info) {
-		int status;
-		int local_widget;
-		uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
-		nasid_t local_nasid = NASID_GET(bridge);
+	list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
+				 sn_irq_lh[irq], list) {
+		uint64_t bridge;
+		int local_widget, status;
+		nasid_t local_nasid;
+		struct sn_irq_info *new_irq_info;
 
-		if (!bridge)
-			break;	/* irq is not a device interrupt */
+		new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+		if (new_irq_info == NULL)
+			break;
+		memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+
+		bridge = (uint64_t) new_irq_info->irq_bridge;
+		if (!bridge) {
+			kfree(new_irq_info);
+			break; /* irq is not a device interrupt */
+		}
+
+		local_nasid = NASID_GET(bridge);
 
 		if (local_nasid & 1)
 			local_widget = TIO_SWIN_WIDGETNUM(bridge);
 		else
 			local_widget = SWIN_WIDGETNUM(bridge);
 
-		/* Free the old PROM sn_irq_info structure */
-		sn_intr_free(local_nasid, local_widget, sn_irq_info);
+		/* Free the old PROM new_irq_info structure */
+		sn_intr_free(local_nasid, local_widget, new_irq_info);
+		/* Update kernels new_irq_info with new target info */
+		unregister_intr_pda(new_irq_info);
 
-		/* allocate a new PROM sn_irq_info struct */
+		/* allocate a new PROM new_irq_info struct */
 		status = sn_intr_alloc(local_nasid, local_widget,
-				       __pa(tmp_sn_irq_info), irq, t_nasid,
-				       t_slice);
+				       __pa(new_irq_info), irq,
+				       cpuid_to_nasid(cpuid),
+				       cpuid_to_slice(cpuid));
 
-		if (status == 0) {
-			/* Update kernels sn_irq_info with new target info */
-			unregister_intr_pda(sn_irq_info);
-			sn_irq_info->irq_cpuid = cpuid;
-			sn_irq_info->irq_nasid = t_nasid;
-			sn_irq_info->irq_slice = t_slice;
-			sn_irq_info->irq_xtalkaddr =
-			    tmp_sn_irq_info->irq_xtalkaddr;
-			sn_irq_info->irq_cookie = tmp_sn_irq_info->irq_cookie;
-			register_intr_pda(sn_irq_info);
+		/* SAL call failed */
+		if (status) {
+			kfree(new_irq_info);
+			break;
+		}
 
-			if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type)) {
-				pcibr_change_devices_irq(sn_irq_info);
-			}
+		new_irq_info->irq_cpuid = cpuid;
+		register_intr_pda(new_irq_info);
 
-			sn_irq_info = sn_irq_info->irq_next;
+		if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type))
+			pcibr_change_devices_irq(new_irq_info);
+
+		spin_lock(&sn_irq_info_lock);
+		list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+		spin_unlock(&sn_irq_info_lock);
+		call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
 
 #ifdef CONFIG_SMP
-			set_irq_affinity_info((irq & 0xff), cpuphys, 0);
+		set_irq_affinity_info((irq & 0xff), cpuphys, 0);
 #endif
-		} else {
-			break;	/* snp_affinity failed the intr_alloc */
-		}
 	}
-	kfree(tmp_sn_irq_info);
 }
 
 struct hw_interrupt_type irq_type_sn = {
-	"SN hub",
-	sn_startup_irq,
-	sn_shutdown_irq,
-	sn_enable_irq,
-	sn_disable_irq,
-	sn_ack_irq,
-	sn_end_irq,
-	sn_set_affinity_irq
+	.typename	= "SN hub",
+	.startup	= sn_startup_irq,
+	.shutdown	= sn_shutdown_irq,
+	.enable		= sn_enable_irq,
+	.disable	= sn_disable_irq,
+	.ack		= sn_ack_irq,
+	.end		= sn_end_irq,
+	.set_affinity	= sn_set_affinity_irq
 };
 
 unsigned int sn_local_vector_to_irq(u8 vector)
@@ -231,19 +234,18 @@
 	struct sn_irq_info *tmp_irq_info;
 	int i, foundmatch;
 
+	rcu_read_lock();
 	if (pdacpu(cpu)->sn_last_irq == irq) {
 		foundmatch = 0;
-		for (i = pdacpu(cpu)->sn_last_irq - 1; i; i--) {
-			tmp_irq_info = sn_irq[i];
-			while (tmp_irq_info) {
+		for (i = pdacpu(cpu)->sn_last_irq - 1;
+		     i && !foundmatch; i--) {
+			list_for_each_entry_rcu(tmp_irq_info,
+						sn_irq_lh[i],
+						list) {
 				if (tmp_irq_info->irq_cpuid == cpu) {
-					foundmatch++;
+					foundmatch = 1;
 					break;
 				}
-				tmp_irq_info = tmp_irq_info->irq_next;
-			}
-			if (foundmatch) {
-				break;
 			}
 		}
 		pdacpu(cpu)->sn_last_irq = i;
@@ -251,60 +253,27 @@
 
 	if (pdacpu(cpu)->sn_first_irq == irq) {
 		foundmatch = 0;
-		for (i = pdacpu(cpu)->sn_first_irq + 1; i < NR_IRQS; i++) {
-			tmp_irq_info = sn_irq[i];
-			while (tmp_irq_info) {
+		for (i = pdacpu(cpu)->sn_first_irq + 1;
+		     i < NR_IRQS && !foundmatch; i++) {
+			list_for_each_entry_rcu(tmp_irq_info,
+						sn_irq_lh[i],
+						list) {
 				if (tmp_irq_info->irq_cpuid == cpu) {
-					foundmatch++;
+					foundmatch = 1;
 					break;
 				}
-				tmp_irq_info = tmp_irq_info->irq_next;
-			}
-			if (foundmatch) {
-				break;
 			}
 		}
 		pdacpu(cpu)->sn_first_irq = ((i == NR_IRQS) ? 0 : i);
 	}
+	rcu_read_unlock();
 }
 
-struct sn_irq_info *sn_irq_alloc(nasid_t local_nasid, int local_widget, int irq,
-				 nasid_t nasid, int slice)
+static void sn_irq_info_free(struct rcu_head *head)
 {
 	struct sn_irq_info *sn_irq_info;
-	int status;
 
-	sn_irq_info = kmalloc(sizeof(*sn_irq_info), GFP_KERNEL);
-	if (sn_irq_info == NULL)
-		return NULL;
-
-	memset(sn_irq_info, 0x0, sizeof(*sn_irq_info));
-
-	status =
-	    sn_intr_alloc(local_nasid, local_widget, __pa(sn_irq_info), irq,
-			  nasid, slice);
-
-	if (status) {
-		kfree(sn_irq_info);
-		return NULL;
-	} else {
-		return sn_irq_info;
-	}
-}
-
-void sn_irq_free(struct sn_irq_info *sn_irq_info)
-{
-	uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
-	nasid_t local_nasid = NASID_GET(bridge);
-	int local_widget;
-
-	if (local_nasid & 1)	/* tio check */
-		local_widget = TIO_SWIN_WIDGETNUM(bridge);
-	else
-		local_widget = SWIN_WIDGETNUM(bridge);
-
-	sn_intr_free(local_nasid, local_widget, sn_irq_info);
-
+	sn_irq_info = container_of(head, struct sn_irq_info, rcu);
 	kfree(sn_irq_info);
 }
 
@@ -314,30 +283,54 @@
 	int slice = sn_irq_info->irq_slice;
 	int cpu = nasid_slice_to_cpuid(nasid, slice);
 
+	pci_dev_get(pci_dev);
 	sn_irq_info->irq_cpuid = cpu;
 	sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev);
 
 	/* link it into the sn_irq[irq] list */
-	sn_irq_info->irq_next = sn_irq[sn_irq_info->irq_irq];
-	sn_irq[sn_irq_info->irq_irq] = sn_irq_info;
+	spin_lock(&sn_irq_info_lock);
+	list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
+	spin_unlock(&sn_irq_info_lock);
 
 	(void)register_intr_pda(sn_irq_info);
 }
 
+void sn_irq_unfixup(struct pci_dev *pci_dev)
+{
+	struct sn_irq_info *sn_irq_info;
+
+	/* Only cleanup IRQ stuff if this device has a host bus context */
+	if (!SN_PCIDEV_BUSSOFT(pci_dev))
+		return;
+
+	sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info;
+	if (!sn_irq_info || !sn_irq_info->irq_irq) {
+		kfree(sn_irq_info);
+		return;
+	}
+
+	unregister_intr_pda(sn_irq_info);
+	spin_lock(&sn_irq_info_lock);
+	list_del_rcu(&sn_irq_info->list);
+	spin_unlock(&sn_irq_info_lock);
+	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+	pci_dev_put(pci_dev);
+}
+
 static void force_interrupt(int irq)
 {
 	struct sn_irq_info *sn_irq_info;
 
 	if (!sn_ioif_inited)
 		return;
-	sn_irq_info = sn_irq[irq];
-	while (sn_irq_info) {
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) {
 		if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
-		    (sn_irq_info->irq_bridge != NULL)) {
+		    (sn_irq_info->irq_bridge != NULL))
 			pcibr_force_interrupt(sn_irq_info);
-		}
-		sn_irq_info = sn_irq_info->irq_next;
 	}
+	rcu_read_unlock();
 }
 
 /*
@@ -402,19 +395,41 @@
 
 void sn_lb_int_war_check(void)
 {
+	struct sn_irq_info *sn_irq_info;
 	int i;
 
 	if (!sn_ioif_inited || pda->sn_first_irq == 0)
 		return;
+
+	rcu_read_lock();
 	for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
-		struct sn_irq_info *sn_irq_info = sn_irq[i];
-		while (sn_irq_info) {
-			/* Only call for PCI bridges that are fully initialized. */
+		list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) {
+			/*
+			 * Only call for PCI bridges that are fully
+			 * initialized.
+			 */
 			if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
-			    (sn_irq_info->irq_bridge != NULL)) {
+			    (sn_irq_info->irq_bridge != NULL))
 				sn_check_intr(i, sn_irq_info);
-			}
-			sn_irq_info = sn_irq_info->irq_next;
 		}
 	}
+	rcu_read_unlock();
+}
+
+void sn_irq_lh_init(void)
+{
+	int i;
+
+	sn_irq_lh = kmalloc(sizeof(struct list_head *) * NR_IRQS, GFP_KERNEL);
+	if (!sn_irq_lh)
+		panic("SN PCI INIT: Failed to allocate memory for PCI init\n");
+
+	for (i = 0; i < NR_IRQS; i++) {
+		sn_irq_lh[i] = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+		if (!sn_irq_lh[i])
+			panic("SN PCI INIT: Failed IRQ memory allocation\n");
+
+		INIT_LIST_HEAD(sn_irq_lh[i]);
+	}
+
 }
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 22e10d2..7c7fe44 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -270,7 +270,7 @@
 {
 	long status, ticks_per_sec, drift;
 	int pxm;
-	int major = sn_sal_rev_major(), minor = sn_sal_rev_minor();
+	u32 version = sn_sal_rev();
 	extern void sn_cpu_init(void);
 
 	ia64_sn_plat_set_error_handling_features();
@@ -308,22 +308,21 @@
 	 * support here so we don't have to listen to failed keyboard probe
 	 * messages.
 	 */
-	if ((major < 2 || (major == 2 && minor <= 9)) &&
-	    acpi_kbd_controller_present) {
+	if (version <= 0x0209 && acpi_kbd_controller_present) {
 		printk(KERN_INFO "Disabling legacy keyboard support as prom "
 		       "is too old and doesn't provide FADT\n");
 		acpi_kbd_controller_present = 0;
 	}
 
-	printk("SGI SAL version %x.%02x\n", major, minor);
+	printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);
 
 	/*
 	 * Confirm the SAL we're running on is recent enough...
 	 */
-	if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR &&
-					   minor < SN_SAL_MIN_MINOR)) {
+	if (version < SN_SAL_MIN_VERSION) {
 		printk(KERN_ERR "This kernel needs SGI SAL version >= "
-		       "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR);
+		       "%x.%02x\n", SN_SAL_MIN_VERSION >> 8,
+		        SN_SAL_MIN_VERSION & 0x00FF);
 		panic("PROM version too old\n");
 	}
 
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index 8716f4d..c1cbcd1 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -14,6 +14,7 @@
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/addrs.h>
@@ -481,6 +482,9 @@
 	cnodeid_t cnodeid;
 	int found_tiocx_device = 0;
 
+	if (!ia64_platform_is("sn2"))
+		return -ENODEV;
+
 	bus_register(&tiocx_bus_type);
 
 	for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) {
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index 5da9bdb..a2f7a88 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -11,9 +11,10 @@
 
 #include <linux/module.h>
 #include <asm/dma.h>
-#include <asm/sn/sn_sal.h>
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
+#include <asm/sn/sn_sal.h>
 
 #define SG_ENT_VIRT_ADDRESS(sg)	(page_address((sg)->page) + (sg)->offset)
 #define SG_ENT_PHYS_ADDRESS(SG)	virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
index 0e47bce8..d1647b8 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
@@ -8,9 +8,9 @@
 
 #include <linux/types.h>
 #include <asm/sn/sn_sal.h>
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
 
 int pcibr_invalidate_ate = 0;	/* by default don't invalidate ATE on free */
 
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index 64af2b2..b058dc2 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -8,18 +8,17 @@
 
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
 #include <asm/sn/geo.h>
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
-#include "pci/tiocp.h"
-#include "pci/pic.h"
-#include "pci/pcibr_provider.h"
-#include "pci/tiocp.h"
+#include <asm/sn/pic.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/tiocp.h>
 #include "tio.h"
-#include <asm/sn/addrs.h>
+#include "xtalk/xwidgetdev.h"
+#include "xtalk/hubdev.h"
 
 extern int sn_ioif_inited;
 
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 3893999..9813da5 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -6,18 +6,51 @@
  * Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved.
  */
 
-#include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/types.h>
 #include <linux/pci.h>
-#include <asm/sn/sn_sal.h>
-#include "xtalk/xwidgetdev.h"
+#include <asm/sn/addrs.h>
 #include <asm/sn/geo.h>
-#include "xtalk/hubdev.h"
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
-#include <asm/sn/addrs.h>
+#include <asm/sn/sn_sal.h>
+#include "xtalk/xwidgetdev.h"
+#include "xtalk/hubdev.h"
 
+int
+sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
+{
+	struct ia64_sal_retval ret_stuff;
+	uint64_t busnum;
+
+	ret_stuff.status = 0;
+	ret_stuff.v0 = 0;
+
+	busnum = soft->pbi_buscommon.bs_persist_busnum;
+	SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, (u64) busnum,
+			(u64) device, (u64) resp, 0, 0, 0, 0);
+
+	return (int)ret_stuff.v0;
+}
+
+int
+sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action,
+		       void *resp)
+{
+	struct ia64_sal_retval ret_stuff;
+	uint64_t busnum;
+
+	ret_stuff.status = 0;
+	ret_stuff.v0 = 0;
+
+	busnum = soft->pbi_buscommon.bs_persist_busnum;
+	SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE,
+			(u64) busnum, (u64) device, (u64) action,
+			(u64) resp, 0, 0, 0);
+
+	return (int)ret_stuff.v0;
+}
 
 static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
 {
@@ -188,3 +221,6 @@
 
 	return 0;
 }
+
+EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable);
+EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
index 865c11c..21426d0 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
@@ -6,13 +6,13 @@
  * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved.
  */
 
-#include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/types.h>
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
-#include "pci/tiocp.h"
-#include "pci/pic.h"
-#include "pci/pcibr_provider.h"
+#include <asm/sn/pic.h>
+#include <asm/sn/tiocp.h>
 
 union br_ptr {
 	struct tiocp tio;
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
index 05aa8c2f..51cc4e6 100644
--- a/arch/ia64/sn/pci/tioca_provider.c
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -589,8 +589,7 @@
 
 	/* sanity check prom rev */
 
-	if (sn_sal_rev_major() < 4 ||
-	    (sn_sal_rev_major() == 4 && sn_sal_rev_minor() < 6)) {
+	if (sn_sal_rev() < 0x0406) {
 		printk
 		    (KERN_ERR "%s:  SGI prom rev 4.06 or greater required "
 		     "for tioca support\n", __FUNCTION__);
diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c
index b014e2c..a146b24 100644
--- a/arch/m32r/kernel/setup_m32700ut.c
+++ b/arch/m32r/kernel/setup_m32700ut.c
@@ -3,8 +3,8 @@
  *
  *  Setup routines for Renesas M32700UT Board
  *
- *  Copyright (c) 2002 	Hiroyuki Kondo, Hirokazu Takata,
- *                      Hitoshi Yamamoto, Takeo Takahashi
+ *  Copyright (c) 2002-2005  Hiroyuki Kondo, Hirokazu Takata,
+ *                           Hitoshi Yamamoto, Takeo Takahashi
  *
  *  This file is subject to the terms and conditions of the GNU General
  *  Public License.  See the file "COPYING" in the main directory of this
@@ -435,7 +435,7 @@
 	icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
 	enable_m32700ut_irq(M32R_IRQ_INT2);
 
-//#if defined(CONFIG_VIDEO_M32R_AR)
+#if defined(CONFIG_VIDEO_M32R_AR)
 	/*
 	 * INT3# is used for AR
 	 */
@@ -445,9 +445,11 @@
 	irq_desc[M32R_IRQ_INT3].depth = 1;
 	icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
 	disable_m32700ut_irq(M32R_IRQ_INT3);
-//#endif	/* CONFIG_VIDEO_M32R_AR */
+#endif	/* CONFIG_VIDEO_M32R_AR */
 }
 
+#if defined(CONFIG_SMC91X)
+
 #define LAN_IOSTART     0x300
 #define LAN_IOEND       0x320
 static struct resource smc91x_resources[] = {
@@ -469,10 +471,55 @@
 	.num_resources  = ARRAY_SIZE(smc91x_resources),
 	.resource       = smc91x_resources,
 };
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+	.initregs		= s1d13xxxfb_initregs,
+	.initregssize		= ARRAY_SIZE(s1d13xxxfb_initregs),
+	.platform_init_video	= NULL,
+#ifdef CONFIG_PM
+	.platform_suspend_video	= NULL,
+	.platform_resume_video	= NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+	[0] = {
+		.start  = 0x10600000UL,
+		.end    = 0x1073FFFFUL,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = 0x10400000UL,
+		.end    = 0x104001FFUL,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device s1d13xxxfb_device = {
+	.name		= S1D_DEVICENAME,
+	.id		= 0,
+	.dev            = {
+		.platform_data  = &s1d13xxxfb_data,
+	},
+	.num_resources  = ARRAY_SIZE(s1d13xxxfb_resources),
+	.resource       = s1d13xxxfb_resources,
+};
+#endif
 
 static int __init platform_init(void)
 {
+#if defined(CONFIG_SMC91X)
 	platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+	platform_device_register(&s1d13xxxfb_device);
+#endif
 	return 0;
 }
 arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c
index aaf8e56..4e70980 100644
--- a/arch/m32r/kernel/setup_mappi.c
+++ b/arch/m32r/kernel/setup_mappi.c
@@ -3,14 +3,15 @@
  *
  *  Setup routines for Renesas MAPPI Board
  *
- *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
- *                            Hitoshi Yamamoto
+ *  Copyright (c) 2001-2005  Hiroyuki Kondo, Hirokazu Takata,
+ *                           Hitoshi Yamamoto
  */
 
 #include <linux/config.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/device.h>
 
 #include <asm/system.h>
 #include <asm/m32r.h>
@@ -158,3 +159,49 @@
 	disable_mappi_irq(M32R_IRQ_INT2);
 #endif /* CONFIG_M32RPCC */
 }
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+	.initregs		= s1d13xxxfb_initregs,
+	.initregssize		= ARRAY_SIZE(s1d13xxxfb_initregs),
+	.platform_init_video	= NULL,
+#ifdef CONFIG_PM
+	.platform_suspend_video	= NULL,
+	.platform_resume_video	= NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+	[0] = {
+		.start  = 0x10200000UL,
+		.end    = 0x1033FFFFUL,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = 0x10000000UL,
+		.end    = 0x100001FFUL,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device s1d13xxxfb_device = {
+	.name		= S1D_DEVICENAME,
+	.id		= 0,
+	.dev            = {
+		.platform_data  = &s1d13xxxfb_data,
+	},
+	.num_resources  = ARRAY_SIZE(s1d13xxxfb_resources),
+	.resource       = s1d13xxxfb_resources,
+};
+
+static int __init platform_init(void)
+{
+	platform_device_register(&s1d13xxxfb_device);
+	return 0;
+}
+arch_initcall(platform_init);
+#endif
diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c
index 38d5e9a..a1d8015 100644
--- a/arch/m32r/kernel/setup_mappi2.c
+++ b/arch/m32r/kernel/setup_mappi2.c
@@ -3,8 +3,8 @@
  *
  *  Setup routines for Renesas MAPPI-II(M3A-ZA36) Board
  *
- *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
- *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ *  Copyright (c) 2001-2005  Hiroyuki Kondo, Hirokazu Takata,
+ *                           Hitoshi Yamamoto, Mamoru Sakugawa
  */
 
 #include <linux/config.h>
diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c
index 3d60a85..a76412e 100644
--- a/arch/m32r/kernel/setup_mappi3.c
+++ b/arch/m32r/kernel/setup_mappi3.c
@@ -3,8 +3,8 @@
  *
  *  Setup routines for Renesas MAPPI-III(M3A-2170) Board
  *
- *  Copyright (c) 2001-2005   Hiroyuki Kondo, Hirokazu Takata,
- *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ *  Copyright (c) 2001-2005  Hiroyuki Kondo, Hirokazu Takata,
+ *                           Hitoshi Yamamoto, Mamoru Sakugawa
  */
 
 #include <linux/config.h>
@@ -178,6 +178,8 @@
 #endif /* CONFIG_M32R_CFC */
 }
 
+#if defined(CONFIG_SMC91X)
+
 #define LAN_IOSTART     0x300
 #define LAN_IOEND       0x320
 static struct resource smc91x_resources[] = {
@@ -200,9 +202,55 @@
 	.resource       = smc91x_resources,
 };
 
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+	.initregs		= s1d13xxxfb_initregs,
+	.initregssize		= ARRAY_SIZE(s1d13xxxfb_initregs),
+	.platform_init_video	= NULL,
+#ifdef CONFIG_PM
+	.platform_suspend_video	= NULL,
+	.platform_resume_video	= NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+	[0] = {
+		.start  = 0x1d600000UL,
+		.end    = 0x1d73FFFFUL,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = 0x1d400000UL,
+		.end    = 0x1d4001FFUL,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device s1d13xxxfb_device = {
+	.name		= S1D_DEVICENAME,
+	.id		= 0,
+	.dev            = {
+		.platform_data  = &s1d13xxxfb_data,
+	},
+	.num_resources  = ARRAY_SIZE(s1d13xxxfb_resources),
+	.resource       = s1d13xxxfb_resources,
+};
+#endif
+
 static int __init platform_init(void)
 {
+#if defined(CONFIG_SMC91X)
 	platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+	platform_device_register(&s1d13xxxfb_device);
+#endif
 	return 0;
 }
 arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c
index d656640..45add5b 100644
--- a/arch/m32r/kernel/setup_oaks32r.c
+++ b/arch/m32r/kernel/setup_oaks32r.c
@@ -3,8 +3,8 @@
  *
  *  Setup routines for OAKS32R Board
  *
- *  Copyright (c) 2002-2004   Hiroyuki Kondo, Hirokazu Takata,
- *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ *  Copyright (c) 2002-2005  Hiroyuki Kondo, Hirokazu Takata,
+ *                           Hitoshi Yamamoto, Mamoru Sakugawa
  */
 
 #include <linux/config.h>
@@ -139,5 +139,4 @@
 	icu_data[M32R_IRQ_SIO1_S].icucr = 0;
 	disable_oaks32r_irq(M32R_IRQ_SIO1_S);
 #endif /* CONFIG_SERIAL_M32R_SIO */
-
 }
diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c
index 86f4cf2..f0301f5 100644
--- a/arch/m32r/kernel/setup_opsput.c
+++ b/arch/m32r/kernel/setup_opsput.c
@@ -3,7 +3,7 @@
  *
  *  Setup routines for Renesas OPSPUT Board
  *
- *  Copyright (c) 2002-2004
+ *  Copyright (c) 2002-2005
  * 	Hiroyuki Kondo, Hirokazu Takata,
  *      Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa
  *
@@ -439,7 +439,7 @@
 	icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
 	enable_opsput_irq(M32R_IRQ_INT2);
 
-//#if defined(CONFIG_VIDEO_M32R_AR)
+#if defined(CONFIG_VIDEO_M32R_AR)
 	/*
 	 * INT3# is used for AR
 	 */
@@ -449,9 +449,11 @@
 	irq_desc[M32R_IRQ_INT3].depth = 1;
 	icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
 	disable_opsput_irq(M32R_IRQ_INT3);
-//#endif	/* CONFIG_VIDEO_M32R_AR */
+#endif /* CONFIG_VIDEO_M32R_AR */
 }
 
+#if defined(CONFIG_SMC91X)
+
 #define LAN_IOSTART     0x300
 #define LAN_IOEND       0x320
 static struct resource smc91x_resources[] = {
@@ -473,10 +475,55 @@
 	.num_resources  = ARRAY_SIZE(smc91x_resources),
 	.resource       = smc91x_resources,
 };
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+	.initregs		= s1d13xxxfb_initregs,
+	.initregssize		= ARRAY_SIZE(s1d13xxxfb_initregs),
+	.platform_init_video	= NULL,
+#ifdef CONFIG_PM
+	.platform_suspend_video	= NULL,
+	.platform_resume_video	= NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+	[0] = {
+		.start  = 0x10600000UL,
+		.end    = 0x1073FFFFUL,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = 0x10400000UL,
+		.end    = 0x104001FFUL,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device s1d13xxxfb_device = {
+	.name		= S1D_DEVICENAME,
+	.id		= 0,
+	.dev            = {
+		.platform_data  = &s1d13xxxfb_data,
+	},
+	.num_resources  = ARRAY_SIZE(s1d13xxxfb_resources),
+	.resource       = s1d13xxxfb_resources,
+};
+#endif
 
 static int __init platform_init(void)
 {
+#if defined(CONFIG_SMC91X)
 	platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+	platform_device_register(&s1d13xxxfb_device);
+#endif
 	return 0;
 }
 arch_initcall(platform_init);
diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c
index 5fdd4f6..c060524 100644
--- a/arch/ppc/platforms/pmac_cpufreq.c
+++ b/arch/ppc/platforms/pmac_cpufreq.c
@@ -452,7 +452,7 @@
 	return offset;
 }
 
-static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state)
+static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
 {
 	/* Ok, this could be made a bit smarter, but let's be robust for now. We
 	 * always force a speed change to high speed before sleep, to make sure
diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c
index 49c0e34..1eb4f72 100644
--- a/arch/ppc/syslib/of_device.c
+++ b/arch/ppc/syslib/of_device.c
@@ -3,6 +3,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <asm/errno.h>
 #include <asm/of_device.h>
 
@@ -15,20 +16,20 @@
  * Used by a driver to check whether an of_device present in the
  * system is in its list of supported devices.
  */
-const struct of_match * of_match_device(const struct of_match *matches,
+const struct of_device_id * of_match_device(const struct of_device_id *matches,
 					const struct of_device *dev)
 {
 	if (!dev->node)
 		return NULL;
-	while (matches->name || matches->type || matches->compatible) {
+	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
 		int match = 1;
-		if (matches->name && matches->name != OF_ANY_MATCH)
+		if (matches->name[0])
 			match &= dev->node->name
 				&& !strcmp(matches->name, dev->node->name);
-		if (matches->type && matches->type != OF_ANY_MATCH)
+		if (matches->type[0])
 			match &= dev->node->type
 				&& !strcmp(matches->type, dev->node->type);
-		if (matches->compatible && matches->compatible != OF_ANY_MATCH)
+		if (matches->compatible[0])
 			match &= device_is_compatible(dev->node,
 				matches->compatible);
 		if (match)
@@ -42,7 +43,7 @@
 {
 	struct of_device * of_dev = to_of_device(dev);
 	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-	const struct of_match * matches = of_drv->match_table;
+	const struct of_device_id * matches = of_drv->match_table;
 
 	if (!matches)
 		return 0;
@@ -75,7 +76,7 @@
 	int error = -ENODEV;
 	struct of_platform_driver *drv;
 	struct of_device *of_dev;
-	const struct of_match *match;
+	const struct of_device_id *match;
 
 	drv = to_of_platform_driver(dev->driver);
 	of_dev = to_of_device(dev);
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c
index 1d162c7..8d4c46f 100644
--- a/arch/ppc64/kernel/cputable.c
+++ b/arch/ppc64/kernel/cputable.c
@@ -49,160 +49,219 @@
 #endif
 
 struct cpu_spec	cpu_specs[] = {
-    {	/* Power3 */
-	    0xffff0000, 0x00400000, "POWER3 (630)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power3,
-	    COMMON_PPC64_FW
-    },
-    {	/* Power3+ */
-	    0xffff0000, 0x00410000, "POWER3 (630+)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power3,
-	    COMMON_PPC64_FW
-    },
-    {	/* Northstar */
-	    0xffff0000, 0x00330000, "RS64-II (northstar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power3,
-	    COMMON_PPC64_FW
-    },
-    {	/* Pulsar */
-	    0xffff0000, 0x00340000, "RS64-III (pulsar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power3,
-	    COMMON_PPC64_FW
-    },
-    {	/* I-star */
-	    0xffff0000, 0x00360000, "RS64-III (icestar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power3,
-	    COMMON_PPC64_FW
-    },
-    {	/* S-star */
-	    0xffff0000, 0x00370000, "RS64-IV (sstar)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power3,
-	    COMMON_PPC64_FW
-    },
-    {	/* Power4 */
-	    0xffff0000, 0x00350000, "POWER4 (gp)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power4,
-	    COMMON_PPC64_FW
-    },
-    {	/* Power4+ */
-	    0xffff0000, 0x00380000, "POWER4+ (gq)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power4,
-	    COMMON_PPC64_FW
-    },
-    {	/* PPC970 */
-	    0xffff0000, 0x00390000, "PPC970",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-		    CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
-	    128, 128,
-	    __setup_cpu_ppc970,
-	    COMMON_PPC64_FW
-    },
-    {	/* PPC970FX */
-	    0xffff0000, 0x003c0000, "PPC970FX",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-		    CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
-	    COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
-	    128, 128,
-	    __setup_cpu_ppc970,
-	    COMMON_PPC64_FW
-    },
-    {	/* Power5 */
-	    0xffff0000, 0x003a0000, "POWER5 (gr)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
-		    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
-		    CPU_FTR_MMCRA_SIHV,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power4,
-	    COMMON_PPC64_FW
-    },
-    {	/* Power5 */
-	    0xffff0000, 0x003b0000, "POWER5 (gs)",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
-		    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
-		    CPU_FTR_MMCRA_SIHV,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power4,
-	    COMMON_PPC64_FW
-    },
-    {	/* BE DD1.x  */
-	    0xffff0000, 0x00700000, "Broadband Engine",
-	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
-		    CPU_FTR_SMT,
-	    COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
-	    128, 128,
-	    __setup_cpu_be,
-	    COMMON_PPC64_FW
-    },
-    {	/* default match */
-	    0x00000000, 0x00000000, "POWER4 (compatible)",
-  	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-		    CPU_FTR_PPCAS_ARCH_V2,
-	    COMMON_USER_PPC64,
-	    128, 128,
-	    __setup_cpu_power4,
-	    COMMON_PPC64_FW
-    }
+	{	/* Power3 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00400000,
+		.cpu_name		= "POWER3 (630)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+			CPU_FTR_PMC8,
+		.cpu_user_features = COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power3,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* Power3+ */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00410000,
+		.cpu_name		= "POWER3 (630+)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+			CPU_FTR_PMC8,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power3,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* Northstar */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00330000,
+		.cpu_name		= "RS64-II (northstar)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+			CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power3,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* Pulsar */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00340000,
+		.cpu_name		= "RS64-III (pulsar)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+			CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power3,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* I-star */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00360000,
+		.cpu_name		= "RS64-III (icestar)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+			CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power3,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* S-star */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00370000,
+		.cpu_name		= "RS64-IV (sstar)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+			CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power3,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* Power4 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00350000,
+		.cpu_name		= "POWER4 (gp)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power4,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* Power4+ */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00380000,
+		.cpu_name		= "POWER4+ (gq)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power4,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* PPC970 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00390000,
+		.cpu_name		= "PPC970",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+			CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+		.cpu_user_features	= COMMON_USER_PPC64 |
+			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_ppc970,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* PPC970FX */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x003c0000,
+		.cpu_name		= "PPC970FX",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+			CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+		.cpu_user_features	= COMMON_USER_PPC64 |
+			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_ppc970,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* Power5 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x003a0000,
+		.cpu_name		= "POWER5 (gr)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
+			CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
+			CPU_FTR_MMCRA_SIHV,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power4,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* Power5 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x003b0000,
+		.cpu_name		= "POWER5 (gs)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
+			CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
+			CPU_FTR_MMCRA_SIHV,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power4,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* BE DD1.x */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x00700000,
+		.cpu_name		= "Broadband Engine",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+			CPU_FTR_SMT,
+		.cpu_user_features	= COMMON_USER_PPC64 |
+			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_be,
+		.firmware_features	= COMMON_PPC64_FW,
+	},
+	{	/* default match */
+		.pvr_mask		= 0x00000000,
+		.pvr_value		= 0x00000000,
+		.cpu_name		= "POWER4 (compatible)",
+		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
+			CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+			CPU_FTR_PPCAS_ARCH_V2,
+		.cpu_user_features	= COMMON_USER_PPC64,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_power4,
+		.firmware_features	= COMMON_PPC64_FW,
+	}
 };
 
 firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
-    {FW_FEATURE_PFT,		"hcall-pft"},
-    {FW_FEATURE_TCE,		"hcall-tce"},
-    {FW_FEATURE_SPRG0,		"hcall-sprg0"},
-    {FW_FEATURE_DABR,		"hcall-dabr"},
-    {FW_FEATURE_COPY,		"hcall-copy"},
-    {FW_FEATURE_ASR,		"hcall-asr"},
-    {FW_FEATURE_DEBUG,		"hcall-debug"},
-    {FW_FEATURE_PERF,		"hcall-perf"},
-    {FW_FEATURE_DUMP,		"hcall-dump"},
-    {FW_FEATURE_INTERRUPT,	"hcall-interrupt"},
-    {FW_FEATURE_MIGRATE,	"hcall-migrate"},
-    {FW_FEATURE_PERFMON,	"hcall-perfmon"},
-    {FW_FEATURE_CRQ,    	"hcall-crq"},
-    {FW_FEATURE_VIO,	        "hcall-vio"},
-    {FW_FEATURE_RDMA,	        "hcall-rdma"},
-    {FW_FEATURE_LLAN,	        "hcall-lLAN"},
-    {FW_FEATURE_BULK,   	"hcall-bulk"},
-    {FW_FEATURE_XDABR,  	"hcall-xdabr"},
-    {FW_FEATURE_MULTITCE,	"hcall-multi-tce"},
-    {FW_FEATURE_SPLPAR,	        "hcall-splpar"},
+	{FW_FEATURE_PFT,		"hcall-pft"},
+	{FW_FEATURE_TCE,		"hcall-tce"},
+	{FW_FEATURE_SPRG0,		"hcall-sprg0"},
+	{FW_FEATURE_DABR,		"hcall-dabr"},
+	{FW_FEATURE_COPY,		"hcall-copy"},
+	{FW_FEATURE_ASR,		"hcall-asr"},
+	{FW_FEATURE_DEBUG,		"hcall-debug"},
+	{FW_FEATURE_PERF,		"hcall-perf"},
+	{FW_FEATURE_DUMP,		"hcall-dump"},
+	{FW_FEATURE_INTERRUPT,		"hcall-interrupt"},
+	{FW_FEATURE_MIGRATE,		"hcall-migrate"},
+	{FW_FEATURE_PERFMON,		"hcall-perfmon"},
+	{FW_FEATURE_CRQ,		"hcall-crq"},
+	{FW_FEATURE_VIO,		"hcall-vio"},
+	{FW_FEATURE_RDMA,		"hcall-rdma"},
+	{FW_FEATURE_LLAN,		"hcall-lLAN"},
+	{FW_FEATURE_BULK,		"hcall-bulk"},
+	{FW_FEATURE_XDABR,		"hcall-xdabr"},
+	{FW_FEATURE_MULTITCE,		"hcall-multi-tce"},
+	{FW_FEATURE_SPLPAR,		"hcall-splpar"},
 };
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index 675c270..93ebcac 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -308,6 +308,7 @@
 label##_pSeries:					\
 	HMT_MEDIUM;					\
 	mtspr	SPRG1,r13;		/* save r13 */	\
+	RUNLATCH_ON(r13);				\
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
 
 #define STD_EXCEPTION_ISERIES(n, label, area)		\
@@ -315,6 +316,7 @@
 label##_iSeries:					\
 	HMT_MEDIUM;					\
 	mtspr	SPRG1,r13;		/* save r13 */	\
+	RUNLATCH_ON(r13);				\
 	EXCEPTION_PROLOG_ISERIES_1(area);		\
 	EXCEPTION_PROLOG_ISERIES_2;			\
 	b	label##_common
@@ -324,6 +326,7 @@
 label##_iSeries:							\
 	HMT_MEDIUM;							\
 	mtspr	SPRG1,r13;		/* save r13 */			\
+	RUNLATCH_ON(r13);						\
 	EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN);				\
 	lbz	r10,PACAPROCENABLED(r13);				\
 	cmpwi	0,r10,0;						\
@@ -393,6 +396,7 @@
 _machine_check_pSeries:
 	HMT_MEDIUM
 	mtspr	SPRG1,r13		/* save r13 */
+	RUNLATCH_ON(r13)
 	EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
 
 	. = 0x300
@@ -419,6 +423,7 @@
 data_access_slb_pSeries:
 	HMT_MEDIUM
 	mtspr	SPRG1,r13
+	RUNLATCH_ON(r13)
 	mfspr	r13,SPRG3		/* get paca address into r13 */
 	std	r9,PACA_EXSLB+EX_R9(r13)	/* save r9 - r12 */
 	std	r10,PACA_EXSLB+EX_R10(r13)
@@ -439,6 +444,7 @@
 instruction_access_slb_pSeries:
 	HMT_MEDIUM
 	mtspr	SPRG1,r13
+	RUNLATCH_ON(r13)
 	mfspr	r13,SPRG3		/* get paca address into r13 */
 	std	r9,PACA_EXSLB+EX_R9(r13)	/* save r9 - r12 */
 	std	r10,PACA_EXSLB+EX_R10(r13)
@@ -464,6 +470,7 @@
 	.globl	system_call_pSeries
 system_call_pSeries:
 	HMT_MEDIUM
+	RUNLATCH_ON(r9)
 	mr	r9,r13
 	mfmsr	r10
 	mfspr	r13,SPRG3
@@ -707,11 +714,13 @@
 system_reset_fwnmi:
 	HMT_MEDIUM
 	mtspr	SPRG1,r13		/* save r13 */
+	RUNLATCH_ON(r13)
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
 	.globl machine_check_fwnmi
 machine_check_fwnmi:
 	HMT_MEDIUM
 	mtspr	SPRG1,r13		/* save r13 */
+	RUNLATCH_ON(r13)
 	EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
 
 	/*
@@ -848,6 +857,7 @@
 	.align	7
 	.globl data_access_common
 data_access_common:
+	RUNLATCH_ON(r10)		/* It wont fit in the 0x300 handler */
 	mfspr	r10,DAR
 	std	r10,PACA_EXGEN+EX_DAR(r13)
 	mfspr	r10,DSISR
diff --git a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c
index c72fb8f..138e128 100644
--- a/arch/ppc64/kernel/hvconsole.c
+++ b/arch/ppc64/kernel/hvconsole.c
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <asm/hvcall.h>
 #include <asm/hvconsole.h>
-#include <asm/prom.h>
 
 /**
  * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
@@ -42,29 +41,14 @@
 	unsigned long got;
 
 	if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got,
-		(unsigned long *)buf, (unsigned long *)buf+1) == H_Success) {
-		/*
-		 * Work around a HV bug where it gives us a null
-		 * after every \r.  -- paulus
-		 */
-		if (got > 0) {
-			int i;
-			for (i = 1; i < got; ++i) {
-				if (buf[i] == 0 && buf[i-1] == '\r') {
-					--got;
-					if (i < got)
-						memmove(&buf[i], &buf[i+1],
-							got - i);
-				}
-			}
-		}
+		(unsigned long *)buf, (unsigned long *)buf+1) == H_Success)
 		return got;
-	}
 	return 0;
 }
 
 EXPORT_SYMBOL(hvc_get_chars);
 
+
 /**
  * hvc_put_chars: send characters to firmware for denoted vterm adapter
  * @vtermno: The vtermno or unit_address of the adapter from which the data
@@ -88,34 +72,3 @@
 }
 
 EXPORT_SYMBOL(hvc_put_chars);
-
-/*
- * We hope/assume that the first vty found corresponds to the first console
- * device.
- */
-int hvc_find_vtys(void)
-{
-	struct device_node *vty;
-	int num_found = 0;
-
-	for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
-			vty = of_find_node_by_name(vty, "vty")) {
-		uint32_t *vtermno;
-
-		/* We have statically defined space for only a certain number of
-		 * console adapters. */
-		if (num_found >= MAX_NR_HVC_CONSOLES)
-			break;
-
-		vtermno = (uint32_t *)get_property(vty, "reg", NULL);
-		if (!vtermno)
-			continue;
-
-		if (device_is_compatible(vty, "hvterm1")) {
-			hvc_instantiate(*vtermno, num_found);
-			++num_found;
-		}
-	}
-
-	return num_found;
-}
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
index b3f770f..077c82f 100644
--- a/arch/ppc64/kernel/iSeries_setup.c
+++ b/arch/ppc64/kernel/iSeries_setup.c
@@ -834,6 +834,92 @@
 
 late_initcall(iSeries_src_init);
 
+static inline void process_iSeries_events(void)
+{
+	asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
+}
+
+static void yield_shared_processor(void)
+{
+	unsigned long tb;
+
+	HvCall_setEnabledInterrupts(HvCall_MaskIPI |
+				    HvCall_MaskLpEvent |
+				    HvCall_MaskLpProd |
+				    HvCall_MaskTimeout);
+
+	tb = get_tb();
+	/* Compute future tb value when yield should expire */
+	HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
+
+	/*
+	 * The decrementer stops during the yield.  Force a fake decrementer
+	 * here and let the timer_interrupt code sort out the actual time.
+	 */
+	get_paca()->lppaca.int_dword.fields.decr_int = 1;
+	process_iSeries_events();
+}
+
+static int iseries_shared_idle(void)
+{
+	while (1) {
+		while (!need_resched() && !hvlpevent_is_pending()) {
+			local_irq_disable();
+			ppc64_runlatch_off();
+
+			/* Recheck with irqs off */
+			if (!need_resched() && !hvlpevent_is_pending())
+				yield_shared_processor();
+
+			HMT_medium();
+			local_irq_enable();
+		}
+
+		ppc64_runlatch_on();
+
+		if (hvlpevent_is_pending())
+			process_iSeries_events();
+
+		schedule();
+	}
+
+	return 0;
+}
+
+static int iseries_dedicated_idle(void)
+{
+	long oldval;
+
+	while (1) {
+		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+
+		if (!oldval) {
+			set_thread_flag(TIF_POLLING_NRFLAG);
+
+			while (!need_resched()) {
+				ppc64_runlatch_off();
+				HMT_low();
+
+				if (hvlpevent_is_pending()) {
+					HMT_medium();
+					ppc64_runlatch_on();
+					process_iSeries_events();
+				}
+			}
+
+			HMT_medium();
+			clear_thread_flag(TIF_POLLING_NRFLAG);
+		} else {
+			set_need_resched();
+		}
+
+		ppc64_runlatch_on();
+		schedule();
+	}
+
+	return 0;
+}
+
 #ifndef CONFIG_PCI
 void __init iSeries_init_IRQ(void) { }
 #endif
@@ -859,5 +945,13 @@
 	ppc_md.get_rtc_time = iSeries_get_rtc_time;
 	ppc_md.calibrate_decr = iSeries_calibrate_decr;
 	ppc_md.progress = iSeries_progress;
+
+	if (get_paca()->lppaca.shared_proc) {
+		ppc_md.idle_loop = iseries_shared_idle;
+		printk(KERN_INFO "Using shared processor idle loop\n");
+	} else {
+		ppc_md.idle_loop = iseries_dedicated_idle;
+		printk(KERN_INFO "Using dedicated idle loop\n");
+	}
 }
 
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
index 08952c7..954395d 100644
--- a/arch/ppc64/kernel/idle.c
+++ b/arch/ppc64/kernel/idle.c
@@ -20,109 +20,18 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
-#include <linux/module.h>
 #include <linux/sysctl.h>
-#include <linux/smp.h>
 
 #include <asm/system.h>
 #include <asm/processor.h>
-#include <asm/mmu.h>
 #include <asm/cputable.h>
 #include <asm/time.h>
-#include <asm/iSeries/HvCall.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/plpar_wrappers.h>
 #include <asm/systemcfg.h>
+#include <asm/machdep.h>
 
 extern void power4_idle(void);
 
-static int (*idle_loop)(void);
-
-#ifdef CONFIG_PPC_ISERIES
-static unsigned long maxYieldTime = 0;
-static unsigned long minYieldTime = 0xffffffffffffffffUL;
-
-static inline void process_iSeries_events(void)
-{
-	asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
-}
-
-static void yield_shared_processor(void)
-{
-	unsigned long tb;
-	unsigned long yieldTime;
-
-	HvCall_setEnabledInterrupts(HvCall_MaskIPI |
-				    HvCall_MaskLpEvent |
-				    HvCall_MaskLpProd |
-				    HvCall_MaskTimeout);
-
-	tb = get_tb();
-	/* Compute future tb value when yield should expire */
-	HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
-
-	yieldTime = get_tb() - tb;
-	if (yieldTime > maxYieldTime)
-		maxYieldTime = yieldTime;
-
-	if (yieldTime < minYieldTime)
-		minYieldTime = yieldTime;
-	
-	/*
-	 * The decrementer stops during the yield.  Force a fake decrementer
-	 * here and let the timer_interrupt code sort out the actual time.
-	 */
-	get_paca()->lppaca.int_dword.fields.decr_int = 1;
-	process_iSeries_events();
-}
-
-static int iSeries_idle(void)
-{
-	struct paca_struct *lpaca;
-	long oldval;
-
-	/* ensure iSeries run light will be out when idle */
-	ppc64_runlatch_off();
-
-	lpaca = get_paca();
-
-	while (1) {
-		if (lpaca->lppaca.shared_proc) {
-			if (hvlpevent_is_pending())
-				process_iSeries_events();
-			if (!need_resched())
-				yield_shared_processor();
-		} else {
-			oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-			if (!oldval) {
-				set_thread_flag(TIF_POLLING_NRFLAG);
-
-				while (!need_resched()) {
-					HMT_medium();
-					if (hvlpevent_is_pending())
-						process_iSeries_events();
-					HMT_low();
-				}
-
-				HMT_medium();
-				clear_thread_flag(TIF_POLLING_NRFLAG);
-			} else {
-				set_need_resched();
-			}
-		}
-
-		ppc64_runlatch_on();
-		schedule();
-		ppc64_runlatch_off();
-	}
-
-	return 0;
-}
-
-#else
-
-static int default_idle(void)
+int default_idle(void)
 {
 	long oldval;
 	unsigned int cpu = smp_processor_id();
@@ -134,7 +43,8 @@
 			set_thread_flag(TIF_POLLING_NRFLAG);
 
 			while (!need_resched() && !cpu_is_offline(cpu)) {
-				barrier();
+				ppc64_runlatch_off();
+
 				/*
 				 * Go into low thread priority and possibly
 				 * low power mode.
@@ -149,6 +59,7 @@
 			set_need_resched();
 		}
 
+		ppc64_runlatch_on();
 		schedule();
 		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
 			cpu_die();
@@ -157,127 +68,19 @@
 	return 0;
 }
 
-#ifdef CONFIG_PPC_PSERIES
-
-DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
-
-int dedicated_idle(void)
+int native_idle(void)
 {
-	long oldval;
-	struct paca_struct *lpaca = get_paca(), *ppaca;
-	unsigned long start_snooze;
-	unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
-	unsigned int cpu = smp_processor_id();
-
-	ppaca = &paca[cpu ^ 1];
-
 	while (1) {
-		/*
-		 * Indicate to the HV that we are idle. Now would be
-		 * a good time to find other work to dispatch.
-		 */
-		lpaca->lppaca.idle = 1;
+		ppc64_runlatch_off();
 
-		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-		if (!oldval) {
-			set_thread_flag(TIF_POLLING_NRFLAG);
-			start_snooze = __get_tb() +
-				*smt_snooze_delay * tb_ticks_per_usec;
-			while (!need_resched() && !cpu_is_offline(cpu)) {
-				/*
-				 * Go into low thread priority and possibly
-				 * low power mode.
-				 */
-				HMT_low();
-				HMT_very_low();
+		if (!need_resched())
+			power4_idle();
 
-				if (*smt_snooze_delay == 0 ||
-				    __get_tb() < start_snooze)
-					continue;
-
-				HMT_medium();
-
-				if (!(ppaca->lppaca.idle)) {
-					local_irq_disable();
-
-					/*
-					 * We are about to sleep the thread
-					 * and so wont be polling any
-					 * more.
-					 */
-					clear_thread_flag(TIF_POLLING_NRFLAG);
-
-					/*
-					 * SMT dynamic mode. Cede will result
-					 * in this thread going dormant, if the
-					 * partner thread is still doing work.
-					 * Thread wakes up if partner goes idle,
-					 * an interrupt is presented, or a prod
-					 * occurs.  Returning from the cede
-					 * enables external interrupts.
-					 */
-					if (!need_resched())
-						cede_processor();
-					else
-						local_irq_enable();
-				} else {
-					/*
-					 * Give the HV an opportunity at the
-					 * processor, since we are not doing
-					 * any work.
-					 */
-					poll_pending();
-				}
-			}
-
-			clear_thread_flag(TIF_POLLING_NRFLAG);
-		} else {
-			set_need_resched();
+		if (need_resched()) {
+			ppc64_runlatch_on();
+			schedule();
 		}
 
-		HMT_medium();
-		lpaca->lppaca.idle = 0;
-		schedule();
-		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-			cpu_die();
-	}
-	return 0;
-}
-
-static int shared_idle(void)
-{
-	struct paca_struct *lpaca = get_paca();
-	unsigned int cpu = smp_processor_id();
-
-	while (1) {
-		/*
-		 * Indicate to the HV that we are idle. Now would be
-		 * a good time to find other work to dispatch.
-		 */
-		lpaca->lppaca.idle = 1;
-
-		while (!need_resched() && !cpu_is_offline(cpu)) {
-			local_irq_disable();
-
-			/*
-			 * Yield the processor to the hypervisor.  We return if
-			 * an external interrupt occurs (which are driven prior
-			 * to returning here) or if a prod occurs from another 
-			 * processor. When returning here, external interrupts
-			 * are enabled.
-			 *
-			 * Check need_resched() again with interrupts disabled
-			 * to avoid a race.
-			 */
-			if (!need_resched())
-				cede_processor();
-			else
-				local_irq_enable();
-		}
-
-		HMT_medium();
-		lpaca->lppaca.idle = 0;
-		schedule();
 		if (cpu_is_offline(smp_processor_id()) &&
 		    system_state == SYSTEM_RUNNING)
 			cpu_die();
@@ -286,29 +89,10 @@
 	return 0;
 }
 
-#endif /* CONFIG_PPC_PSERIES */
-
-static int native_idle(void)
-{
-	while(1) {
-		/* check CPU type here */
-		if (!need_resched())
-			power4_idle();
-		if (need_resched())
-			schedule();
-
-		if (cpu_is_offline(raw_smp_processor_id()) &&
-		    system_state == SYSTEM_RUNNING)
-			cpu_die();
-	}
-	return 0;
-}
-
-#endif /* CONFIG_PPC_ISERIES */
-
 void cpu_idle(void)
 {
-	idle_loop();
+	BUG_ON(NULL == ppc_md.idle_loop);
+	ppc_md.idle_loop();
 }
 
 int powersave_nap;
@@ -342,42 +126,3 @@
 }
 __initcall(register_powersave_nap_sysctl);
 #endif
-
-int idle_setup(void)
-{
-	/*
-	 * Move that junk to each platform specific file, eventually define
-	 * a pSeries_idle for shared processor stuff
-	 */
-#ifdef CONFIG_PPC_ISERIES
-	idle_loop = iSeries_idle;
-	return 1;
-#else
-	idle_loop = default_idle;
-#endif
-#ifdef CONFIG_PPC_PSERIES
-	if (systemcfg->platform & PLATFORM_PSERIES) {
-		if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
-			if (get_paca()->lppaca.shared_proc) {
-				printk(KERN_INFO "Using shared processor idle loop\n");
-				idle_loop = shared_idle;
-			} else {
-				printk(KERN_INFO "Using dedicated idle loop\n");
-				idle_loop = dedicated_idle;
-			}
-		} else {
-			printk(KERN_INFO "Using default idle loop\n");
-			idle_loop = default_idle;
-		}
-	}
-#endif /* CONFIG_PPC_PSERIES */
-#ifndef CONFIG_PPC_ISERIES
-	if (systemcfg->platform == PLATFORM_POWERMAC ||
-	    systemcfg->platform == PLATFORM_MAPLE) {
-		printk(KERN_INFO "Using native/NAP idle loop\n");
-		idle_loop = native_idle;
-	}
-#endif /* CONFIG_PPC_ISERIES */
-
-	return 1;
-}
diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c
index da8900b..bb55b5a 100644
--- a/arch/ppc64/kernel/maple_setup.c
+++ b/arch/ppc64/kernel/maple_setup.c
@@ -177,6 +177,8 @@
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
+
+	printk(KERN_INFO "Using native/NAP idle loop\n");
 }
 
 /* 
@@ -297,4 +299,5 @@
        	.get_rtc_time		= maple_get_rtc_time,
       	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= maple_progress,
+	.idle_loop		= native_idle,
 };
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index f3dea0c..59f4f99 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -1124,9 +1124,11 @@
 	.llong .compat_sys_mq_getsetattr
 	.llong .compat_sys_kexec_load
 	.llong .sys32_add_key
-	.llong .sys32_request_key
+	.llong .sys32_request_key	/* 270 */
 	.llong .compat_sys_keyctl
 	.llong .compat_sys_waitid
+	.llong .sys32_ioprio_set
+	.llong .sys32_ioprio_get
 
 	.balign 8
 _GLOBAL(sys_call_table)
@@ -1403,3 +1405,5 @@
 	.llong .sys_request_key		/* 270 */
 	.llong .sys_keyctl
 	.llong .sys_waitid
+	.llong .sys_ioprio_set
+	.llong .sys_ioprio_get
diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c
index 66bd5ab7..b80e819 100644
--- a/arch/ppc64/kernel/of_device.c
+++ b/arch/ppc64/kernel/of_device.c
@@ -3,6 +3,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <asm/errno.h>
 #include <asm/of_device.h>
 
@@ -15,20 +16,20 @@
  * Used by a driver to check whether an of_device present in the
  * system is in its list of supported devices.
  */
-const struct of_match * of_match_device(const struct of_match *matches,
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
 					const struct of_device *dev)
 {
 	if (!dev->node)
 		return NULL;
-	while (matches->name || matches->type || matches->compatible) {
+	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
 		int match = 1;
-		if (matches->name && matches->name != OF_ANY_MATCH)
+		if (matches->name[0])
 			match &= dev->node->name
 				&& !strcmp(matches->name, dev->node->name);
-		if (matches->type && matches->type != OF_ANY_MATCH)
+		if (matches->type[0])
 			match &= dev->node->type
 				&& !strcmp(matches->type, dev->node->type);
-		if (matches->compatible && matches->compatible != OF_ANY_MATCH)
+		if (matches->compatible[0])
 			match &= device_is_compatible(dev->node,
 				matches->compatible);
 		if (match)
@@ -42,7 +43,7 @@
 {
 	struct of_device * of_dev = to_of_device(dev);
 	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-	const struct of_match * matches = of_drv->match_table;
+	const struct of_device_id * matches = of_drv->match_table;
 
 	if (!matches)
 		return 0;
@@ -75,7 +76,7 @@
 	int error = -ENODEV;
 	struct of_platform_driver *drv;
 	struct of_device *of_dev;
-	const struct of_match *match;
+	const struct of_device_id *match;
 
 	drv = to_of_platform_driver(dev->driver);
 	of_dev = to_of_device(dev);
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c
index 44d9af7..5bec956 100644
--- a/arch/ppc64/kernel/pSeries_setup.c
+++ b/arch/ppc64/kernel/pSeries_setup.c
@@ -19,6 +19,7 @@
 #undef DEBUG
 
 #include <linux/config.h>
+#include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -82,6 +83,9 @@
 extern void pSeries_system_reset_exception(struct pt_regs *regs);
 extern int pSeries_machine_check_exception(struct pt_regs *regs);
 
+static int pseries_shared_idle(void);
+static int pseries_dedicated_idle(void);
+
 static volatile void __iomem * chrp_int_ack_special;
 struct mpic *pSeries_mpic;
 
@@ -229,6 +233,20 @@
 
 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
 		vpa_init(boot_cpuid);
+
+	/* Choose an idle loop */
+	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+		if (get_paca()->lppaca.shared_proc) {
+			printk(KERN_INFO "Using shared processor idle loop\n");
+			ppc_md.idle_loop = pseries_shared_idle;
+		} else {
+			printk(KERN_INFO "Using dedicated idle loop\n");
+			ppc_md.idle_loop = pseries_dedicated_idle;
+		}
+	} else {
+		printk(KERN_INFO "Using default idle loop\n");
+		ppc_md.idle_loop = default_idle;
+	}
 }
 
 static int __init pSeries_init_panel(void)
@@ -418,6 +436,144 @@
 	return 1;
 }
 
+DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
+
+static inline void dedicated_idle_sleep(unsigned int cpu)
+{
+	struct paca_struct *ppaca = &paca[cpu ^ 1];
+
+	/* Only sleep if the other thread is not idle */
+	if (!(ppaca->lppaca.idle)) {
+		local_irq_disable();
+
+		/*
+		 * We are about to sleep the thread and so wont be polling any
+		 * more.
+		 */
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+
+		/*
+		 * SMT dynamic mode. Cede will result in this thread going
+		 * dormant, if the partner thread is still doing work.  Thread
+		 * wakes up if partner goes idle, an interrupt is presented, or
+		 * a prod occurs.  Returning from the cede enables external
+		 * interrupts.
+		 */
+		if (!need_resched())
+			cede_processor();
+		else
+			local_irq_enable();
+	} else {
+		/*
+		 * Give the HV an opportunity at the processor, since we are
+		 * not doing any work.
+		 */
+		poll_pending();
+	}
+}
+
+static int pseries_dedicated_idle(void)
+{
+	long oldval;
+	struct paca_struct *lpaca = get_paca();
+	unsigned int cpu = smp_processor_id();
+	unsigned long start_snooze;
+	unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
+
+	while (1) {
+		/*
+		 * Indicate to the HV that we are idle. Now would be
+		 * a good time to find other work to dispatch.
+		 */
+		lpaca->lppaca.idle = 1;
+
+		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+		if (!oldval) {
+			set_thread_flag(TIF_POLLING_NRFLAG);
+
+			start_snooze = __get_tb() +
+				*smt_snooze_delay * tb_ticks_per_usec;
+
+			while (!need_resched() && !cpu_is_offline(cpu)) {
+				ppc64_runlatch_off();
+
+				/*
+				 * Go into low thread priority and possibly
+				 * low power mode.
+				 */
+				HMT_low();
+				HMT_very_low();
+
+				if (*smt_snooze_delay != 0 &&
+				    __get_tb() > start_snooze) {
+					HMT_medium();
+					dedicated_idle_sleep(cpu);
+				}
+
+			}
+
+			HMT_medium();
+			clear_thread_flag(TIF_POLLING_NRFLAG);
+		} else {
+			set_need_resched();
+		}
+
+		lpaca->lppaca.idle = 0;
+		ppc64_runlatch_on();
+
+		schedule();
+
+		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+			cpu_die();
+	}
+}
+
+static int pseries_shared_idle(void)
+{
+	struct paca_struct *lpaca = get_paca();
+	unsigned int cpu = smp_processor_id();
+
+	while (1) {
+		/*
+		 * Indicate to the HV that we are idle. Now would be
+		 * a good time to find other work to dispatch.
+		 */
+		lpaca->lppaca.idle = 1;
+
+		while (!need_resched() && !cpu_is_offline(cpu)) {
+			local_irq_disable();
+			ppc64_runlatch_off();
+
+			/*
+			 * Yield the processor to the hypervisor.  We return if
+			 * an external interrupt occurs (which are driven prior
+			 * to returning here) or if a prod occurs from another
+			 * processor. When returning here, external interrupts
+			 * are enabled.
+			 *
+			 * Check need_resched() again with interrupts disabled
+			 * to avoid a race.
+			 */
+			if (!need_resched())
+				cede_processor();
+			else
+				local_irq_enable();
+
+			HMT_medium();
+		}
+
+		lpaca->lppaca.idle = 0;
+		ppc64_runlatch_on();
+
+		schedule();
+
+		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+			cpu_die();
+	}
+
+	return 0;
+}
+
 struct machdep_calls __initdata pSeries_md = {
 	.probe			= pSeries_probe,
 	.setup_arch		= pSeries_setup_arch,
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
index 6cf03d3..3013cdb 100644
--- a/arch/ppc64/kernel/pmac_setup.c
+++ b/arch/ppc64/kernel/pmac_setup.c
@@ -186,6 +186,8 @@
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
+
+	printk(KERN_INFO "Using native/NAP idle loop\n");
 }
 
 #ifdef CONFIG_SCSI
@@ -507,5 +509,6 @@
       	.calibrate_decr		= pmac_calibrate_decr,
 	.feature_call		= pmac_do_feature_call,
 	.progress		= pmac_progress,
-	.check_legacy_ioport	= pmac_check_legacy_ioport
+	.check_legacy_ioport	= pmac_check_legacy_ioport,
+	.idle_loop		= native_idle,
 };
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
index d5e4866..d1b33f0 100644
--- a/arch/ppc64/kernel/setup.c
+++ b/arch/ppc64/kernel/setup.c
@@ -96,7 +96,6 @@
 extern unsigned long klimit;
 
 extern void mm_init_ppc64(void);
-extern int  idle_setup(void);
 extern void stab_initialize(unsigned long stab);
 extern void htab_initialize(void);
 extern void early_init_devtree(void *flat_dt);
@@ -1081,8 +1080,11 @@
 
 	ppc_md.setup_arch();
 
-	/* Select the correct idle loop for the platform. */
-	idle_setup();
+	/* Use the default idle loop if the platform hasn't provided one. */
+	if (NULL == ppc_md.idle_loop) {
+		ppc_md.idle_loop = default_idle;
+		printk(KERN_INFO "Using default idle loop\n");
+	}
 
 	paging_init();
 	ppc64_boot_msg(0x15, "Setup Done");
diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
index 118436e..2066190 100644
--- a/arch/ppc64/kernel/sys_ppc32.c
+++ b/arch/ppc64/kernel/sys_ppc32.c
@@ -30,47 +30,26 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
-#include <linux/slab.h>
-#include <linux/uio.h>
-#include <linux/aio.h>
-#include <linux/nfs_fs.h>
-#include <linux/module.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/nfsd/nfsd.h>
-#include <linux/nfsd/cache.h>
-#include <linux/nfsd/xdr.h>
-#include <linux/nfsd/syscall.h>
 #include <linux/poll.h>
 #include <linux/personality.h>
 #include <linux/stat.h>
-#include <linux/filter.h>
-#include <linux/highmem.h>
-#include <linux/highuid.h>
 #include <linux/mman.h>
-#include <linux/ipv6.h>
 #include <linux/in.h>
-#include <linux/icmpv6.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/sysctl.h>
 #include <linux/binfmts.h>
-#include <linux/dnotify.h>
 #include <linux/security.h>
 #include <linux/compat.h>
 #include <linux/ptrace.h>
-#include <linux/aio_abi.h>
 #include <linux/elf.h>
 
-#include <net/scm.h>
-#include <net/sock.h>
-
 #include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/ipc.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/semaphore.h>
-#include <asm/ppcdebug.h>
 #include <asm/time.h>
 #include <asm/mmu_context.h>
 #include <asm/systemcfg.h>
@@ -350,8 +329,6 @@
 	return ret;
 }
 
-
-/* These are here just in case some old sparc32 binary calls it. */
 asmlinkage long sys32_pause(void)
 {
 	current->state = TASK_INTERRUPTIBLE;
@@ -360,8 +337,6 @@
 	return -ERESTARTNOHAND;
 }
 
-
-
 static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
 {
 	long usec;
@@ -847,16 +822,6 @@
 }
 
 
-/* Note: it is necessary to treat which and who as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_getpriority(u32 which, u32 who)
-{
-	return sys_getpriority((int)which, (int)who);
-}
-
 
 /* Note: it is necessary to treat pid as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
@@ -1048,6 +1013,11 @@
 	return sys_setpgid((int)pid, (int)pgid);
 }
 
+long sys32_getpriority(u32 which, u32 who)
+{
+	/* sign extend which and who */
+	return sys_getpriority((int)which, (int)who);
+}
 
 long sys32_setpriority(u32 which, u32 who, u32 niceval)
 {
@@ -1055,6 +1025,18 @@
 	return sys_setpriority((int)which, (int)who, (int)niceval);
 }
 
+long sys32_ioprio_get(u32 which, u32 who)
+{
+	/* sign extend which and who */
+	return sys_ioprio_get((int)which, (int)who);
+}
+
+long sys32_ioprio_set(u32 which, u32 who, u32 ioprio)
+{
+	/* sign extend which, who and ioprio */
+	return sys_ioprio_set((int)which, (int)who, (int)ioprio);
+}
+
 /* Note: it is necessary to treat newmask as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -1273,8 +1255,6 @@
 			     (u64)len_high << 32 | len_low, advice);
 }
 
-extern asmlinkage long sys_timer_create(clockid_t, sigevent_t __user *, timer_t __user *);
-
 long ppc32_timer_create(clockid_t clock,
 			struct compat_sigevent __user *ev32,
 			timer_t __user *timer_id)
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c
index 2f704a2..02b8ac4 100644
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/ppc64/kernel/sysfs.c
@@ -112,7 +112,6 @@
 	unsigned long hid0;
 #ifdef CONFIG_PPC_PSERIES
 	unsigned long set, reset;
-	int ret;
 #endif /* CONFIG_PPC_PSERIES */
 
 	/* Only need to enable them once */
@@ -145,11 +144,7 @@
 	case PLATFORM_PSERIES_LPAR:
 		set = 1UL << 63;
 		reset = 0;
-		ret = plpar_hcall_norets(H_PERFMON, set, reset);
-		if (ret)
-			printk(KERN_ERR "H_PERFMON call on cpu %u "
-			       "returned %d\n",
-			       smp_processor_id(), ret);
+		plpar_hcall_norets(H_PERFMON, set, reset);
 		break;
 #endif /* CONFIG_PPC_PSERIES */
 
@@ -161,13 +156,6 @@
 	/* instruct hypervisor to maintain PMCs */
 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
 		get_paca()->lppaca.pmcregs_in_use = 1;
-
-	/*
-	 * On SMT machines we have to set the run latch in the ctrl register
-	 * in order to make PMC6 spin.
-	 */
-	if (cpu_has_feature(CPU_FTR_SMT))
-		ppc64_runlatch_on();
 #endif /* CONFIG_PPC_PSERIES */
 }
 
diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S
index 11290c9..6f87a91 100644
--- a/arch/ppc64/kernel/vdso32/vdso32.lds.S
+++ b/arch/ppc64/kernel/vdso32/vdso32.lds.S
@@ -40,9 +40,9 @@
   .gcc_except_table	: { *(.gcc_except_table) }
   .fixup		: { *(.fixup) }
 
-  .got ALIGN(4)		: { *(.got.plt) *(.got) }
-
   .dynamic		: { *(.dynamic) }		:text	:dynamic
+  .got : { *(.got) }
+  .plt : { *(.plt) }
 
   _end = .;
   __end = .;
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 928ffeb..025f451 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -57,11 +57,11 @@
 /*180*/	.long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_ni_syscall
 /*185*/	.long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
 /*190*/	.long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl
-/*195*/	.long sys_epoll_wait, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
+/*195*/	.long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
 /*205*/	.long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
 /*210*/	.long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
-/*215*/	.long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*215*/	.long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex
 /*220*/	.long sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
 /*225*/	.long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16
 /*230*/	.long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_statfs64
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index d78bc13..6a47336 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -43,6 +43,25 @@
 
 endchoice
 
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS
+	default y
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y. Only embedded should say N here.
+
+source kernel/Kconfig.hz
+
 source "init/Kconfig"
 
 config SYSVIPC_COMPAT
diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S
index b73a3c8..5385228 100644
--- a/arch/sparc64/kernel/dtlb_backend.S
+++ b/arch/sparc64/kernel/dtlb_backend.S
@@ -16,7 +16,7 @@
 #elif PAGE_SHIFT == 19
 #define SZ_BITS		_PAGE_SZ512K
 #elif PAGE_SHIFT == 22
-#define SZ_BITS		_PAGE_SZ4M
+#define SZ_BITS		_PAGE_SZ4MB
 #endif
 
 #define VALID_SZ_BITS	(_PAGE_VALID | SZ_BITS)
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index d3973d8..d781f10 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -22,8 +22,6 @@
 #include <asm/estate.h>
 #include <asm/auxio.h>
 
-/* #define SYSCALL_TRACING	1 */
-
 #define curptr      g6
 
 #define NR_SYSCALLS 284      /* Each OS is different... */
@@ -1554,11 +1552,12 @@
 		nop
 		.align		32
 1:		ldx		[%curptr + TI_FLAGS], %l5
-		andcc		%l5, _TIF_SYSCALL_TRACE, %g0
+		andcc		%l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
 		be,pt		%icc, rtrap
 		 clr		%l6
+		add		%sp, PTREGS_OFF, %o0
 		call		syscall_trace
-		 nop
+		 mov		1, %o1
 
 		ba,pt		%xcc, rtrap
 		 clr		%l6
@@ -1642,18 +1641,20 @@
 	 or		%l7, %lo(sys_ni_syscall), %l7
 
 linux_syscall_trace32:
+	add		%sp, PTREGS_OFF, %o0
 	call		syscall_trace
-	 nop
+	 clr		%o1
 	srl		%i0, 0, %o0
-	mov		%i4, %o4
+	srl		%i4, 0, %o4
 	srl		%i1, 0, %o1
 	srl		%i2, 0, %o2
 	b,pt		%xcc, 2f
 	 srl		%i3, 0, %o3
 
 linux_syscall_trace:
+	add		%sp, PTREGS_OFF, %o0
 	call		syscall_trace
-	 nop
+	 clr		%o1
 	mov		%i0, %o0
 	mov		%i1, %o1
 	mov		%i2, %o2
@@ -1671,11 +1672,6 @@
 	bgeu,pn		%xcc, linux_sparc_ni_syscall		! CTI
 	 srl		%i0, 0, %o0				! IEU0
 	sll		%g1, 2, %l4				! IEU0	Group
-#ifdef SYSCALL_TRACING
-	call		syscall_trace_entry
-	 add		%sp, PTREGS_OFF, %o0
-	srl		%i0, 0, %o0
-#endif
 	srl		%i4, 0, %o4				! IEU1
 	lduw		[%l7 + %l4], %l7			! Load
 	srl		%i1, 0, %o1				! IEU0	Group
@@ -1683,7 +1679,7 @@
 
 	srl		%i5, 0, %o5				! IEU1
 	srl		%i2, 0, %o2				! IEU0	Group
-	andcc		%l0, _TIF_SYSCALL_TRACE, %g0		! IEU0	Group
+	andcc		%l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
 	bne,pn		%icc, linux_syscall_trace32		! CTI
 	 mov		%i0, %l5				! IEU1
 	call		%l7					! CTI	Group brk forced
@@ -1699,11 +1695,6 @@
 	bgeu,pn		%xcc, linux_sparc_ni_syscall		! CTI
 	 mov		%i0, %o0				! IEU0
 	sll		%g1, 2, %l4				! IEU0	Group
-#ifdef SYSCALL_TRACING
-	call		syscall_trace_entry
-	 add		%sp, PTREGS_OFF, %o0
-	mov		%i0, %o0
-#endif
 	mov		%i1, %o1				! IEU1
 	lduw		[%l7 + %l4], %l7			! Load
 4:	mov		%i2, %o2				! IEU0	Group
@@ -1711,7 +1702,7 @@
 
 	mov		%i3, %o3				! IEU1
 	mov		%i4, %o4				! IEU0	Group
-	andcc		%l0, _TIF_SYSCALL_TRACE, %g0		! IEU1	Group+1 bubble
+	andcc		%l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
 	bne,pn		%icc, linux_syscall_trace		! CTI	Group
 	 mov		%i0, %l5				! IEU0
 2:	call		%l7					! CTI	Group brk forced
@@ -1720,12 +1711,6 @@
 
 3:	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 ret_sys_call:
-#ifdef SYSCALL_TRACING
-	mov		%o0, %o1
-	call		syscall_trace_exit
-	 add		%sp, PTREGS_OFF, %o0
-	mov		%o1, %o0
-#endif
 	ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
 	ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
 	sra		%o0, 0, %o0
@@ -1745,7 +1730,7 @@
 1:
 	cmp		%o0, -ERESTART_RESTARTBLOCK
 	bgeu,pn		%xcc, 1f
-	 andcc		%l0, _TIF_SYSCALL_TRACE, %l6	
+	 andcc		%l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6
 80:
 	/* System call success, clear Carry condition code. */
 	andn		%g3, %g2, %g3
@@ -1760,7 +1745,7 @@
 	/* System call failure, set Carry condition code.
 	 * Also, get abs(errno) to return to the process.
 	 */
-	andcc		%l0, _TIF_SYSCALL_TRACE, %l6	
+	andcc		%l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6	
 	sub		%g0, %o0, %o0
 	or		%g3, %g2, %g3
 	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
@@ -1773,8 +1758,9 @@
 	b,pt		%xcc, rtrap
 	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 linux_syscall_trace2:
+	add		%sp, PTREGS_OFF, %o0
 	call		syscall_trace
-	 nop
+	 mov		1, %o1
 	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	ba,pt		%xcc, rtrap
 	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 74a2e08..daa2fb9 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -917,7 +917,8 @@
 			int count, int *eof, void *data)
 {
 	struct ino_bucket *bp = ivector_table + (long)data;
-	struct irqaction *ap = bp->irq_info;
+	struct irq_desc *desc = bp->irq_info;
+	struct irqaction *ap = desc->action;
 	cpumask_t mask;
 	int len;
 
@@ -935,11 +936,13 @@
 static inline void set_intr_affinity(int irq, cpumask_t hw_aff)
 {
 	struct ino_bucket *bp = ivector_table + irq;
+	struct irq_desc *desc = bp->irq_info;
+	struct irqaction *ap = desc->action;
 
 	/* Users specify affinity in terms of hw cpu ids.
 	 * As soon as we do this, handler_irq() might see and take action.
 	 */
-	put_smpaff_in_irqaction((struct irqaction *)bp->irq_info, hw_aff);
+	put_smpaff_in_irqaction(ap, hw_aff);
 
 	/* Migration is simply done by the next cpu to service this
 	 * interrupt.
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 52f14e3..533104c 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -4,6 +4,8 @@
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  */
 
+#define __KERNEL_SYSCALLS__
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -17,7 +19,6 @@
 #include <asm/ebus.h>
 #include <asm/auxio.h>
 
-#define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
 /*
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 80a76e2..23ad839 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -19,6 +19,8 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/security.h>
+#include <linux/seccomp.h>
+#include <linux/audit.h>
 #include <linux/signal.h>
 
 #include <asm/asi.h>
@@ -628,15 +630,27 @@
 	unlock_kernel();
 }
 
-asmlinkage void syscall_trace(void)
+asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
 {
-#ifdef DEBUG_PTRACE
-	printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
-#endif
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
+	/* do the secure computing check first */
+	secure_computing(regs->u_regs[UREG_G1]);
+
+	if (unlikely(current->audit_context) && syscall_exit_p) {
+		unsigned long tstate = regs->tstate;
+		int result = AUDITSC_SUCCESS;
+
+		if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+			result = AUDITSC_FAILURE;
+
+		audit_syscall_exit(current, result, regs->u_regs[UREG_I0]);
+	}
+
 	if (!(current->ptrace & PT_PTRACED))
-		return;
+		goto out;
+
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		goto out;
+
 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 				 ? 0x80 : 0));
 
@@ -645,12 +659,20 @@
 	 * for normal use.  strace only continues with a signal if the
 	 * stopping signal is not SIGTRAP.  -brl
 	 */
-#ifdef DEBUG_PTRACE
-	printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
-		current->pid, current->exit_code);
-#endif
 	if (current->exit_code) {
-		send_sig (current->exit_code, current, 1);
+		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
+
+out:
+	if (unlikely(current->audit_context) && !syscall_exit_p)
+		audit_syscall_entry(current,
+				    (test_thread_flag(TIF_32BIT) ?
+				     AUDIT_ARCH_SPARC :
+				     AUDIT_ARCH_SPARC64),
+				    regs->u_regs[UREG_G1],
+				    regs->u_regs[UREG_I0],
+				    regs->u_regs[UREG_I1],
+				    regs->u_regs[UREG_I2],
+				    regs->u_regs[UREG_I3]);
 }
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index e5b9c7a..441fc2e 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -45,8 +45,8 @@
 /* Please don't make this stuff initdata!!!  --DaveM */
 static unsigned char boot_cpu_id;
 
-cpumask_t cpu_online_map = CPU_MASK_NONE;
-cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+cpumask_t cpu_online_map = CPU_MASK_NONE __read_mostly;
+cpumask_t phys_cpu_present_map = CPU_MASK_NONE __read_mostly;
 static cpumask_t smp_commenced_mask;
 static cpumask_t cpu_callout_map;
 
@@ -155,7 +155,7 @@
 	panic("SMP bolixed\n");
 }
 
-static unsigned long current_tick_offset;
+static unsigned long current_tick_offset __read_mostly;
 
 /* This tick register synchronization scheme is taken entirely from
  * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit.
@@ -1193,8 +1193,8 @@
 {
 }
 
-unsigned long __per_cpu_base;
-unsigned long __per_cpu_shift;
+unsigned long __per_cpu_base __read_mostly;
+unsigned long __per_cpu_shift __read_mostly;
 
 EXPORT_SYMBOL(__per_cpu_base);
 EXPORT_SYMBOL(__per_cpu_shift);
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 56cd96f..9202d92 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -79,7 +79,7 @@
 extern void rtrap(void);
 extern void show_regs(struct pt_regs *);
 extern void solaris_syscall(void);
-extern void syscall_trace(void);
+extern void syscall_trace(struct pt_regs *, int);
 extern u32 sunos_sys_table[], sys_call_table32[];
 extern void tl0_solaris(void);
 extern void sys_sigsuspend(void);
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index 5a95e98..5f9e4fa 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -135,6 +135,8 @@
 SIGN3(sys32_socketpair, sys_socketpair, %o0, %o1, %o2)
 SIGN1(sys32_getpeername, sys_getpeername, %o0)
 SIGN1(sys32_getsockname, sys_getsockname, %o0)
+SIGN2(sys32_ioprio_get, sys_ioprio_get, %o0, %o1)
+SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2)
 
 	.globl		sys32_mmap2
 sys32_mmap2:
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index a5e36a4..bceb91a 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -59,11 +59,11 @@
 /*180*/	.word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
 	.word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sparc64_newuname
 /*190*/	.word sys32_init_module, sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl
-	.word sys32_epoll_wait, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
+	.word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
 	.word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64
 /*210*/	.word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo
-	.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+	.word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, sys32_adjtimex
 /*220*/	.word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid
 	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
 /*230*/	.word sys32_select, compat_sys_time, sys_nis_syscall, compat_sys_stime, compat_sys_statfs64
@@ -125,11 +125,11 @@
 /*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_ni_syscall
 	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname
 /*190*/	.word sys_init_module, sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl
-	.word sys_epoll_wait, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
+	.word sys_epoll_wait, sys_ioprio_set, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
 	.word sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
 /*210*/	.word sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
-	.word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex
+	.word sys_ipc, sys_nis_syscall, sys_clone, sys_ioprio_get, sys_adjtimex
 /*220*/	.word sys_nis_syscall, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
 	.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
 /*230*/	.word sys_select, sys_nis_syscall, sys_nis_syscall, sys_stime, sys_statfs64
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index b40db38..362b9c2 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -73,7 +73,7 @@
 	.get_tick	= dummy_get_tick,
 };
 
-struct sparc64_tick_ops *tick_ops = &dummy_tick_ops;
+struct sparc64_tick_ops *tick_ops __read_mostly = &dummy_tick_ops;
 
 #define TICK_PRIV_BIT	(1UL << 63)
 
@@ -195,7 +195,7 @@
 	return new_tick;
 }
 
-static struct sparc64_tick_ops tick_operations = {
+static struct sparc64_tick_ops tick_operations __read_mostly = {
 	.init_tick	=	tick_init_tick,
 	.get_tick	=	tick_get_tick,
 	.get_compare	=	tick_get_compare,
@@ -276,7 +276,7 @@
 	return new_compare;
 }
 
-static struct sparc64_tick_ops stick_operations = {
+static struct sparc64_tick_ops stick_operations __read_mostly = {
 	.init_tick	=	stick_init_tick,
 	.get_tick	=	stick_get_tick,
 	.get_compare	=	stick_get_compare,
@@ -422,7 +422,7 @@
 	return val;
 }
 
-static struct sparc64_tick_ops hbtick_operations = {
+static struct sparc64_tick_ops hbtick_operations __read_mostly = {
 	.init_tick	=	hbtick_init_tick,
 	.get_tick	=	hbtick_get_tick,
 	.get_compare	=	hbtick_get_compare,
@@ -437,10 +437,9 @@
  * NOTE: On SUN5 systems the ticker interrupt comes in using 2
  *       interrupts, one at level14 and one with softint bit 0.
  */
-unsigned long timer_tick_offset;
-unsigned long timer_tick_compare;
+unsigned long timer_tick_offset __read_mostly;
 
-static unsigned long timer_ticks_per_nsec_quotient;
+static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
 
 #define TICK_SIZE (tick_nsec / 1000)
 
@@ -464,7 +463,7 @@
 
 static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	unsigned long ticks, pstate;
+	unsigned long ticks, compare, pstate;
 
 	write_seqlock(&xtime_lock);
 
@@ -483,14 +482,14 @@
 				     : "=r" (pstate)
 				     : "i" (PSTATE_IE));
 
-		timer_tick_compare = tick_ops->add_compare(timer_tick_offset);
+		compare = tick_ops->add_compare(timer_tick_offset);
 		ticks = tick_ops->get_tick();
 
 		/* Restore PSTATE_IE. */
 		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 				     : /* no outputs */
 				     : "r" (pstate));
-	} while (time_after_eq(ticks, timer_tick_compare));
+	} while (time_after_eq(ticks, compare));
 
 	timer_check_rtc();
 
@@ -506,11 +505,6 @@
 
 	do_timer(regs);
 
-	/*
-	 * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
-	 */
-	timer_tick_compare = tick_ops->get_compare() + timer_tick_offset;
-
 	timer_check_rtc();
 
 	write_sequnlock(&xtime_lock);
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 382fd67..950423d 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -32,6 +32,8 @@
   .data1   : { *(.data1) }
   . = ALIGN(64);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  . = ALIGN(64);
+  .data.read_mostly : { *(.data.read_mostly) }
   _edata  =  .;
   PROVIDE (edata = .);
   .fixup   : { *(.fixup) }
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 3ffee7b..52e9375 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -34,22 +34,6 @@
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 
 /*
- * To debug kernel during syscall entry.
- */
-void syscall_trace_entry(struct pt_regs *regs)
-{
-	printk("scall entry: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
-}
-
-/*
- * To debug kernel during syscall exit.
- */
-void syscall_trace_exit(struct pt_regs *regs)
-{
-	printk("scall exit: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
-}
-
-/*
  * To debug kernel to catch accesses to certain virtual/physical addresses.
  * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
  * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses.
diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S
index 0cc9dad..4b6ae58 100644
--- a/arch/sparc64/solaris/entry64.S
+++ b/arch/sparc64/solaris/entry64.S
@@ -24,8 +24,9 @@
 
 	.text
 solaris_syscall_trace:
+	add		%sp, PTREGS_OFF, %o0
 	call		syscall_trace
-	 nop
+	 mov		0, %o1
 	srl		%i0, 0, %o0
 	mov		%i4, %o4
 	srl		%i1, 0, %o1
@@ -159,8 +160,10 @@
 	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4 
 
 solaris_syscall_trace2:
+	add		%sp, PTREGS_OFF, %o0
 	call		syscall_trace
-	 add		%l1, 0x4, %l2			/* npc = npc+4 */
+	 mov		1, %o1
+	add		%l1, 0x4, %l2			/* npc = npc+4 */
 	andcc		%l1, 1, %g0
 	bne,pn		%icc, 2b
 	 nop
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 9469e77..6682c78 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -128,7 +128,6 @@
 
 config HPPFS
 	tristate "HoneyPot ProcFS (EXPERIMENTAL)"
-	depends on BROKEN
 	help
 	hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
 	entries to be overridden, removed, or fabricated from the host.
@@ -141,8 +140,9 @@
 	You only need this if you are setting up a UML honeypot.  Otherwise,
 	it is safe to say 'N' here.
 
-	If you are actively using it, please ask for it to be fixed. In this
-	moment, it does not work on 2.6 (it works somehow on 2.4).
+	If you are actively using it, please report any problems, since it's
+	getting fixed. In this moment, it is experimental on 2.6 (it works on
+	2.4).
 
 config MCONSOLE
 	bool "Management console"
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386
index e41f374..27c18a8 100644
--- a/arch/um/Kconfig_i386
+++ b/arch/um/Kconfig_i386
@@ -19,6 +19,18 @@
 	memory.  All the memory that can't be mapped directly will be treated
 	as high memory.
 
+config STUB_CODE
+	hex
+	default 0xbfffe000
+
+config STUB_DATA
+	hex
+	default 0xbffff000
+
+config STUB_START
+	hex
+	default STUB_CODE
+
 config ARCH_HAS_SC_SIGNALS
 	bool
 	default y
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64
index f162f50..735a047 100644
--- a/arch/um/Kconfig_x86_64
+++ b/arch/um/Kconfig_x86_64
@@ -14,6 +14,18 @@
        bool
        default y
 
+config STUB_CODE
+	hex
+	default 0x7fbfffe000
+
+config STUB_DATA
+	hex
+	default 0x7fbffff000
+
+config STUB_START
+	hex
+	default STUB_CODE
+
 config ARCH_HAS_SC_SIGNALS
 	bool
 	default n
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 29e182d..3010590 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -8,7 +8,7 @@
   endif
 endif
 
-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
 ARCH_USER_CFLAGS :=
 
 ifneq ($(CONFIG_GPROF),y)
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 3214456..d80bd00 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -4,7 +4,7 @@
 SUBARCH_LIBS := arch/um/sys-x86_64/
 START := 0x60000000
 
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin
+CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
 ARCH_USER_CFLAGS := -D__x86_64__
 
 ELF_ARCH := i386:x86-64
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 4067c3a..80d30d1 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2
-# Sun Apr 24 19:46:10 2005
+# Linux kernel version: 2.6.12-rc6-mm1
+# Tue Jun 14 18:22:21 2005
 #
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_UML=y
@@ -13,23 +13,32 @@
 #
 # UML-specific options
 #
-CONFIG_MODE_TT=y
+# CONFIG_MODE_TT is not set
+# CONFIG_STATIC_LINK is not set
 CONFIG_MODE_SKAS=y
 CONFIG_UML_X86=y
 # CONFIG_64BIT is not set
 CONFIG_TOP_ADDR=0xc0000000
 # CONFIG_3_LEVEL_PGTABLES is not set
+CONFIG_STUB_CODE=0xbfffe000
+CONFIG_STUB_DATA=0xbffff000
+CONFIG_STUB_START=0xbfffe000
 CONFIG_ARCH_HAS_SC_SIGNALS=y
 CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
-CONFIG_LD_SCRIPT_STATIC=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_LD_SCRIPT_DYN=y
 CONFIG_NET=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
-CONFIG_HOSTFS=y
+# CONFIG_HOSTFS is not set
 CONFIG_MCONSOLE=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_HOST_2G_2G is not set
-# CONFIG_SMP is not set
 CONFIG_NEST_LEVEL=0
 CONFIG_KERNEL_HALF_GIGS=1
 # CONFIG_HIGHMEM is not set
@@ -63,6 +72,8 @@
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -81,6 +92,7 @@
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 
@@ -115,6 +127,7 @@
 CONFIG_SOUND=m
 CONFIG_HOSTAUDIO=m
 CONFIG_UML_RANDOM=y
+# CONFIG_MMAPPER is not set
 
 #
 # Block devices
@@ -176,6 +189,17 @@
 # CONFIG_INET_TUNNEL is not set
 CONFIG_IP_TCPDIAG=y
 # CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
 
@@ -206,11 +230,15 @@
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_KGDBOE is not set
 # CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -227,6 +255,7 @@
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
 CONFIG_SLIP=m
 # CONFIG_SLIP_COMPRESSED is not set
@@ -240,10 +269,12 @@
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
+# CONFIG_REISER4_FS is not set
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
@@ -256,6 +287,7 @@
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 CONFIG_QUOTA=y
 # CONFIG_QFMT_V1 is not set
 # CONFIG_QFMT_V2 is not set
@@ -265,6 +297,12 @@
 CONFIG_AUTOFS4_FS=m
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+# CONFIG_FUSE_FS is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=m
@@ -291,6 +329,8 @@
 # CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -319,6 +359,7 @@
 # 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
@@ -404,14 +445,15 @@
 # CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SLAB=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
-CONFIG_PT_PROXY=y
+# CONFIG_GPROF is not set
 # CONFIG_GCOV is not set
 # CONFIG_SYSCALL_DEBUG is not set
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 2bb4c4f..e0fdffa 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -663,11 +663,15 @@
 	return driver;
 }
 
+static spinlock_t winch_handler_lock;
+LIST_HEAD(winch_handlers);
+
 void lines_init(struct line *lines, int nlines)
 {
 	struct line *line;
 	int i;
 
+	spin_lock_init(&winch_handler_lock);
 	for(i = 0; i < nlines; i++){
 		line = &lines[i];
 		INIT_LIST_HEAD(&line->chan_list);
@@ -724,31 +728,30 @@
 	return IRQ_HANDLED;
 }
 
-DECLARE_MUTEX(winch_handler_sem);
-LIST_HEAD(winch_handlers);
-
 void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
 {
 	struct winch *winch;
 
-	down(&winch_handler_sem);
 	winch = kmalloc(sizeof(*winch), GFP_KERNEL);
 	if (winch == NULL) {
 		printk("register_winch_irq - kmalloc failed\n");
-		goto out;
+		return;
 	}
+
 	*winch = ((struct winch) { .list  	= LIST_HEAD_INIT(winch->list),
 				   .fd  	= fd,
 				   .tty_fd 	= tty_fd,
 				   .pid  	= pid,
 				   .tty 	= tty });
+
+	spin_lock(&winch_handler_lock);
 	list_add(&winch->list, &winch_handlers);
+	spin_unlock(&winch_handler_lock);
+
 	if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
 			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
 			  "winch", winch) < 0)
 		printk("register_winch_irq - failed to register IRQ\n");
- out:
-	up(&winch_handler_sem);
 }
 
 static void unregister_winch(struct tty_struct *tty)
@@ -756,7 +759,7 @@
 	struct list_head *ele;
 	struct winch *winch, *found = NULL;
 
-	down(&winch_handler_sem);
+	spin_lock(&winch_handler_lock);
 	list_for_each(ele, &winch_handlers){
 		winch = list_entry(ele, struct winch, list);
                 if(winch->tty == tty){
@@ -764,20 +767,25 @@
                         break;
                 }
         }
-
         if(found == NULL)
-                goto out;
+		goto err;
+
+	list_del(&winch->list);
+	spin_unlock(&winch_handler_lock);
 
         if(winch->pid != -1)
                 os_kill_process(winch->pid, 1);
 
         free_irq(WINCH_IRQ, winch);
-        list_del(&winch->list);
         kfree(winch);
- out:
-	up(&winch_handler_sem);
+
+	return;
+err:
+	spin_unlock(&winch_handler_lock);
 }
 
+/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
+ * order... are we sure that nothing else is done on the list? */
 static void winch_cleanup(void)
 {
 	struct list_head *ele;
@@ -786,6 +794,9 @@
 	list_for_each(ele, &winch_handlers){
 		winch = list_entry(ele, struct winch, list);
 		if(winch->fd != -1){
+			/* Why is this different from the above free_irq(),
+			 * which deactivates SIGIO? This searches the FD
+			 * somewhere else and removes it from the list... */
 			deactivate_fd(winch->fd, WINCH_IRQ);
 			os_close_file(winch->fd);
 		}
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
index 10c46c3..99d3ad4 100644
--- a/arch/um/include/mem.h
+++ b/arch/um/include/mem.h
@@ -13,6 +13,7 @@
 extern int is_remapped(void *virt);
 extern int physmem_remove_mapping(void *virt);
 extern void physmem_forget_descriptor(int fd);
+extern unsigned long to_phys(void *virt);
 
 #endif
 
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
index 8744abb..0a35e6d 100644
--- a/arch/um/include/registers.h
+++ b/arch/um/include/registers.h
@@ -14,6 +14,7 @@
 extern void save_registers(int pid, union uml_pt_regs *regs);
 extern void restore_registers(int pid, union uml_pt_regs *regs);
 extern void init_registers(int pid);
+extern void get_safe_registers(unsigned long * regs);
 
 #endif
 
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
index eca8066..899aa4b 100644
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -20,11 +20,24 @@
 #define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
 #define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
 #define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
+#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP)
 
 #define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
 
+#define REGS_SYSCALL_NR EAX /* This is used before a system call */
+#define REGS_SYSCALL_ARG1 EBX
+#define REGS_SYSCALL_ARG2 ECX
+#define REGS_SYSCALL_ARG3 EDX
+#define REGS_SYSCALL_ARG4 ESI
+#define REGS_SYSCALL_ARG5 EDI
+#define REGS_SYSCALL_ARG6 EBP
+
+#define REGS_IP_INDEX EIP
+#define REGS_SP_INDEX UESP
+
 #define PT_IP_OFFSET PT_OFFSET(EIP)
 #define PT_IP(regs) ((regs)[EIP])
+#define PT_SP_OFFSET PT_OFFSET(UESP)
 #define PT_SP(regs) ((regs)[UESP])
 
 #ifndef FRAME_SIZE
diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h
new file mode 100644
index 0000000..d3699fe
--- /dev/null
+++ b/arch/um/include/sysdep-i386/stub.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET EAX
+#define STUB_MMAP_NR __NR_mmap2
+#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+	long ret;
+
+	__asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+	__asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+	__asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+	__asm__("int $0x80;" : : : "%eax");
+	__asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :);
+	return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+	__asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+	return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+				 long arg4)
+{
+	__asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+	return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+				 long arg4, long arg5, long arg6)
+{
+	long ret;
+	__asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+	__asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+	__asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+	__asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+	__asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+	__asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi");
+	__asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; "
+		"int $0x80; popl %%ebp ; "
+		"movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax");
+	return(ret);
+}
+
+static inline void trap_myself(void)
+{
+	__asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
index 3172997..128faf0 100644
--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -55,6 +55,20 @@
 #define PTRACE_OLDSETOPTIONS 21
 #endif
 
+/* These are before the system call, so the the system call number is RAX
+ * rather than ORIG_RAX, and arg4 is R10 rather than RCX
+ */
+#define REGS_SYSCALL_NR PT_INDEX(RAX)
+#define REGS_SYSCALL_ARG1 PT_INDEX(RDI)
+#define REGS_SYSCALL_ARG2 PT_INDEX(RSI)
+#define REGS_SYSCALL_ARG3 PT_INDEX(RDX)
+#define REGS_SYSCALL_ARG4 PT_INDEX(R10)
+#define REGS_SYSCALL_ARG5 PT_INDEX(R8)
+#define REGS_SYSCALL_ARG6 PT_INDEX(R9)
+
+#define REGS_IP_INDEX PT_INDEX(RIP)
+#define REGS_SP_INDEX PT_INDEX(RSP)
+
 #endif
 
 /*
diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h
new file mode 100644
index 0000000..f599058
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/stub.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <sysdep/ptrace_user.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET PT_INDEX(RAX)
+#define STUB_MMAP_NR __NR_mmap
+#define MMAP_OFFSET(o) (o)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+	long ret;
+
+	__asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi");
+	__asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi");
+	__asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax");
+	__asm__("syscall;" : : : "%rax", "%r11", "%rcx");
+	__asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :);
+	return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+	__asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx");
+	return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+				 long arg4)
+{
+	__asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10");
+	return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+				 long arg4, long arg5, long arg6)
+{
+	__asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9");
+	__asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8");
+	return(stub_syscall4(syscall, arg1, arg2, arg3, arg4));
+}
+
+static inline void trap_myself(void)
+{
+	__asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
index f64ef77..17d7ef2 100644
--- a/arch/um/include/time_user.h
+++ b/arch/um/include/time_user.h
@@ -10,6 +10,7 @@
 extern void switch_timers(int to_real);
 extern void idle_sleep(int secs);
 extern void enable_timer(void);
+extern void prepare_timer(void * ptr);
 extern void disable_timer(void);
 extern unsigned long time_lock(void);
 extern void time_unlock(unsigned long);
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index da10972..c6f9628 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -37,31 +37,25 @@
 extern void mprotect_kernel_vm(int w);
 extern void force_flush_all(void);
 extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
-			     unsigned long end_addr, int force, int data,
-			     void (*do_ops)(int, struct host_vm_op *, int));
+                             unsigned long end_addr, int force,
+                             void (*do_ops)(union mm_context *,
+                                            struct host_vm_op *, int));
 extern int flush_tlb_kernel_range_common(unsigned long start,
 					 unsigned long end);
 
 extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
 		    int r, int w, int x, struct host_vm_op *ops, int index,
-		    int last_filled, int data,
-		    void (*do_ops)(int, struct host_vm_op *, int));
+                    int last_filled, union mm_context *mmu,
+                    void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                   int));
 extern int add_munmap(unsigned long addr, unsigned long len,
 		      struct host_vm_op *ops, int index, int last_filled,
-		      int data, void (*do_ops)(int, struct host_vm_op *, int));
+                      union mm_context *mmu,
+                      void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                     int));
 extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
 			int x, struct host_vm_op *ops, int index,
-			int last_filled, int data,
-			void (*do_ops)(int, struct host_vm_op *, int));
+                        int last_filled, union mm_context *mmu,
+                        void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                       int));
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 715b083..3942a5f 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -67,6 +67,12 @@
     *(.stub .text.* .gnu.linkonce.t.*)
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
+
+    . = ALIGN(4096);
+    __syscall_stub_start = .;
+    *(.__syscall_stub*)
+    __syscall_stub_end = .;
+    . = ALIGN(4096);
   } =0x90909090
   .fini           : {
     KEEP (*(.fini))
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 420e6d5..a24e3b7 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -353,6 +353,8 @@
 
 #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 
+extern int __syscall_stub_start, __binary_start;
+
 void setup_physmem(unsigned long start, unsigned long reserve_end,
 		   unsigned long len, unsigned long highmem)
 {
@@ -371,6 +373,12 @@
 		exit(1);
 	}
 
+	/* Special kludge - This page will be mapped in to userspace processes
+	 * from physmem_fd, so it needs to be written out there.
+	 */
+	os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
+	os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
+
 	bootmap_size = init_bootmem(pfn, pfn + delta);
 	free_bootmem(__pa(reserve_end) + bootmap_size,
 		     len - bootmap_size - reserve);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 1b5ef3e..c45a60e 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,6 +32,7 @@
 #include "uml-config.h"
 #include "choose-mode.h"
 #include "mode.h"
+#include "tempfile.h"
 #ifdef UML_CONFIG_MODE_SKAS
 #include "skas.h"
 #include "skas_ptrace.h"
@@ -358,11 +359,16 @@
 		kill(target, SIGIO);
 }
 
+int ptrace_faultinfo = 0;
+int proc_mm = 1;
+
+extern void *__syscall_stub_start, __syscall_stub_end;
+
 #ifdef UML_CONFIG_MODE_SKAS
-static inline int check_skas3_ptrace_support(void)
+static inline void check_skas3_ptrace_support(void)
 {
 	struct ptrace_faultinfo fi;
-	int pid, n, ret = 1;
+	int pid, n;
 
 	printf("Checking for the skas3 patch in the host...");
 	pid = start_ptraced_child();
@@ -374,33 +380,31 @@
 		else {
 			perror("not found");
 		}
-		ret = 0;
-	} else {
+	}
+	else {
+		ptrace_faultinfo = 1;
 		printf("found\n");
 	}
 
 	init_registers(pid);
 	stop_ptraced_child(pid, 1, 1);
-
-	return(ret);
 }
 
 int can_do_skas(void)
 {
-	int ret = 1;
-
 	printf("Checking for /proc/mm...");
 	if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
+		proc_mm = 0;
 		printf("not found\n");
-		ret = 0;
 		goto out;
-	} else {
+	}
+	else {
 		printf("found\n");
 	}
 
-	ret = check_skas3_ptrace_support();
 out:
-	return ret;
+	check_skas3_ptrace_support();
+	return 1;
 }
 #else
 int can_do_skas(void)
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index ff69c4b..d296d55 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,11 +3,14 @@
 # Licensed under the GPL
 #
 
-obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
+obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
 	syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
 
 subdir- := util
 
-USER_OBJS := process.o
+USER_OBJS := process.o clone.o
 
 include arch/um/scripts/Makefile.rules
+
+# clone.o is in the stub, so it can't be built with profiling
+$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
new file mode 100644
index 0000000..4dc55f1
--- /dev/null
+++ b/arch/um/kernel/skas/clone.c
@@ -0,0 +1,44 @@
+#include <sched.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#include "ptrace_user.h"
+#include "skas.h"
+#include "stub-data.h"
+#include "uml-config.h"
+#include "sysdep/stub.h"
+
+/* This is in a separate file because it needs to be compiled with any
+ * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
+ */
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_clone_handler(void)
+{
+	long err;
+	struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA;
+
+	err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
+			    UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 -
+			    sizeof(void *));
+	if(err != 0)
+		goto out;
+
+	err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
+	if(err)
+		goto out;
+
+	err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
+			    (long) &from->timer, 0);
+	if(err)
+		goto out;
+
+	err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE,
+			    PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
+			    from->fd, from->offset);
+ out:
+	/* save current result. Parent: pid; child: retcode of mmap */
+	from->err = err;
+	trap_myself();
+}
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
index c6b4d5d..77ed7bb 100644
--- a/arch/um/kernel/skas/exec_kern.c
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -18,7 +18,7 @@
 void flush_thread_skas(void)
 {
 	force_flush_all();
-	switch_mm_skas(current->mm->context.skas.mm_fd);
+        switch_mm_skas(&current->mm->context.skas.id);
 }
 
 void start_thread_skas(struct pt_regs *regs, unsigned long eip, 
diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/kernel/skas/include/mm_id.h
new file mode 100644
index 0000000..48dd098
--- /dev/null
+++ b/arch/um/kernel/skas/include/mm_id.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MM_ID_H
+#define __MM_ID_H
+
+struct mm_id {
+	union {
+		int mm_fd;
+		int pid;
+	} u;
+	unsigned long stack;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 4cd60d7..278b72f 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -6,10 +6,15 @@
 #ifndef __SKAS_MMU_H
 #define __SKAS_MMU_H
 
+#include "mm_id.h"
+
 struct mmu_context_skas {
-	int mm_fd;
+	struct mm_id id;
+        unsigned long last_page_table;
 };
 
+extern void switch_mm_skas(struct mm_id * mm_idp);
+
 #endif
 
 /*
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index 96b51db..d983ea8 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -6,9 +6,11 @@
 #ifndef __SKAS_H
 #define __SKAS_H
 
+#include "mm_id.h"
 #include "sysdep/ptrace.h"
 
 extern int userspace_pid[];
+extern int proc_mm, ptrace_faultinfo;
 
 extern void switch_threads(void *me, void *next);
 extern void thread_wait(void *sw, void *fb);
@@ -22,16 +24,18 @@
 extern void remove_sigstack(void);
 extern void new_thread_handler(int sig);
 extern void handle_syscall(union uml_pt_regs *regs);
-extern void map(int fd, unsigned long virt, unsigned long len, int r, int w,
-		int x, int phys_fd, unsigned long long offset);
-extern int unmap(int fd, void *addr, unsigned long len);
-extern int protect(int fd, unsigned long addr, unsigned long len, 
-		   int r, int w, int x);
+extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
+               int r, int w, int x, int phys_fd, unsigned long long offset);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
+extern int protect(struct mm_id * mm_idp, unsigned long addr,
+		   unsigned long len, int r, int w, int x);
 extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
 extern int new_mm(int from);
-extern void start_userspace(int cpu);
+extern int start_userspace(unsigned long stub_stack);
+extern int copy_context_skas0(unsigned long stack, int pid);
 extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
 extern long execute_syscall_skas(void *r);
+extern unsigned long current_stub_stack(void);
 
 #endif
 
diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/kernel/skas/include/stub-data.h
new file mode 100644
index 0000000..f6ed92c
--- /dev/null
+++ b/arch/um/kernel/skas/include/stub-data.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __STUB_DATA_H
+#define __STUB_DATA_H
+
+#include <sys/time.h>
+
+struct stub_data {
+	long offset;
+	int fd;
+	struct itimerval timer;
+	long err;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 438db2f..147466d 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -5,7 +5,9 @@
 
 #include "linux/config.h"
 #include "linux/mm.h"
+#include "asm/pgtable.h"
 #include "mem_user.h"
+#include "skas.h"
 
 unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, 
 				  unsigned long *task_size_out)
@@ -18,7 +20,9 @@
 	*task_size_out = CONFIG_HOST_TASK_SIZE;
 #else
 	*host_size_out = top;
-	*task_size_out = top;
+	if (proc_mm && ptrace_faultinfo)
+		*task_size_out = top;
+	else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
 #endif
 	return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
 }
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index 1310bf1..b0980ff 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -3,100 +3,171 @@
  * Licensed under the GPL
  */
 
+#include <signal.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <sys/wait.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
 #include "mem_user.h"
 #include "mem.h"
+#include "mm_id.h"
 #include "user.h"
 #include "os.h"
 #include "proc_mm.h"
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "registers.h"
+#include "uml-config.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/stub.h"
+#include "skas.h"
 
-void map(int fd, unsigned long virt, unsigned long len, int r, int w,
-	 int x, int phys_fd, unsigned long long offset)
+extern unsigned long syscall_stub, __syscall_stub_start;
+
+extern void wait_stub_done(int pid, int sig, char * fname);
+
+static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
+                             unsigned long *args)
 {
-	struct proc_mm_op map;
-	int prot, n;
+        int n, pid = mm_idp->u.pid;
+        unsigned long regs[MAX_REG_NR];
 
-	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
-		(x ? PROT_EXEC : 0);
+        get_safe_registers(regs);
+        regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+                ((unsigned long) &syscall_stub -
+                 (unsigned long) &__syscall_stub_start);
+        /* XXX Don't have a define for starting a syscall */
+        regs[REGS_SYSCALL_NR] = syscall;
+        regs[REGS_SYSCALL_ARG1] = args[0];
+        regs[REGS_SYSCALL_ARG2] = args[1];
+        regs[REGS_SYSCALL_ARG3] = args[2];
+        regs[REGS_SYSCALL_ARG4] = args[3];
+        regs[REGS_SYSCALL_ARG5] = args[4];
+        regs[REGS_SYSCALL_ARG6] = args[5];
+        n = ptrace_setregs(pid, regs);
+        if(n < 0){
+                printk("run_syscall_stub : PTRACE_SETREGS failed, "
+                       "errno = %d\n", n);
+                return(n);
+        }
 
-	map = ((struct proc_mm_op) { .op 	= MM_MMAP,
-				     .u 	= 
-				     { .mmap	= 
-				       { .addr 		= virt,
-					 .len		= len,
-					 .prot		= prot,
-					 .flags		= MAP_SHARED | 
-					                  MAP_FIXED,
-					 .fd		= phys_fd,
-					 .offset	= offset
-				       } } } );
-	n = os_write_file(fd, &map, sizeof(map));
-	if(n != sizeof(map)) 
-		printk("map : /proc/mm map failed, err = %d\n", -n);
+        wait_stub_done(pid, 0, "run_syscall_stub");
+
+        return(*((unsigned long *) mm_idp->stack));
 }
 
-int unmap(int fd, void *addr, unsigned long len)
+int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
+        int r, int w, int x, int phys_fd, unsigned long long offset)
 {
-	struct proc_mm_op unmap;
-	int n;
+        int prot, n;
 
-	unmap = ((struct proc_mm_op) { .op 	= MM_MUNMAP,
-				       .u 	= 
-				       { .munmap	= 
-					 { .addr 	= (unsigned long) addr,
-					   .len		= len } } } );
-	n = os_write_file(fd, &unmap, sizeof(unmap));
-	if(n != sizeof(unmap)) {
-		if(n < 0)
-			return(n);
-		else if(n > 0)
-			return(-EIO);
-	}
+        prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+                (x ? PROT_EXEC : 0);
 
-	return(0);
+        if(proc_mm){
+                struct proc_mm_op map;
+                int fd = mm_idp->u.mm_fd;
+                map = ((struct proc_mm_op) { .op	= MM_MMAP,
+                                             .u		=
+                                             { .mmap	=
+                                               { .addr	= virt,
+                                                 .len	= len,
+                                                 .prot	= prot,
+                                                 .flags	= MAP_SHARED |
+                                                 MAP_FIXED,
+                                                 .fd	= phys_fd,
+                                                 .offset= offset
+                                               } } } );
+                n = os_write_file(fd, &map, sizeof(map));
+                if(n != sizeof(map))
+                        printk("map : /proc/mm map failed, err = %d\n", -n);
+        }
+        else {
+                long res;
+                unsigned long args[] = { virt, len, prot,
+                                         MAP_SHARED | MAP_FIXED, phys_fd,
+                                         MMAP_OFFSET(offset) };
+
+                res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
+                if((void *) res == MAP_FAILED)
+                        printk("mmap stub failed, errno = %d\n", res);
+        }
+
+        return 0;
 }
 
-int protect(int fd, unsigned long addr, unsigned long len, int r, int w, 
-	    int x, int must_succeed)
+int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
 {
-	struct proc_mm_op protect;
-	int prot, n;
+        int n;
 
-	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
-		(x ? PROT_EXEC : 0);
+        if(proc_mm){
+                struct proc_mm_op unmap;
+                int fd = mm_idp->u.mm_fd;
+                unmap = ((struct proc_mm_op) { .op	= MM_MUNMAP,
+                                               .u	=
+                                               { .munmap	=
+                                                 { .addr	=
+                                                   (unsigned long) addr,
+                                                   .len		= len } } } );
+                n = os_write_file(fd, &unmap, sizeof(unmap));
+                if(n != sizeof(unmap)) {
+                        if(n < 0)
+                                return(n);
+                        else if(n > 0)
+                                return(-EIO);
+                }
+        }
+        else {
+                int res;
+                unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
+                                         0 };
 
-	protect = ((struct proc_mm_op) { .op 	= MM_MPROTECT,
-				       .u 	= 
-				       { .mprotect	= 
-					 { .addr 	= (unsigned long) addr,
-					   .len		= len,
-					   .prot	= prot } } } );
+                res = run_syscall_stub(mm_idp, __NR_munmap, args);
+                if(res < 0)
+                        printk("munmap stub failed, errno = %d\n", res);
+        }
 
-	n = os_write_file(fd, &protect, sizeof(protect));
-	if(n != sizeof(protect)) {
-		if(n == 0) return(0);
+        return(0);
+}
 
-		if(must_succeed)
-			panic("protect failed, err = %d", -n);
+int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
+	    int r, int w, int x)
+{
+        struct proc_mm_op protect;
+        int prot, n;
 
-		return(-EIO);
-	}
+        prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+                (x ? PROT_EXEC : 0);
 
-	return(0);
+        if(proc_mm){
+                int fd = mm_idp->u.mm_fd;
+                protect = ((struct proc_mm_op) { .op	= MM_MPROTECT,
+                                                 .u	=
+                                                 { .mprotect	=
+                                                   { .addr	=
+                                                     (unsigned long) addr,
+                                                     .len	= len,
+                                                     .prot	= prot } } } );
+
+                n = os_write_file(fd, &protect, sizeof(protect));
+                if(n != sizeof(protect))
+                        panic("protect failed, err = %d", -n);
+        }
+        else {
+                int res;
+                unsigned long args[] = { addr, len, prot, 0, 0, 0 };
+
+                res = run_syscall_stub(mm_idp, __NR_mprotect, args);
+                if(res < 0)
+                        panic("mprotect stub failed, errno = %d\n", res);
+        }
+
+        return(0);
 }
 
 void before_mem_skas(unsigned long unused)
 {
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 6cb9a6d..d232daa 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,46 +3,143 @@
  * Licensed under the GPL
  */
 
+#include "linux/config.h"
 #include "linux/sched.h"
 #include "linux/list.h"
 #include "linux/spinlock.h"
 #include "linux/slab.h"
+#include "linux/errno.h"
+#include "linux/mm.h"
 #include "asm/current.h"
 #include "asm/segment.h"
 #include "asm/mmu.h"
+#include "asm/pgalloc.h"
+#include "asm/pgtable.h"
 #include "os.h"
 #include "skas.h"
 
+extern int __syscall_stub_start;
+
+static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
+			 unsigned long kernel)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	spin_lock(&mm->page_table_lock);
+	pgd = pgd_offset(mm, proc);
+	pud = pud_alloc(mm, pgd, proc);
+	if (!pud)
+		goto out;
+
+	pmd = pmd_alloc(mm, pud, proc);
+	if (!pmd)
+		goto out_pmd;
+
+	pte = pte_alloc_map(mm, pmd, proc);
+	if (!pte)
+		goto out_pte;
+
+	/* There's an interaction between the skas0 stub pages, stack
+	 * randomization, and the BUG at the end of exit_mmap.  exit_mmap
+         * checks that the number of page tables freed is the same as had
+         * been allocated.  If the stack is on the last page table page,
+	 * then the stack pte page will be freed, and if not, it won't.  To
+	 * avoid having to know where the stack is, or if the process mapped
+	 * something at the top of its address space for some other reason,
+	 * we set TASK_SIZE to end at the start of the last page table.
+	 * This keeps exit_mmap off the last page, but introduces a leak
+	 * of that page.  So, we hang onto it here and free it in
+	 * destroy_context_skas.
+	 */
+
+        mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
+
+	*pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
+	*pte = pte_mkexec(*pte);
+	*pte = pte_wrprotect(*pte);
+	spin_unlock(&mm->page_table_lock);
+	return(0);
+
+ out_pmd:
+	pud_free(pud);
+ out_pte:
+	pmd_free(pmd);
+ out:
+	spin_unlock(&mm->page_table_lock);
+	return(-ENOMEM);
+}
+
 int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
 {
-	int from;
+	struct mm_struct *cur_mm = current->mm;
+	struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
+	struct mm_id *mm_id = &mm->context.skas.id;
+	unsigned long stack;
+	int from, ret;
 
-	if((current->mm != NULL) && (current->mm != &init_mm))
-		from = current->mm->context.skas.mm_fd;
-	else from = -1;
+	if(proc_mm){
+		if((cur_mm != NULL) && (cur_mm != &init_mm))
+			from = cur_mm->context.skas.id.u.mm_fd;
+		else from = -1;
 
-	mm->context.skas.mm_fd = new_mm(from);
-	if(mm->context.skas.mm_fd < 0){
-		printk("init_new_context_skas - new_mm failed, errno = %d\n",
-		       mm->context.skas.mm_fd);
-		return(mm->context.skas.mm_fd);
+		ret = new_mm(from);
+		if(ret < 0){
+			printk("init_new_context_skas - new_mm failed, "
+			       "errno = %d\n", ret);
+			return ret;
+		}
+		mm_id->u.mm_fd = ret;
+	}
+	else {
+		/* This zeros the entry that pgd_alloc didn't, needed since
+		 * we are about to reinitialize it, and want mm.nr_ptes to
+		 * be accurate.
+		 */
+		mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
+
+		ret = init_stub_pte(mm, CONFIG_STUB_CODE,
+				    (unsigned long) &__syscall_stub_start);
+		if(ret)
+			goto out;
+
+		ret = -ENOMEM;
+		stack = get_zeroed_page(GFP_KERNEL);
+		if(stack == 0)
+			goto out;
+		mm_id->stack = stack;
+
+		ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
+		if(ret)
+			goto out_free;
+
+		mm->nr_ptes--;
+
+		if((cur_mm != NULL) && (cur_mm != &init_mm))
+			mm_id->u.pid = copy_context_skas0(stack,
+							  cur_mm_id->u.pid);
+		else mm_id->u.pid = start_userspace(stack);
 	}
 
-	return(0);
+	return 0;
+
+ out_free:
+	free_page(mm_id->stack);
+ out:
+	return ret;
 }
 
 void destroy_context_skas(struct mm_struct *mm)
 {
-	os_close_file(mm->context.skas.mm_fd);
-}
+	struct mmu_context_skas *mmu = &mm->context.skas;
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+	if(proc_mm)
+		os_close_file(mmu->id.u.mm_fd);
+	else {
+		os_kill_ptraced_process(mmu->id.u.pid, 1);
+		free_page(mmu->id.stack);
+		free_page(mmu->last_page_table);
+	}
+}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 773cd2b..ba671da 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
 
@@ -13,7 +13,9 @@
 #include <sys/wait.h>
 #include <sys/mman.h>
 #include <sys/user.h>
+#include <sys/time.h>
 #include <asm/unistd.h>
+#include <asm/types.h>
 #include "user.h"
 #include "ptrace_user.h"
 #include "time_user.h"
@@ -21,13 +23,18 @@
 #include "user_util.h"
 #include "kern_util.h"
 #include "skas.h"
+#include "stub-data.h"
+#include "mm_id.h"
 #include "sysdep/sigcontext.h"
+#include "sysdep/stub.h"
 #include "os.h"
 #include "proc_mm.h"
 #include "skas_ptrace.h"
 #include "chan_user.h"
 #include "signal_user.h"
 #include "registers.h"
+#include "mem.h"
+#include "uml-config.h"
 #include "process.h"
 
 int is_skas_winch(int pid, int fd, void *data)
@@ -39,20 +46,55 @@
 	return(1);
 }
 
+void wait_stub_done(int pid, int sig, char * fname)
+{
+        int n, status, err;
+
+        do {
+                if ( sig != -1 ) {
+                        err = ptrace(PTRACE_CONT, pid, 0, sig);
+                        if(err)
+                                panic("%s : continue failed, errno = %d\n",
+                                      fname, errno);
+                }
+                sig = 0;
+
+                CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+        } while((n >= 0) && WIFSTOPPED(status) &&
+                (WSTOPSIG(status) == SIGVTALRM));
+
+        if((n < 0) || !WIFSTOPPED(status) ||
+           (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
+                panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
+                      "pid = %d, n = %d, errno = %d, status = 0x%x\n",
+                      fname, pid, n, errno, status);
+        }
+}
+
 void get_skas_faultinfo(int pid, struct faultinfo * fi)
 {
-	int err;
+        int err;
 
-        err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
-	if(err)
-                panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
-                      "errno = %d\n", errno);
+        if(ptrace_faultinfo){
+                err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
+                if(err)
+                        panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+                              "errno = %d\n", errno);
 
-        /* Special handling for i386, which has different structs */
-        if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
-                memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
-                       sizeof(struct faultinfo) -
-                       sizeof(struct ptrace_faultinfo));
+                /* Special handling for i386, which has different structs */
+                if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+                        memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+                               sizeof(struct faultinfo) -
+                               sizeof(struct ptrace_faultinfo));
+        }
+        else {
+                wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+
+                /* faultinfo is prepared by the stub-segv-handler at start of
+                 * the stub stack page. We just have to copy it.
+                 */
+                memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
+        }
 }
 
 static void handle_segv(int pid, union uml_pt_regs * regs)
@@ -91,11 +133,56 @@
 	handle_syscall(regs);
 }
 
-static int userspace_tramp(void *arg)
+extern int __syscall_stub_start;
+
+static int userspace_tramp(void *stack)
 {
-	init_new_thread_signals(0);
-	enable_timer();
+	void *addr;
+
 	ptrace(PTRACE_TRACEME, 0, 0, 0);
+
+	init_new_thread_signals(1);
+	enable_timer();
+
+	if(!proc_mm){
+		/* This has a pte, but it can't be mapped in with the usual
+		 * tlb_flush mechanism because this is part of that mechanism
+		 */
+		int fd;
+		__u64 offset;
+
+		fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
+		addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+			      PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+		if(addr == MAP_FAILED){
+			printk("mapping mmap stub failed, errno = %d\n",
+			       errno);
+			exit(1);
+		}
+
+		if(stack != NULL){
+			fd = phys_mapping(to_phys(stack), &offset);
+			addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
+				    PROT_READ | PROT_WRITE,
+				    MAP_FIXED | MAP_SHARED, fd, offset);
+			if(addr == MAP_FAILED){
+				printk("mapping segfault stack failed, "
+				       "errno = %d\n", errno);
+				exit(1);
+			}
+		}
+	}
+	if(!ptrace_faultinfo && (stack != NULL)){
+		unsigned long v = UML_CONFIG_STUB_CODE +
+				  (unsigned long) stub_segv_handler -
+				  (unsigned long) &__syscall_stub_start;
+
+		set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+		set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
+			    SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
+			    SIGUSR1, -1);
+	}
+
 	os_stop_process(os_getpid());
 	return(0);
 }
@@ -105,11 +192,11 @@
 #define NR_CPUS 1
 int userspace_pid[NR_CPUS];
 
-void start_userspace(int cpu)
+int start_userspace(unsigned long stub_stack)
 {
 	void *stack;
 	unsigned long sp;
-	int pid, status, n;
+	int pid, status, n, flags;
 
 	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
 		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -117,8 +204,9 @@
 		panic("start_userspace : mmap failed, errno = %d", errno);
 	sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
 
-	pid = clone(userspace_tramp, (void *) sp, 
-		    CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
+	flags = CLONE_FILES | SIGCHLD;
+	if(proc_mm) flags |= CLONE_VM;
+	pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
 	if(pid < 0)
 		panic("start_userspace : clone failed, errno = %d", errno);
 
@@ -140,7 +228,7 @@
 	if(munmap(stack, PAGE_SIZE) < 0)
 		panic("start_userspace : munmap failed, errno = %d\n", errno);
 
-	userspace_pid[cpu] = pid;
+	return(pid);
 }
 
 void userspace(union uml_pt_regs *regs)
@@ -174,7 +262,9 @@
 		if(WIFSTOPPED(status)){
 		  	switch(WSTOPSIG(status)){
 			case SIGSEGV:
-                                handle_segv(pid, regs);
+                                if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
+                                        user_signal(SIGSEGV, regs, pid);
+                                else handle_segv(pid, regs);
 				break;
 			case SIGTRAP + 0x80:
 			        handle_trap(pid, regs, local_using_sysemu);
@@ -194,6 +284,7 @@
 			        printk("userspace - child stopped with signal "
 				       "%d\n", WSTOPSIG(status));
 			}
+			pid = userspace_pid[0];
 			interrupt_end();
 
 			/* Avoid -ERESTARTSYS handling in host */
@@ -207,6 +298,67 @@
 #define INIT_JMP_HALT 3
 #define INIT_JMP_REBOOT 4
 
+
+int copy_context_skas0(unsigned long new_stack, int pid)
+{
+	int err;
+	unsigned long regs[MAX_REG_NR];
+	unsigned long current_stack = current_stub_stack();
+	struct stub_data *data = (struct stub_data *) current_stack;
+	struct stub_data *child_data = (struct stub_data *) new_stack;
+	__u64 new_offset;
+	int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+
+	/* prepare offset and fd of child's stack as argument for parent's
+	 * and child's mmap2 calls
+	 */
+	*data = ((struct stub_data) { .offset	= MMAP_OFFSET(new_offset),
+				      .fd	= new_fd,
+				      .timer	= ((struct itimerval)
+					           { { 0, 1000000 / hz() },
+						     { 0, 1000000 / hz() }})});
+	get_safe_registers(regs);
+
+	/* Set parent's instruction pointer to start of clone-stub */
+	regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+				(unsigned long) stub_clone_handler -
+				(unsigned long) &__syscall_stub_start;
+	regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
+		sizeof(void *);
+	err = ptrace_setregs(pid, regs);
+	if(err < 0)
+		panic("copy_context_skas0 : PTRACE_SETREGS failed, "
+		      "pid = %d, errno = %d\n", pid, errno);
+
+	/* set a well known return code for detection of child write failure */
+	child_data->err = 12345678;
+
+	/* Wait, until parent has finished its work: read child's pid from
+	 * parent's stack, and check, if bad result.
+	 */
+	wait_stub_done(pid, 0, "copy_context_skas0");
+
+	pid = data->err;
+	if(pid < 0)
+		panic("copy_context_skas0 - stub-parent reports error %d\n",
+		      pid);
+
+	/* Wait, until child has finished too: read child's result from
+	 * child's stack and check it.
+	 */
+	wait_stub_done(pid, -1, "copy_context_skas0");
+	if (child_data->err != UML_CONFIG_STUB_DATA)
+		panic("copy_context_skas0 - stub-child reports error %d\n",
+		      child_data->err);
+
+	if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
+		   (void *)PTRACE_O_TRACESYSGOOD) < 0)
+		panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
+		      "errno = %d\n", errno);
+
+	return pid;
+}
+
 void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
 		void (*handler)(int))
 {
@@ -334,21 +486,19 @@
 	siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
 }
 
-void switch_mm_skas(int mm_fd)
+void switch_mm_skas(struct mm_id *mm_idp)
 {
 	int err;
 
 #warning need cpu pid in switch_mm_skas
-	err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
-	if(err)
-		panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
-		      errno);
-}
-
-void kill_off_processes_skas(void)
-{
-#warning need to loop over userspace_pids in kill_off_processes_skas
-	os_kill_ptraced_process(userspace_pid[0], 1);
+	if(proc_mm){
+		err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
+			     mm_idp->u.mm_fd);
+		if(err)
+			panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
+			      "errno = %d\n", errno);
+	}
+	else userspace_pid[0] = mm_idp->u.pid;
 }
 
 /*
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 0a7b8aa..cbabab1 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -175,9 +175,12 @@
 	return(0);
 }
 
+extern int userspace_pid[];
+
 int start_uml_skas(void)
 {
-	start_userspace(0);
+	if(proc_mm)
+		userspace_pid[0] = start_userspace(0);
 
 	init_new_thread_signals(1);
 
@@ -199,3 +202,31 @@
 #warning Need to look up userspace_pid by cpu
 	return(userspace_pid[0]);
 }
+
+void kill_off_processes_skas(void)
+{
+	if(proc_mm)
+#warning need to loop over userspace_pids in kill_off_processes_skas
+		os_kill_ptraced_process(userspace_pid[0], 1);
+	else {
+		struct task_struct *p;
+		int pid, me;
+
+		me = os_getpid();
+		for_each_process(p){
+			if(p->mm == NULL)
+				continue;
+
+			pid = p->mm->context.skas.id.u.pid;
+			os_kill_ptraced_process(pid, 1);
+		}
+	}
+}
+
+unsigned long current_stub_stack(void)
+{
+	if(current->mm == NULL)
+		return(0);
+
+	return(current->mm->context.skas.id.stack);
+}
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index b8c5e71..6230999 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,6 +6,7 @@
 
 #include "linux/stddef.h"
 #include "linux/sched.h"
+#include "linux/config.h"
 #include "linux/mm.h"
 #include "asm/page.h"
 #include "asm/pgtable.h"
@@ -17,7 +18,7 @@
 #include "os.h"
 #include "tlb.h"
 
-static void do_ops(int fd, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
 {
 	struct host_vm_op *op;
 	int i;
@@ -26,18 +27,18 @@
 		op = &ops[i];
 		switch(op->type){
 		case MMAP:
-			map(fd, op->u.mmap.addr, op->u.mmap.len,
+                        map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
 			    op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
 			    op->u.mmap.fd, op->u.mmap.offset);
 			break;
 		case MUNMAP:
-			unmap(fd, (void *) op->u.munmap.addr,
+                        unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
 			      op->u.munmap.len);
 			break;
 		case MPROTECT:
-			protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
-				op->u.mprotect.r, op->u.mprotect.w,
-				op->u.mprotect.x);
+                        protect(&mmu->skas.id, op->u.mprotect.addr,
+                                op->u.mprotect.len, op->u.mprotect.r,
+                                op->u.mprotect.w, op->u.mprotect.x);
 			break;
 		default:
 			printk("Unknown op type %d in do_ops\n", op->type);
@@ -46,12 +47,15 @@
 	}
 }
 
+extern int proc_mm;
+
 static void fix_range(struct mm_struct *mm, unsigned long start_addr,
 		      unsigned long end_addr, int force)
 {
-        int fd = mm->context.skas.mm_fd;
+        if(!proc_mm && (end_addr > CONFIG_STUB_START))
+                end_addr = CONFIG_STUB_START;
 
-        fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
+        fix_range_common(mm, start_addr, end_addr, force, do_ops);
 }
 
 void __flush_tlb_one_skas(unsigned long addr)
@@ -69,17 +73,20 @@
 
 void flush_tlb_mm_skas(struct mm_struct *mm)
 {
+	unsigned long end;
+
 	/* Don't bother flushing if this address space is about to be
          * destroyed.
          */
         if(atomic_read(&mm->mm_users) == 0)
                 return;
 
-        fix_range(mm, 0, host_task_size, 0);
-        flush_tlb_kernel_range_common(start_vm, end_vm);
+	end = proc_mm ? task_size : CONFIG_STUB_START;
+        fix_range(mm, 0, end, 0);
 }
 
 void force_flush_all_skas(void)
 {
-        fix_range(current->mm, 0, host_task_size, 1);
+	unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+        fix_range(current->mm, 0, end, 1);
 }
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index f829b30..c40b611 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -48,6 +48,13 @@
 	set_interval(ITIMER_VIRTUAL);
 }
 
+void prepare_timer(void * ptr)
+{
+	int usec = 1000000/hz();
+	*(struct itimerval *)ptr = ((struct itimerval) { { 0, usec },
+							 { 0, usec }});
+}
+
 void disable_timer(void)
 {
 	struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index eda477e..83ec8d4 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -18,13 +18,15 @@
 #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
 
 void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
-                      unsigned long end_addr, int force, int data,
-                      void (*do_ops)(int, struct host_vm_op *, int))
+                      unsigned long end_addr, int force,
+                      void (*do_ops)(union mm_context *, struct host_vm_op *,
+                                     int))
 {
         pgd_t *npgd;
         pud_t *npud;
         pmd_t *npmd;
         pte_t *npte;
+        union mm_context *mmu = &mm->context;
         unsigned long addr, end;
         int r, w, x;
         struct host_vm_op ops[16];
@@ -40,7 +42,7 @@
                                 end = end_addr;
                         if(force || pgd_newpage(*npgd)){
                                 op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, data,
+                                                      op_index, last_op, mmu,
                                                       do_ops);
                                 pgd_mkuptodate(*npgd);
                         }
@@ -55,7 +57,7 @@
                                 end = end_addr;
                         if(force || pud_newpage(*npud)){
                                 op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, data,
+                                                      op_index, last_op, mmu,
                                                       do_ops);
                                 pud_mkuptodate(*npud);
                         }
@@ -70,7 +72,7 @@
                                 end = end_addr;
                         if(force || pmd_newpage(*npmd)){
                                 op_index = add_munmap(addr, end - addr, ops,
-                                                      op_index, last_op, data,
+                                                      op_index, last_op, mmu,
                                                       do_ops);
                                 pmd_mkuptodate(*npmd);
                         }
@@ -93,21 +95,21 @@
                                 op_index = add_mmap(addr,
                                                     pte_val(*npte) & PAGE_MASK,
                                                     PAGE_SIZE, r, w, x, ops,
-                                                    op_index, last_op, data,
+                                                    op_index, last_op, mmu,
                                                     do_ops);
                         else op_index = add_munmap(addr, PAGE_SIZE, ops,
-                                                   op_index, last_op, data,
+                                                   op_index, last_op, mmu,
                                                    do_ops);
                 }
                 else if(pte_newprot(*npte))
                         op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
-                                                op_index, last_op, data,
+                                                op_index, last_op, mmu,
                                                 do_ops);
 
                 *npte = pte_mkuptodate(*npte);
                 addr += PAGE_SIZE;
         }
-        (*do_ops)(data, ops, op_index);
+        (*do_ops)(mmu, ops, op_index);
 }
 
 int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -195,51 +197,6 @@
         return(updated);
 }
 
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
-{
-        address &= PAGE_MASK;
-        flush_tlb_range(vma, address, address + PAGE_SIZE);
-}
-
-void flush_tlb_all(void)
-{
-        flush_tlb_mm(current->mm);
-}
-  
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-        CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
-                         flush_tlb_kernel_range_common, start, end);
-}
-
-void flush_tlb_kernel_vm(void)
-{
-        CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
-                    flush_tlb_kernel_range_common(start_vm, end_vm));
-}
-
-void __flush_tlb_one(unsigned long addr)
-{
-        CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
-}
-
-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 
-     unsigned long end)
-{
-        CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
-                         end);
-}
-
-void flush_tlb_mm(struct mm_struct *mm)
-{
-        CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
-}
-
-void force_flush_all(void)
-{
-        CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
-}
-
 pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
 {
         return(pgd_offset(mm, address));
@@ -270,9 +227,9 @@
 }
 
 int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
-     int r, int w, int x, struct host_vm_op *ops, int index,
-     int last_filled, int data,
-     void (*do_ops)(int, struct host_vm_op *, int))
+             int r, int w, int x, struct host_vm_op *ops, int index,
+             int last_filled, union mm_context *mmu,
+             void (*do_ops)(union mm_context *, struct host_vm_op *, int))
 {
         __u64 offset;
 	struct host_vm_op *last;
@@ -292,7 +249,7 @@
 	}
 
 	if(index == last_filled){
-		(*do_ops)(data, ops, last_filled);
+		(*do_ops)(mmu, ops, last_filled);
 		index = -1;
 	}
 
@@ -310,8 +267,8 @@
 }
 
 int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
-	       int index, int last_filled, int data,
-	       void (*do_ops)(int, struct host_vm_op *, int))
+	       int index, int last_filled, union mm_context *mmu,
+	       void (*do_ops)(union mm_context *, struct host_vm_op *, int))
 {
 	struct host_vm_op *last;
 
@@ -325,7 +282,7 @@
 	}
 
 	if(index == last_filled){
-		(*do_ops)(data, ops, last_filled);
+		(*do_ops)(mmu, ops, last_filled);
 		index = -1;
 	}
 
@@ -337,8 +294,9 @@
 }
 
 int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
-		 struct host_vm_op *ops, int index, int last_filled, int data,
-		 void (*do_ops)(int, struct host_vm_op *, int))
+                 struct host_vm_op *ops, int index, int last_filled,
+                 union mm_context *mmu,
+                 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
 {
 	struct host_vm_op *last;
 
@@ -354,7 +312,7 @@
 	}
 
 	if(index == last_filled){
-		(*do_ops)(data, ops, last_filled);
+		(*do_ops)(mmu, ops, last_filled);
 		index = -1;
 	}
 
@@ -367,3 +325,49 @@
 						      .x	= x } } });
 	return(index);
 }
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+        address &= PAGE_MASK;
+        flush_tlb_range(vma, address, address + PAGE_SIZE);
+}
+
+void flush_tlb_all(void)
+{
+        flush_tlb_mm(current->mm);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+        CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
+                         flush_tlb_kernel_range_common, start, end);
+}
+
+void flush_tlb_kernel_vm(void)
+{
+        CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
+                    flush_tlb_kernel_range_common(start_vm, end_vm));
+}
+
+void __flush_tlb_one(unsigned long addr)
+{
+        CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+		     unsigned long end)
+{
+        CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
+                         end);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+        CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
+}
+
+void force_flush_all(void)
+{
+        CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
+}
+
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 203216a..2eefb43 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -17,7 +17,7 @@
 #include "os.h"
 #include "tlb.h"
 
-static void do_ops(int unused, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
 {
 	struct host_vm_op *op;
 	int i;
@@ -55,7 +55,7 @@
                 panic("fix_range fixing wrong address space, current = 0x%p",
                       current);
 
-        fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
+        fix_range_common(mm, start_addr, end_addr, force, do_ops);
 }
 
 atomic_t vmchange_seq = ATOMIC_INIT(1);
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 61dfd4f..163476a 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -30,6 +30,7 @@
 	_einittext = .;
   }
   . = ALIGN(4096);
+
   .text      :
   {
     *(.text)
@@ -39,6 +40,12 @@
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
     *(.gnu.linkonce.t*)
+
+    . = ALIGN(4096);
+    __syscall_stub_start = .;
+    *(.__syscall_stub*)
+    __syscall_stub_end = .;
+    . = ALIGN(4096);
   }
 
   #include "asm/common.lds.S"
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
index 9a0ad09..3125d32 100644
--- a/arch/um/os-Linux/sys-i386/registers.c
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -121,6 +121,11 @@
 		      err);
 }
 
+void get_safe_registers(unsigned long *regs)
+{
+	memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c
index 6286c97..44438d1 100644
--- a/arch/um/os-Linux/sys-x86_64/registers.c
+++ b/arch/um/os-Linux/sys-x86_64/registers.c
@@ -69,6 +69,11 @@
 		      err);
 }
 
+void get_safe_registers(unsigned long *regs)
+{
+	memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index 7459d09..17f305b 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -16,6 +16,11 @@
 endef
 
 
+# The stubs and unmap.o can't try to call mcount or update basic block data
+define unprofile
+	$(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
+endef
+
 quiet_cmd_make_link = SYMLINK $@
 cmd_make_link       = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
 
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 095bcdb..77c3c4d 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,6 +1,6 @@
 obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
-	ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
-	sys_call_table.o
+	ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
+	syscalls.o sysrq.o sys_call_table.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 obj-$(CONFIG_MODULES) += module.o
@@ -16,6 +16,14 @@
 highmem.c-dir = mm
 module.c-dir = kernel
 
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
 subdir- := util
 
 include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
new file mode 100644
index 0000000..2f2c70a
--- /dev/null
+++ b/arch/um/sys-i386/stub.S
@@ -0,0 +1,8 @@
+#include "uml-config.h"
+
+	.globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+	int 	$0x80
+	mov	%eax, UML_CONFIG_STUB_DATA
+	int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
new file mode 100644
index 0000000..b251442
--- /dev/null
+++ b/arch/um/sys-i386/stub_segv.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+	struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
+
+	GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+			      sc);
+
+	__asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
+	__asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
+		"int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
+	/* Pop the frame pointer and return address since we need to leave
+	 * the stack in its original form when we do the sigreturn here, by
+	 * hand.
+	 */
+	__asm__("popl %%eax ; popl %%eax ; popl %%eax ; movl %0, %%eax ; "
+		"int $0x80" : : "g" (__NR_sigreturn));
+}
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 2bc6f68..7488206 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -6,8 +6,8 @@
 
 #XXX: why into lib-y?
 lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
-	ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \
-	syscalls.o sysrq.o thunk.o syscall_table.o
+	ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+	stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
 
 obj-y := ksyms.o
 obj-$(CONFIG_MODULES) += module.o um_module.o
@@ -28,6 +28,14 @@
 thunk.S-dir = lib
 module.c-dir = kernel
 
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
 subdir- := util
 
 include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S
new file mode 100644
index 0000000..31c1492
--- /dev/null
+++ b/arch/um/sys-x86_64/stub.S
@@ -0,0 +1,15 @@
+#include "uml-config.h"
+
+	.globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+	syscall
+	/* We don't have 64-bit constants, so this constructs the address
+	 * we need.
+	 */
+	movq	$(UML_CONFIG_STUB_DATA >> 32), %rbx
+	salq	$32, %rbx
+	movq	$(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx
+	or	%rcx, %rbx
+	movq	%rax, (%rbx)
+	int3
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
new file mode 100644
index 0000000..161d1fe
--- /dev/null
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <linux/compiler.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+	struct ucontext *uc;
+
+	__asm__("movq %%rdx, %0" : "=g" (uc) :);
+        GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+                              &uc->uc_mcontext);
+
+	__asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid));
+	__asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;"
+		"syscall": : "g" (__NR_kill), "g" (SIGUSR1));
+	/* Two popqs to restore the stack to the state just before entering
+	 * the handler, one pops the return address, the other pops the frame
+	 * pointer.
+	 */
+	__asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g"
+		(__NR_rt_sigreturn));
+}
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 8a73794..4289156 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -65,7 +65,9 @@
 head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o
 
 libs-y 					+= arch/x86_64/lib/
-core-y					+= arch/x86_64/kernel/ arch/x86_64/mm/
+core-y					+= arch/x86_64/kernel/ \
+					   arch/x86_64/mm/ \
+					   arch/x86_64/crypto/
 core-$(CONFIG_IA32_EMULATION)		+= arch/x86_64/ia32/
 drivers-$(CONFIG_PCI)			+= arch/x86_64/pci/
 drivers-$(CONFIG_OPROFILE)		+= arch/x86_64/oprofile/
diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile
new file mode 100644
index 0000000..426d20f
--- /dev/null
+++ b/arch/x86_64/crypto/Makefile
@@ -0,0 +1,9 @@
+# 
+# x86_64/crypto/Makefile 
+# 
+# Arch-specific CryptoAPI modules.
+# 
+
+obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
+
+aes-x86_64-y := aes-x86_64-asm.o aes.o
diff --git a/arch/x86_64/crypto/aes-x86_64-asm.S b/arch/x86_64/crypto/aes-x86_64-asm.S
new file mode 100644
index 0000000..483cbb2
--- /dev/null
+++ b/arch/x86_64/crypto/aes-x86_64-asm.S
@@ -0,0 +1,186 @@
+/* AES (Rijndael) implementation (FIPS PUB 197) for x86_64
+ *
+ * Copyright (C) 2005 Andreas Steinmetz, <ast@domdv.de>
+ *
+ * License:
+ * This code can be distributed under the terms of the GNU General Public
+ * License (GPL) Version 2 provided that the above header down to and
+ * including this sentence is retained in full.
+ */
+
+.extern aes_ft_tab
+.extern aes_it_tab
+.extern aes_fl_tab
+.extern aes_il_tab
+
+.text
+
+#define R1	%rax
+#define R1E	%eax
+#define R1X	%ax
+#define R1H	%ah
+#define R1L	%al
+#define R2	%rbx
+#define R2E	%ebx
+#define R2X	%bx
+#define R2H	%bh
+#define R2L	%bl
+#define R3	%rcx
+#define R3E	%ecx
+#define R3X	%cx
+#define R3H	%ch
+#define R3L	%cl
+#define R4	%rdx
+#define R4E	%edx
+#define R4X	%dx
+#define R4H	%dh
+#define R4L	%dl
+#define R5	%rsi
+#define R5E	%esi
+#define R6	%rdi
+#define R6E	%edi
+#define R7	%rbp
+#define R7E	%ebp
+#define R8	%r8
+#define R9	%r9
+#define R10	%r10
+#define R11	%r11
+
+#define prologue(FUNC,BASE,B128,B192,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11) \
+	.global	FUNC;			\
+	.type	FUNC,@function;		\
+	.align	8;			\
+FUNC:	movq	r1,r2;			\
+	movq	r3,r4;			\
+	leaq	BASE+52(r8),r9;		\
+	movq	r10,r11;		\
+	movl	(r7),r5 ## E;		\
+	movl	4(r7),r1 ## E;		\
+	movl	8(r7),r6 ## E;		\
+	movl	12(r7),r7 ## E;		\
+	movl	(r8),r10 ## E;		\
+	xorl	-48(r9),r5 ## E;	\
+	xorl	-44(r9),r1 ## E;	\
+	xorl	-40(r9),r6 ## E;	\
+	xorl	-36(r9),r7 ## E;	\
+	cmpl	$24,r10 ## E;		\
+	jb	B128;			\
+	leaq	32(r9),r9;		\
+	je	B192;			\
+	leaq	32(r9),r9;
+
+#define epilogue(r1,r2,r3,r4,r5,r6,r7,r8,r9) \
+	movq	r1,r2;			\
+	movq	r3,r4;			\
+	movl	r5 ## E,(r9);		\
+	movl	r6 ## E,4(r9);		\
+	movl	r7 ## E,8(r9);		\
+	movl	r8 ## E,12(r9);		\
+	ret;
+
+#define round(TAB,OFFSET,r1,r2,r3,r4,r5,r6,r7,r8,ra,rb,rc,rd) \
+	movzbl	r2 ## H,r5 ## E;	\
+	movzbl	r2 ## L,r6 ## E;	\
+	movl	TAB+1024(,r5,4),r5 ## E;\
+	movw	r4 ## X,r2 ## X;	\
+	movl	TAB(,r6,4),r6 ## E;	\
+	roll	$16,r2 ## E;		\
+	shrl	$16,r4 ## E;		\
+	movzbl	r4 ## H,r7 ## E;	\
+	movzbl	r4 ## L,r4 ## E;	\
+	xorl	OFFSET(r8),ra ## E;	\
+	xorl	OFFSET+4(r8),rb ## E;	\
+	xorl	TAB+3072(,r7,4),r5 ## E;\
+	xorl	TAB+2048(,r4,4),r6 ## E;\
+	movzbl	r1 ## L,r7 ## E;	\
+	movzbl	r1 ## H,r4 ## E;	\
+	movl	TAB+1024(,r4,4),r4 ## E;\
+	movw	r3 ## X,r1 ## X;	\
+	roll	$16,r1 ## E;		\
+	shrl	$16,r3 ## E;		\
+	xorl	TAB(,r7,4),r5 ## E;	\
+	movzbl	r3 ## H,r7 ## E;	\
+	movzbl	r3 ## L,r3 ## E;	\
+	xorl	TAB+3072(,r7,4),r4 ## E;\
+	xorl	TAB+2048(,r3,4),r5 ## E;\
+	movzbl	r1 ## H,r7 ## E;	\
+	movzbl	r1 ## L,r3 ## E;	\
+	shrl	$16,r1 ## E;		\
+	xorl	TAB+3072(,r7,4),r6 ## E;\
+	movl	TAB+2048(,r3,4),r3 ## E;\
+	movzbl	r1 ## H,r7 ## E;	\
+	movzbl	r1 ## L,r1 ## E;	\
+	xorl	TAB+1024(,r7,4),r6 ## E;\
+	xorl	TAB(,r1,4),r3 ## E;	\
+	movzbl	r2 ## H,r1 ## E;	\
+	movzbl	r2 ## L,r7 ## E;	\
+	shrl	$16,r2 ## E;		\
+	xorl	TAB+3072(,r1,4),r3 ## E;\
+	xorl	TAB+2048(,r7,4),r4 ## E;\
+	movzbl	r2 ## H,r1 ## E;	\
+	movzbl	r2 ## L,r2 ## E;	\
+	xorl	OFFSET+8(r8),rc ## E;	\
+	xorl	OFFSET+12(r8),rd ## E;	\
+	xorl	TAB+1024(,r1,4),r3 ## E;\
+	xorl	TAB(,r2,4),r4 ## E;
+
+#define move_regs(r1,r2,r3,r4) \
+	movl	r3 ## E,r1 ## E;	\
+	movl	r4 ## E,r2 ## E;
+
+#define entry(FUNC,BASE,B128,B192) \
+	prologue(FUNC,BASE,B128,B192,R2,R8,R7,R9,R1,R3,R4,R6,R10,R5,R11)
+
+#define return epilogue(R8,R2,R9,R7,R5,R6,R3,R4,R11)
+
+#define encrypt_round(TAB,OFFSET) \
+	round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4) \
+	move_regs(R1,R2,R5,R6)
+
+#define encrypt_final(TAB,OFFSET) \
+	round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4)
+
+#define decrypt_round(TAB,OFFSET) \
+	round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4) \
+	move_regs(R1,R2,R5,R6)
+
+#define decrypt_final(TAB,OFFSET) \
+	round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4)
+
+/* void aes_encrypt(void *ctx, u8 *out, const u8 *in) */
+
+	entry(aes_encrypt,0,enc128,enc192)
+	encrypt_round(aes_ft_tab,-96)
+	encrypt_round(aes_ft_tab,-80)
+enc192:	encrypt_round(aes_ft_tab,-64)
+	encrypt_round(aes_ft_tab,-48)
+enc128:	encrypt_round(aes_ft_tab,-32)
+	encrypt_round(aes_ft_tab,-16)
+	encrypt_round(aes_ft_tab,  0)
+	encrypt_round(aes_ft_tab, 16)
+	encrypt_round(aes_ft_tab, 32)
+	encrypt_round(aes_ft_tab, 48)
+	encrypt_round(aes_ft_tab, 64)
+	encrypt_round(aes_ft_tab, 80)
+	encrypt_round(aes_ft_tab, 96)
+	encrypt_final(aes_fl_tab,112)
+	return
+
+/* void aes_decrypt(void *ctx, u8 *out, const u8 *in) */
+
+	entry(aes_decrypt,240,dec128,dec192)
+	decrypt_round(aes_it_tab,-96)
+	decrypt_round(aes_it_tab,-80)
+dec192:	decrypt_round(aes_it_tab,-64)
+	decrypt_round(aes_it_tab,-48)
+dec128:	decrypt_round(aes_it_tab,-32)
+	decrypt_round(aes_it_tab,-16)
+	decrypt_round(aes_it_tab,  0)
+	decrypt_round(aes_it_tab, 16)
+	decrypt_round(aes_it_tab, 32)
+	decrypt_round(aes_it_tab, 48)
+	decrypt_round(aes_it_tab, 64)
+	decrypt_round(aes_it_tab, 80)
+	decrypt_round(aes_it_tab, 96)
+	decrypt_final(aes_il_tab,112)
+	return
diff --git a/arch/x86_64/crypto/aes.c b/arch/x86_64/crypto/aes.c
new file mode 100644
index 0000000..2b5c401
--- /dev/null
+++ b/arch/x86_64/crypto/aes.c
@@ -0,0 +1,324 @@
+/*
+ * Cryptographic API.
+ *
+ * AES Cipher Algorithm.
+ *
+ * Based on Brian Gladman's code.
+ *
+ * Linux developers:
+ *  Alexander Kjeldaas <astor@fast.no>
+ *  Herbert Valerio Riedel <hvr@hvrlab.org>
+ *  Kyle McMartin <kyle@debian.org>
+ *  Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
+ *  Andreas Steinmetz <ast@domdv.de> (adapted to x86_64 assembler)
+ *
+ * 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.
+ *
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ * All rights reserved.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ *   1. distributions of this source code include the above copyright
+ *      notice, this list of conditions and the following disclaimer;
+ *
+ *   2. distributions in binary form include the above copyright
+ *      notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other associated materials;
+ *
+ *   3. the copyright holder's name is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ */
+
+/* Some changes from the Gladman version:
+    s/RIJNDAEL(e_key)/E_KEY/g
+    s/RIJNDAEL(d_key)/D_KEY/g
+*/
+
+#include <asm/byteorder.h>
+#include <linux/bitops.h>
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#define AES_MIN_KEY_SIZE	16
+#define AES_MAX_KEY_SIZE	32
+
+#define AES_BLOCK_SIZE		16
+
+/*
+ * #define byte(x, nr) ((unsigned char)((x) >> (nr*8)))
+ */
+static inline u8 byte(const u32 x, const unsigned n)
+{
+	return x >> (n << 3);
+}
+
+#define u32_in(x) le32_to_cpu(*(const __le32 *)(x))
+
+struct aes_ctx
+{
+	u32 key_length;
+	u32 E[60];
+	u32 D[60];
+};
+
+#define E_KEY ctx->E
+#define D_KEY ctx->D
+
+static u8 pow_tab[256] __initdata;
+static u8 log_tab[256] __initdata;
+static u8 sbx_tab[256] __initdata;
+static u8 isb_tab[256] __initdata;
+static u32 rco_tab[10];
+u32 aes_ft_tab[4][256];
+u32 aes_it_tab[4][256];
+
+u32 aes_fl_tab[4][256];
+u32 aes_il_tab[4][256];
+
+static inline u8 f_mult(u8 a, u8 b)
+{
+	u8 aa = log_tab[a], cc = aa + log_tab[b];
+
+	return pow_tab[cc + (cc < aa ? 1 : 0)];
+}
+
+#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0)
+
+#define ls_box(x)				\
+	(aes_fl_tab[0][byte(x, 0)] ^		\
+	 aes_fl_tab[1][byte(x, 1)] ^		\
+	 aes_fl_tab[2][byte(x, 2)] ^		\
+	 aes_fl_tab[3][byte(x, 3)])
+
+static void __init gen_tabs(void)
+{
+	u32 i, t;
+	u8 p, q;
+
+	/* log and power tables for GF(2**8) finite field with
+	   0x011b as modular polynomial - the simplest primitive
+	   root is 0x03, used here to generate the tables */
+
+	for (i = 0, p = 1; i < 256; ++i) {
+		pow_tab[i] = (u8)p;
+		log_tab[p] = (u8)i;
+
+		p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
+	}
+
+	log_tab[1] = 0;
+
+	for (i = 0, p = 1; i < 10; ++i) {
+		rco_tab[i] = p;
+
+		p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
+	}
+
+	for (i = 0; i < 256; ++i) {
+		p = (i ? pow_tab[255 - log_tab[i]] : 0);
+		q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
+		p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
+		sbx_tab[i] = p;
+		isb_tab[p] = (u8)i;
+	}
+
+	for (i = 0; i < 256; ++i) {
+		p = sbx_tab[i];
+
+		t = p;
+		aes_fl_tab[0][i] = t;
+		aes_fl_tab[1][i] = rol32(t, 8);
+		aes_fl_tab[2][i] = rol32(t, 16);
+		aes_fl_tab[3][i] = rol32(t, 24);
+
+		t = ((u32)ff_mult(2, p)) |
+		    ((u32)p << 8) |
+		    ((u32)p << 16) | ((u32)ff_mult(3, p) << 24);
+
+		aes_ft_tab[0][i] = t;
+		aes_ft_tab[1][i] = rol32(t, 8);
+		aes_ft_tab[2][i] = rol32(t, 16);
+		aes_ft_tab[3][i] = rol32(t, 24);
+
+		p = isb_tab[i];
+
+		t = p;
+		aes_il_tab[0][i] = t;
+		aes_il_tab[1][i] = rol32(t, 8);
+		aes_il_tab[2][i] = rol32(t, 16);
+		aes_il_tab[3][i] = rol32(t, 24);
+
+		t = ((u32)ff_mult(14, p)) |
+		    ((u32)ff_mult(9, p) << 8) |
+		    ((u32)ff_mult(13, p) << 16) |
+		    ((u32)ff_mult(11, p) << 24);
+
+		aes_it_tab[0][i] = t;
+		aes_it_tab[1][i] = rol32(t, 8);
+		aes_it_tab[2][i] = rol32(t, 16);
+		aes_it_tab[3][i] = rol32(t, 24);
+	}
+}
+
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
+
+#define imix_col(y, x)			\
+	u    = star_x(x);		\
+	v    = star_x(u);		\
+	w    = star_x(v);		\
+	t    = w ^ (x);			\
+	(y)  = u ^ v ^ w;		\
+	(y) ^= ror32(u ^ t,  8) ^	\
+	       ror32(v ^ t, 16) ^	\
+	       ror32(t, 24)
+
+/* initialise the key schedule from the user supplied key */
+
+#define loop4(i)					\
+{							\
+	t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];	\
+	t ^= E_KEY[4 * i];     E_KEY[4 * i + 4] = t;	\
+	t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t;	\
+	t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t;	\
+	t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t;	\
+}
+
+#define loop6(i)					\
+{							\
+	t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];	\
+	t ^= E_KEY[6 * i];     E_KEY[6 * i + 6] = t;	\
+	t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t;	\
+	t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t;	\
+	t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t;	\
+	t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t;	\
+	t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t;	\
+}
+
+#define loop8(i)					\
+{							\
+	t = ror32(t,  8); ; t = ls_box(t) ^ rco_tab[i];	\
+	t ^= E_KEY[8 * i];     E_KEY[8 * i + 8] = t;	\
+	t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t;	\
+	t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t;	\
+	t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t;	\
+	t  = E_KEY[8 * i + 4] ^ ls_box(t);		\
+	E_KEY[8 * i + 12] = t;				\
+	t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t;	\
+	t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t;	\
+	t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t;	\
+}
+
+static int aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len,
+		       u32 *flags)
+{
+	struct aes_ctx *ctx = ctx_arg;
+	u32 i, j, t, u, v, w;
+
+	if (key_len != 16 && key_len != 24 && key_len != 32) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	ctx->key_length = key_len;
+
+	D_KEY[key_len + 24] = E_KEY[0] = u32_in(in_key);
+	D_KEY[key_len + 25] = E_KEY[1] = u32_in(in_key + 4);
+	D_KEY[key_len + 26] = E_KEY[2] = u32_in(in_key + 8);
+	D_KEY[key_len + 27] = E_KEY[3] = u32_in(in_key + 12);
+
+	switch (key_len) {
+	case 16:
+		t = E_KEY[3];
+		for (i = 0; i < 10; ++i)
+			loop4(i);
+		break;
+
+	case 24:
+		E_KEY[4] = u32_in(in_key + 16);
+		t = E_KEY[5] = u32_in(in_key + 20);
+		for (i = 0; i < 8; ++i)
+			loop6 (i);
+		break;
+
+	case 32:
+		E_KEY[4] = u32_in(in_key + 16);
+		E_KEY[5] = u32_in(in_key + 20);
+		E_KEY[6] = u32_in(in_key + 24);
+		t = E_KEY[7] = u32_in(in_key + 28);
+		for (i = 0; i < 7; ++i)
+			loop8(i);
+		break;
+	}
+
+	D_KEY[0] = E_KEY[key_len + 24];
+	D_KEY[1] = E_KEY[key_len + 25];
+	D_KEY[2] = E_KEY[key_len + 26];
+	D_KEY[3] = E_KEY[key_len + 27];
+
+	for (i = 4; i < key_len + 24; ++i) {
+		j = key_len + 24 - (i & ~3) + (i & 3);
+		imix_col(D_KEY[j], E_KEY[i]);
+	}
+
+	return 0;
+}
+
+extern void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in);
+extern void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in);
+
+static struct crypto_alg aes_alg = {
+	.cra_name		=	"aes",
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	AES_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct aes_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
+	.cra_u			=	{
+		.cipher = {
+			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
+			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
+			.cia_setkey	   	= 	aes_set_key,
+			.cia_encrypt	 	=	aes_encrypt,
+			.cia_decrypt	  	=	aes_decrypt
+		}
+	}
+};
+
+static int __init aes_init(void)
+{
+	gen_tabs();
+	return crypto_register_alg(&aes_alg);
+}
+
+static void __exit aes_fini(void)
+{
+	crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
+MODULE_LICENSE("GPL");
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index b02d921..5fd0322 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -1076,6 +1076,10 @@
 #ifdef CONFIG_X86_MCE
 	mcheck_init(c);
 #endif
+	if (c == &boot_cpu_data)
+		mtrr_bp_init();
+	else
+		mtrr_ap_init();
 #ifdef CONFIG_NUMA
 	if (c != &boot_cpu_data)
 		numa_add_cpu(c - cpu_data);
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c
index 6c0f402e..0612640 100644
--- a/arch/x86_64/kernel/suspend.c
+++ b/arch/x86_64/kernel/suspend.c
@@ -119,6 +119,7 @@
 	fix_processor_context();
 
 	do_fpu_end();
+	mtrr_ap_init();
 }
 
 void restore_processor_state(void)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 73389f5..61c1275 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -56,6 +56,10 @@
   .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
 	*(.data.cacheline_aligned)
   }
+  . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
+  	*(.data.read_mostly)
+  }
 
 #define VSYSCALL_ADDR (-10*1024*1024)
 #define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095))
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
index abc8ed6..7270509 100644
--- a/arch/xtensa/kernel/syscalls.c
+++ b/arch/xtensa/kernel/syscalls.c
@@ -42,12 +42,9 @@
 #include <asm/mman.h>
 #include <asm/shmparam.h>
 #include <asm/page.h>
-#include <asm/ipc.h>
 
 extern void do_syscall_trace(void);
 typedef int (*syscall_t)(void *a0,...);
-extern int (*do_syscalls)(struct pt_regs *regs, syscall_t fun,
-				     int narg);
 extern syscall_t sys_call_table[];
 extern unsigned char sys_narg_table[];
 
@@ -72,10 +69,8 @@
 /*
  * Common code for old and new mmaps.
  */
-
-static inline long do_mmap2(unsigned long addr, unsigned long len,
-    			    unsigned long prot, unsigned long flags,
-			    unsigned long fd, unsigned long pgoff)
+long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+	       unsigned long flags, unsigned long fd, unsigned long pgoff)
 {
 	int error = -EBADF;
 	struct file * file = NULL;
@@ -97,29 +92,6 @@
 	return error;
 }
 
-unsigned long old_mmap(unsigned long addr, size_t len, int prot,
-		       int flags, int fd, off_t offset)
-{
-	return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
-}
-
-long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
-	       unsigned long flags, unsigned long fd, unsigned long pgoff)
-{
-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
-int sys_fork(struct pt_regs *regs)
-{
-	return do_fork(SIGCHLD, regs->areg[1], regs, 0, NULL, NULL);
-}
-
-int sys_vfork(struct pt_regs *regs)
-{
-	return do_fork(CLONE_VFORK|CLONE_VM|SIGCHLD, regs->areg[1],
-		       regs, 0, NULL, NULL);
-}
-
 int sys_clone(struct pt_regs *regs)
 {
 	unsigned long clone_flags;
@@ -162,30 +134,6 @@
 	return -EFAULT;
 }
 
-int sys_olduname(struct oldold_utsname * name)
-{
-	int error;
-
-	if (!name)
-		return -EFAULT;
-	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
-		return -EFAULT;
-
-	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
-	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
-	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
-	error -= __put_user(0,name->release+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
-	error -= __put_user(0,name->version+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
-	error -= __put_user(0,name->machine+__OLD_UTS_LEN);
-
-	return error ? -EFAULT : 0;
-}
-
-
 /*
  * Build the string table for the builtin "poor man's strace".
  */
@@ -319,100 +267,3 @@
 	regs->areg[2] = res;
 	do_syscall_trace();
 }
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-
-int sys_ipc (uint call, int first, int second,
-			int third, void __user *ptr, long fifth)
-{
-	int version, ret;
-
-	version = call >> 16; /* hack for backward compatibility */
-	call &= 0xffff;
-	ret = -ENOSYS;
-
-	switch (call) {
-	case SEMOP:
-		ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
-				     second, NULL);
-		break;
-
-	case SEMTIMEDOP:
-		ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
-				      second, (const struct timespec *) fifth);
-		break;
-
-	case SEMGET:
-		ret = sys_semget (first, second, third);
-		break;
-
-	case SEMCTL: {
-		union semun fourth;
-
-		if (ptr && !get_user(fourth.__pad, (void *__user *) ptr))
-			ret = sys_semctl (first, second, third, fourth);
-		break;
-		}
-
-	case MSGSND:
-		ret = sys_msgsnd (first, (struct msgbuf __user*) ptr,
-				  second, third);
-		break;
-
-	case MSGRCV:
-		switch (version) {
-		case 0: {
-			struct ipc_kludge tmp;
-
-			if (ptr && !copy_from_user(&tmp,
-					   (struct ipc_kludge *) ptr,
-					   sizeof (tmp)))
-				ret = sys_msgrcv (first, tmp.msgp, second,
-						  tmp.msgtyp, third);
-			break;
-			}
-
-		default:
-			ret = sys_msgrcv (first, (struct msgbuf __user *) ptr,
-					  second, 0, third);
-			break;
-		}
-		break;
-
-	case MSGGET:
-		ret = sys_msgget ((key_t) first, second);
-		break;
-
-	case MSGCTL:
-		ret = sys_msgctl (first, second, (struct msqid_ds __user*) ptr);
-		break;
-
-	case SHMAT: {
-		ulong raddr;
-		ret = do_shmat (first, (char __user *) ptr, second, &raddr);
-
-		if (!ret)
-			ret = put_user (raddr, (ulong __user *) third);
-
-		break;
-		}
-
-	case SHMDT:
-		ret = sys_shmdt ((char __user *)ptr);
-		break;
-
-	case SHMGET:
-		ret = sys_shmget (first, second, third);
-		break;
-
-	case SHMCTL:
-		ret = sys_shmctl (first, second, (struct shmid_ds __user*) ptr);
-		break;
-	}
-	return ret;
-}
-
diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h
index 5b3f75f..0758069 100644
--- a/arch/xtensa/kernel/syscalls.h
+++ b/arch/xtensa/kernel/syscalls.h
@@ -25,20 +25,19 @@
  */
 
 SYSCALL(0, 0)		                /* 00 */
-
 SYSCALL(sys_exit, 1)
-SYSCALL(sys_fork, 0)
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_read, 3)
 SYSCALL(sys_write, 3)
 SYSCALL(sys_open, 3)			/* 05 */
 SYSCALL(sys_close, 1)
-SYSCALL(sys_waitpid, 3)
+SYSCALL(sys_ni_syscall, 3)
 SYSCALL(sys_creat, 2)
 SYSCALL(sys_link, 2)
 SYSCALL(sys_unlink, 1)			/* 10 */
 SYSCALL(sys_execve, 0)
 SYSCALL(sys_chdir, 1)
-SYSCALL(sys_time, 1)
+SYSCALL(sys_ni_syscall, 1)
 SYSCALL(sys_mknod, 3)
 SYSCALL(sys_chmod, 2)			/* 15 */
 SYSCALL(sys_lchown, 3)
@@ -47,19 +46,19 @@
 SYSCALL(sys_lseek, 3)
 SYSCALL(sys_getpid, 0)			/* 20 */
 SYSCALL(sys_mount, 5)
-SYSCALL(sys_oldumount, 1)
+SYSCALL(sys_ni_syscall, 1)
 SYSCALL(sys_setuid, 1)
 SYSCALL(sys_getuid, 0)
-SYSCALL(sys_stime, 1)			/* 25 */
+SYSCALL(sys_ni_syscall, 1)		/* 25 */
 SYSCALL(sys_ptrace, 4)
-SYSCALL(sys_alarm, 1)
+SYSCALL(sys_ni_syscall, 1)
 SYSCALL(sys_fstat, 2)
-SYSCALL(sys_pause, 0)
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_utime, 2)			/* 30 */
 SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_access, 2)
-SYSCALL(sys_nice, 1)
+SYSCALL(sys_ni_syscall, 1)
 SYSCALL(sys_ni_syscall, 0)		/* 35 */
 SYSCALL(sys_sync, 0)
 SYSCALL(sys_kill, 2)
@@ -73,7 +72,7 @@
 SYSCALL(sys_brk, 1)			/* 45 */
 SYSCALL(sys_setgid, 1)
 SYSCALL(sys_getgid, 0)
-SYSCALL(sys_ni_syscall, 0)		/* was signal(2) */
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_geteuid, 0)
 SYSCALL(sys_getegid, 0)			/* 50 */
 SYSCALL(sys_acct, 1)
@@ -84,21 +83,21 @@
 SYSCALL(sys_ni_syscall, 2)
 SYSCALL(sys_setpgid, 2)
 SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_olduname, 1)
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_umask, 1)			/* 60 */
 SYSCALL(sys_chroot, 1)
 SYSCALL(sys_ustat, 2)
 SYSCALL(sys_dup2, 2)
 SYSCALL(sys_getppid, 0)
-SYSCALL(sys_getpgrp, 0)			/* 65 */
+SYSCALL(sys_ni_syscall, 0)		/* 65 */
 SYSCALL(sys_setsid, 0)
 SYSCALL(sys_sigaction, 3)
-SYSCALL(sys_sgetmask, 0)
-SYSCALL(sys_ssetmask, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 1)
 SYSCALL(sys_setreuid, 2)		/* 70 */
 SYSCALL(sys_setregid, 2)
 SYSCALL(sys_sigsuspend, 0)
-SYSCALL(sys_sigpending, 1)
+SYSCALL(sys_ni_syscall, 1)
 SYSCALL(sys_sethostname, 2)
 SYSCALL(sys_setrlimit, 2)		/* 75 */
 SYSCALL(sys_getrlimit, 2)
@@ -107,15 +106,15 @@
 SYSCALL(sys_settimeofday, 2)
 SYSCALL(sys_getgroups, 2)		/* 80 */
 SYSCALL(sys_setgroups, 2)
-SYSCALL(sys_ni_syscall, 0)		 /* old_select */
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_symlink, 2)
 SYSCALL(sys_lstat, 2)
 SYSCALL(sys_readlink, 3)		/* 85 */
 SYSCALL(sys_uselib, 1)
 SYSCALL(sys_swapon, 2)
 SYSCALL(sys_reboot, 3)
-SYSCALL(old_readdir, 3)
-SYSCALL(old_mmap, 6)			/* 90 */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 6)		/* 90 */
 SYSCALL(sys_munmap, 2)
 SYSCALL(sys_truncate, 2)
 SYSCALL(sys_ftruncate, 2)
@@ -127,7 +126,7 @@
 SYSCALL(sys_statfs, 2)
 SYSCALL(sys_fstatfs, 2)			/* 100 */
 SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_socketcall, 2)
+SYSCALL(sys_ni_syscall, 2)
 SYSCALL(sys_syslog, 3)
 SYSCALL(sys_setitimer, 3)
 SYSCALL(sys_getitimer, 2)		/* 105 */
@@ -137,32 +136,32 @@
 SYSCALL(sys_uname, 1)
 SYSCALL(sys_ni_syscall, 0)		/* 110 */
 SYSCALL(sys_vhangup, 0)
-SYSCALL(sys_ni_syscall, 0)		/* was sys_idle() */
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_wait4, 4)
 SYSCALL(sys_swapoff, 1)			/* 115 */
 SYSCALL(sys_sysinfo, 1)
-SYSCALL(sys_ipc, 5)   			/* 6 really, but glibc uses only 5) */
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_fsync, 1)
 SYSCALL(sys_sigreturn, 0)
 SYSCALL(sys_clone, 0)			/* 120 */
 SYSCALL(sys_setdomainname, 2)
 SYSCALL(sys_newuname, 1)
-SYSCALL(sys_ni_syscall, 0) 		/* sys_modify_ldt */
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_adjtimex, 1)
 SYSCALL(sys_mprotect, 3)		/* 125 */
-SYSCALL(sys_sigprocmask, 3)
-SYSCALL(sys_ni_syscall, 2)		/* old sys_create_module */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 2)
 SYSCALL(sys_init_module, 2)
 SYSCALL(sys_delete_module, 1)
-SYSCALL(sys_ni_syscall, 1)		/* old sys_get_kernel_sysm */	/* 130 */
+SYSCALL(sys_ni_syscall, 1)		/* 130 */
 SYSCALL(sys_quotactl, 0)
 SYSCALL(sys_getpgid, 1)
 SYSCALL(sys_fchdir, 1)
 SYSCALL(sys_bdflush, 2)
 SYSCALL(sys_sysfs, 3)			/* 135 */
 SYSCALL(sys_personality, 1)
-SYSCALL(sys_ni_syscall, 0)		/* for afs_syscall */
+SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_setfsuid, 1)
 SYSCALL(sys_setfsgid, 1)
 SYSCALL(sys_llseek, 5)			/* 140 */
@@ -212,7 +211,7 @@
 SYSCALL(sys_socketpair, 4)
 SYSCALL(sys_setresuid, 3)		/* 185 */
 SYSCALL(sys_getresuid, 3)
-SYSCALL(sys_ni_syscall, 5)		/* old sys_query_module */
+SYSCALL(sys_ni_syscall, 5)
 SYSCALL(sys_poll, 3)
 SYSCALL(sys_nfsservctl, 3)
 SYSCALL(sys_setresgid, 3)		/* 190 */
@@ -235,7 +234,7 @@
 SYSCALL(sys_sendfile, 4)
 SYSCALL(sys_ni_syscall, 0)
 SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_mmap2, 6)			/* 210 */
+SYSCALL(sys_mmap, 6)			/* 210 */
 SYSCALL(sys_truncate64, 2)
 SYSCALL(sys_ftruncate64, 2)
 SYSCALL(sys_stat64, 2)
@@ -245,4 +244,4 @@
 SYSCALL(sys_mincore, 3)
 SYSCALL(sys_madvise, 3)
 SYSCALL(sys_getdents64, 3)
-SYSCALL(sys_vfork, 0)			/* 220 */
+SYSCALL(sys_ni_syscall, 0)		/* 220 */
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 90d6089..256c0b1 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -146,7 +146,7 @@
 
 config CRYPTO_AES
 	tristate "AES cipher algorithms"
-	depends on CRYPTO && !((X86 || UML_X86) && !64BIT)
+	depends on CRYPTO && !(X86 || UML_X86)
 	help
 	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
 	  algorithm.
@@ -184,6 +184,26 @@
 
 	  See <http://csrc.nist.gov/encryption/aes/> for more information.
 
+config CRYPTO_AES_X86_64
+	tristate "AES cipher algorithms (x86_64)"
+	depends on CRYPTO && ((X86 || UML_X86) && 64BIT)
+	help
+	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
+	  algorithm.
+
+	  Rijndael appears to be consistently a very good performer in
+	  both hardware and software across a wide range of computing 
+	  environments regardless of its use in feedback or non-feedback 
+	  modes. Its key setup time is excellent, and its key agility is 
+	  good. Rijndael's very low memory requirements make it very well 
+	  suited for restricted-space environments, in which it also 
+	  demonstrates excellent performance. Rijndael's operations are 
+	  among the easiest to defend against power and timing attacks.	
+
+	  The AES specifies three key sizes: 128, 192 and 256 bits	  
+
+	  See <http://csrc.nist.gov/encryption/aes/> for more information.
+
 config CRYPTO_CAST5
 	tristate "CAST5 (CAST-128) cipher algorithm"
 	depends on CRYPTO
diff --git a/crypto/api.c b/crypto/api.c
index 394169a..b472881 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -13,9 +13,12 @@
  * any later version.
  *
  */
+
+#include <linux/compiler.h>
 #include <linux/init.h>
 #include <linux/crypto.h>
 #include <linux/errno.h>
+#include <linux/kmod.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
 #include "internal.h"
@@ -33,7 +36,7 @@
 	module_put(alg->cra_module);
 }
 
-struct crypto_alg *crypto_alg_lookup(const char *name)
+static struct crypto_alg *crypto_alg_lookup(const char *name)
 {
 	struct crypto_alg *q, *alg = NULL;
 
@@ -54,6 +57,13 @@
 	return alg;
 }
 
+/* A far more intelligent version of this is planned.  For now, just
+ * try an exact match on the name of the algorithm. */
+static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
+{
+	return try_then_request_module(crypto_alg_lookup(name), name);
+}
+
 static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
 {
 	tfm->crt_flags = 0;
@@ -117,20 +127,46 @@
 	}
 }
 
+static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags)
+{
+	unsigned int len;
+
+	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+	default:
+		BUG();
+
+	case CRYPTO_ALG_TYPE_CIPHER:
+		len = crypto_cipher_ctxsize(alg, flags);
+		break;
+		
+	case CRYPTO_ALG_TYPE_DIGEST:
+		len = crypto_digest_ctxsize(alg, flags);
+		break;
+		
+	case CRYPTO_ALG_TYPE_COMPRESS:
+		len = crypto_compress_ctxsize(alg, flags);
+		break;
+	}
+
+	return len + alg->cra_alignmask;
+}
+
 struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
 {
 	struct crypto_tfm *tfm = NULL;
 	struct crypto_alg *alg;
+	unsigned int tfm_size;
 
 	alg = crypto_alg_mod_lookup(name);
 	if (alg == NULL)
 		goto out;
-	
-	tfm = kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL);
+
+	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
+	tfm = kmalloc(tfm_size, GFP_KERNEL);
 	if (tfm == NULL)
 		goto out_put;
 
-	memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize);
+	memset(tfm, 0, tfm_size);
 	
 	tfm->__crt_alg = alg;
 	
@@ -155,8 +191,14 @@
 
 void crypto_free_tfm(struct crypto_tfm *tfm)
 {
-	struct crypto_alg *alg = tfm->__crt_alg;
-	int size = sizeof(*tfm) + alg->cra_ctxsize;
+	struct crypto_alg *alg;
+	int size;
+
+	if (unlikely(!tfm))
+		return;
+
+	alg = tfm->__crt_alg;
+	size = sizeof(*tfm) + alg->cra_ctxsize;
 
 	crypto_exit_ops(tfm);
 	crypto_alg_put(alg);
@@ -168,6 +210,12 @@
 {
 	int ret = 0;
 	struct crypto_alg *q;
+
+	if (alg->cra_alignmask & (alg->cra_alignmask + 1))
+		return -EINVAL;
+
+	if (alg->cra_alignmask > PAGE_SIZE)
+		return -EINVAL;
 	
 	down_write(&crypto_alg_sem);
 	
diff --git a/crypto/cipher.c b/crypto/cipher.c
index f434ce7..1c92c6b 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -4,6 +4,7 @@
  * Cipher operations.
  *
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -22,10 +23,6 @@
 #include "internal.h"
 #include "scatterwalk.h"
 
-typedef void (cryptfn_t)(void *, u8 *, const u8 *);
-typedef void (procfn_t)(struct crypto_tfm *, u8 *,
-                        u8*, cryptfn_t, void *);
-
 static inline void xor_64(u8 *a, const u8 *b)
 {
 	((u32 *)a)[0] ^= ((u32 *)b)[0];
@@ -39,63 +36,70 @@
 	((u32 *)a)[2] ^= ((u32 *)b)[2];
 	((u32 *)a)[3] ^= ((u32 *)b)[3];
 }
- 
-static inline void *prepare_src(struct scatter_walk *walk, int bsize,
-				void *tmp, int in_place)
-{
-	void *src = walk->data;
-	int n = bsize;
 
-	if (unlikely(scatterwalk_across_pages(walk, bsize))) {
+static unsigned int crypt_slow(const struct cipher_desc *desc,
+			       struct scatter_walk *in,
+			       struct scatter_walk *out, unsigned int bsize)
+{
+	unsigned int alignmask = crypto_tfm_alg_alignmask(desc->tfm);
+	u8 buffer[bsize * 2 + alignmask];
+	u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+	u8 *dst = src + bsize;
+	unsigned int n;
+
+	n = scatterwalk_copychunks(src, in, bsize, 0);
+	scatterwalk_advance(in, n);
+
+	desc->prfn(desc, dst, src, bsize);
+
+	n = scatterwalk_copychunks(dst, out, bsize, 1);
+	scatterwalk_advance(out, n);
+
+	return bsize;
+}
+
+static inline unsigned int crypt_fast(const struct cipher_desc *desc,
+				      struct scatter_walk *in,
+				      struct scatter_walk *out,
+				      unsigned int nbytes, u8 *tmp)
+{
+	u8 *src, *dst;
+
+	src = in->data;
+	dst = scatterwalk_samebuf(in, out) ? src : out->data;
+
+	if (tmp) {
+		memcpy(tmp, in->data, nbytes);
 		src = tmp;
-		n = scatterwalk_copychunks(src, walk, bsize, 0);
-	}
-	scatterwalk_advance(walk, n);
-	return src;
-}
-
-static inline void *prepare_dst(struct scatter_walk *walk, int bsize,
-				void *tmp, int in_place)
-{
-	void *dst = walk->data;
-
-	if (unlikely(scatterwalk_across_pages(walk, bsize)) || in_place)
 		dst = tmp;
-	return dst;
-}
+	}
 
-static inline void complete_src(struct scatter_walk *walk, int bsize,
-				void *src, int in_place)
-{
-}
+	nbytes = desc->prfn(desc, dst, src, nbytes);
 
-static inline void complete_dst(struct scatter_walk *walk, int bsize,
-				void *dst, int in_place)
-{
-	int n = bsize;
+	if (tmp)
+		memcpy(out->data, tmp, nbytes);
 
-	if (unlikely(scatterwalk_across_pages(walk, bsize)))
-		n = scatterwalk_copychunks(dst, walk, bsize, 1);
-	else if (in_place)
-		memcpy(walk->data, dst, bsize);
-	scatterwalk_advance(walk, n);
+	scatterwalk_advance(in, nbytes);
+	scatterwalk_advance(out, nbytes);
+
+	return nbytes;
 }
 
 /* 
  * Generic encrypt/decrypt wrapper for ciphers, handles operations across
  * multiple page boundaries by using temporary blocks.  In user context,
- * the kernel is given a chance to schedule us once per block.
+ * the kernel is given a chance to schedule us once per page.
  */
-static int crypt(struct crypto_tfm *tfm,
+static int crypt(const struct cipher_desc *desc,
 		 struct scatterlist *dst,
 		 struct scatterlist *src,
-                 unsigned int nbytes, cryptfn_t crfn,
-                 procfn_t prfn, void *info)
+		 unsigned int nbytes)
 {
 	struct scatter_walk walk_in, walk_out;
+	struct crypto_tfm *tfm = desc->tfm;
 	const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
-	u8 tmp_src[bsize];
-	u8 tmp_dst[bsize];
+	unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
+	unsigned long buffer = 0;
 
 	if (!nbytes)
 		return 0;
@@ -109,64 +113,144 @@
 	scatterwalk_start(&walk_out, dst);
 
 	for(;;) {
-		u8 *src_p, *dst_p;
-		int in_place;
+		unsigned int n = nbytes;
+		u8 *tmp = NULL;
+
+		if (!scatterwalk_aligned(&walk_in, alignmask) ||
+		    !scatterwalk_aligned(&walk_out, alignmask)) {
+			if (!buffer) {
+				buffer = __get_free_page(GFP_ATOMIC);
+				if (!buffer)
+					n = 0;
+			}
+			tmp = (u8 *)buffer;
+		}
 
 		scatterwalk_map(&walk_in, 0);
 		scatterwalk_map(&walk_out, 1);
 
-		in_place = scatterwalk_samebuf(&walk_in, &walk_out);
+		n = scatterwalk_clamp(&walk_in, n);
+		n = scatterwalk_clamp(&walk_out, n);
 
-		do {
-			src_p = prepare_src(&walk_in, bsize, tmp_src,
-					    in_place);
-			dst_p = prepare_dst(&walk_out, bsize, tmp_dst,
-					    in_place);
+		if (likely(n >= bsize))
+			n = crypt_fast(desc, &walk_in, &walk_out, n, tmp);
+		else
+			n = crypt_slow(desc, &walk_in, &walk_out, bsize);
 
-			prfn(tfm, dst_p, src_p, crfn, info);
-
-			complete_src(&walk_in, bsize, src_p, in_place);
-			complete_dst(&walk_out, bsize, dst_p, in_place);
-
-			nbytes -= bsize;
-		} while (nbytes &&
-			 !scatterwalk_across_pages(&walk_in, bsize) &&
-			 !scatterwalk_across_pages(&walk_out, bsize));
+		nbytes -= n;
 
 		scatterwalk_done(&walk_in, 0, nbytes);
 		scatterwalk_done(&walk_out, 1, nbytes);
 
 		if (!nbytes)
-			return 0;
+			break;
 
 		crypto_yield(tfm);
 	}
+
+	if (buffer)
+		free_page(buffer);
+
+	return 0;
 }
 
-static void cbc_process_encrypt(struct crypto_tfm *tfm, u8 *dst, u8 *src,
-				cryptfn_t fn, void *info)
+static int crypt_iv_unaligned(struct cipher_desc *desc,
+			      struct scatterlist *dst,
+			      struct scatterlist *src,
+			      unsigned int nbytes)
 {
-	u8 *iv = info;
+	struct crypto_tfm *tfm = desc->tfm;
+	unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
+	u8 *iv = desc->info;
 
-	tfm->crt_u.cipher.cit_xor_block(iv, src);
-	fn(crypto_tfm_ctx(tfm), dst, iv);
-	memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm));
+	if (unlikely(((unsigned long)iv & alignmask))) {
+		unsigned int ivsize = tfm->crt_cipher.cit_ivsize;
+		u8 buffer[ivsize + alignmask];
+		u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+		int err;
+
+		desc->info = memcpy(tmp, iv, ivsize);
+		err = crypt(desc, dst, src, nbytes);
+		memcpy(iv, tmp, ivsize);
+
+		return err;
+	}
+
+	return crypt(desc, dst, src, nbytes);
 }
 
-static void cbc_process_decrypt(struct crypto_tfm *tfm, u8 *dst, u8 *src,
-				cryptfn_t fn, void *info)
+static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
+					u8 *dst, const u8 *src,
+					unsigned int nbytes)
 {
-	u8 *iv = info;
+	struct crypto_tfm *tfm = desc->tfm;
+	void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
+	int bsize = crypto_tfm_alg_blocksize(tfm);
 
-	fn(crypto_tfm_ctx(tfm), dst, src);
-	tfm->crt_u.cipher.cit_xor_block(dst, iv);
-	memcpy(iv, src, crypto_tfm_alg_blocksize(tfm));
+	void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+	u8 *iv = desc->info;
+	unsigned int done = 0;
+
+	do {
+		xor(iv, src);
+		fn(crypto_tfm_ctx(tfm), dst, iv);
+		memcpy(iv, dst, bsize);
+
+		src += bsize;
+		dst += bsize;
+	} while ((done += bsize) < nbytes);
+
+	return done;
 }
 
-static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
-			cryptfn_t fn, void *info)
+static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
+					u8 *dst, const u8 *src,
+					unsigned int nbytes)
 {
-	fn(crypto_tfm_ctx(tfm), dst, src);
+	struct crypto_tfm *tfm = desc->tfm;
+	void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
+	int bsize = crypto_tfm_alg_blocksize(tfm);
+
+	u8 stack[src == dst ? bsize : 0];
+	u8 *buf = stack;
+	u8 **dst_p = src == dst ? &buf : &dst;
+
+	void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+	u8 *iv = desc->info;
+	unsigned int done = 0;
+
+	do {
+		u8 *tmp_dst = *dst_p;
+
+		fn(crypto_tfm_ctx(tfm), tmp_dst, src);
+		xor(tmp_dst, iv);
+		memcpy(iv, src, bsize);
+		if (tmp_dst != dst)
+			memcpy(dst, tmp_dst, bsize);
+
+		src += bsize;
+		dst += bsize;
+	} while ((done += bsize) < nbytes);
+
+	return done;
+}
+
+static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst,
+				const u8 *src, unsigned int nbytes)
+{
+	struct crypto_tfm *tfm = desc->tfm;
+	int bsize = crypto_tfm_alg_blocksize(tfm);
+	void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+	unsigned int done = 0;
+
+	do {
+		fn(crypto_tfm_ctx(tfm), dst, src);
+
+		src += bsize;
+		dst += bsize;
+	} while ((done += bsize) < nbytes);
+
+	return done;
 }
 
 static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
@@ -185,9 +269,14 @@
 		       struct scatterlist *dst,
                        struct scatterlist *src, unsigned int nbytes)
 {
-	return crypt(tfm, dst, src, nbytes,
-	             tfm->__crt_alg->cra_cipher.cia_encrypt,
-	             ecb_process, NULL);
+	struct cipher_desc desc;
+	struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+	desc.tfm = tfm;
+	desc.crfn = cipher->cia_encrypt;
+	desc.prfn = cipher->cia_encrypt_ecb ?: ecb_process;
+
+	return crypt(&desc, dst, src, nbytes);
 }
 
 static int ecb_decrypt(struct crypto_tfm *tfm,
@@ -195,9 +284,14 @@
                        struct scatterlist *src,
 		       unsigned int nbytes)
 {
-	return crypt(tfm, dst, src, nbytes,
-	             tfm->__crt_alg->cra_cipher.cia_decrypt,
-	             ecb_process, NULL);
+	struct cipher_desc desc;
+	struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+	desc.tfm = tfm;
+	desc.crfn = cipher->cia_decrypt;
+	desc.prfn = cipher->cia_decrypt_ecb ?: ecb_process;
+
+	return crypt(&desc, dst, src, nbytes);
 }
 
 static int cbc_encrypt(struct crypto_tfm *tfm,
@@ -205,9 +299,15 @@
                        struct scatterlist *src,
 		       unsigned int nbytes)
 {
-	return crypt(tfm, dst, src, nbytes,
-	             tfm->__crt_alg->cra_cipher.cia_encrypt,
-	             cbc_process_encrypt, tfm->crt_cipher.cit_iv);
+	struct cipher_desc desc;
+	struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+	desc.tfm = tfm;
+	desc.crfn = cipher->cia_encrypt;
+	desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
+	desc.info = tfm->crt_cipher.cit_iv;
+
+	return crypt(&desc, dst, src, nbytes);
 }
 
 static int cbc_encrypt_iv(struct crypto_tfm *tfm,
@@ -215,9 +315,15 @@
                           struct scatterlist *src,
                           unsigned int nbytes, u8 *iv)
 {
-	return crypt(tfm, dst, src, nbytes,
-	             tfm->__crt_alg->cra_cipher.cia_encrypt,
-	             cbc_process_encrypt, iv);
+	struct cipher_desc desc;
+	struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+	desc.tfm = tfm;
+	desc.crfn = cipher->cia_encrypt;
+	desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
+	desc.info = iv;
+
+	return crypt_iv_unaligned(&desc, dst, src, nbytes);
 }
 
 static int cbc_decrypt(struct crypto_tfm *tfm,
@@ -225,9 +331,15 @@
                        struct scatterlist *src,
 		       unsigned int nbytes)
 {
-	return crypt(tfm, dst, src, nbytes,
-	             tfm->__crt_alg->cra_cipher.cia_decrypt,
-	             cbc_process_decrypt, tfm->crt_cipher.cit_iv);
+	struct cipher_desc desc;
+	struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+	desc.tfm = tfm;
+	desc.crfn = cipher->cia_decrypt;
+	desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
+	desc.info = tfm->crt_cipher.cit_iv;
+
+	return crypt(&desc, dst, src, nbytes);
 }
 
 static int cbc_decrypt_iv(struct crypto_tfm *tfm,
@@ -235,9 +347,15 @@
                           struct scatterlist *src,
                           unsigned int nbytes, u8 *iv)
 {
-	return crypt(tfm, dst, src, nbytes,
-	             tfm->__crt_alg->cra_cipher.cia_decrypt,
-	             cbc_process_decrypt, iv);
+	struct cipher_desc desc;
+	struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+	desc.tfm = tfm;
+	desc.crfn = cipher->cia_decrypt;
+	desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
+	desc.info = iv;
+
+	return crypt_iv_unaligned(&desc, dst, src, nbytes);
 }
 
 static int nocrypt(struct crypto_tfm *tfm,
@@ -306,6 +424,8 @@
 	}
 	
 	if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) {
+		unsigned int align;
+		unsigned long addr;
 	    	
 	    	switch (crypto_tfm_alg_blocksize(tfm)) {
 	    	case 8:
@@ -325,9 +445,11 @@
 	    	}
 	    	
 		ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm);
-	    	ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL);
-		if (ops->cit_iv == NULL)
-			ret = -ENOMEM;
+		align = crypto_tfm_alg_alignmask(tfm) + 1;
+		addr = (unsigned long)crypto_tfm_ctx(tfm);
+		addr = ALIGN(addr, align);
+		addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align);
+		ops->cit_iv = (void *)addr;
 	}
 
 out:	
@@ -336,6 +458,4 @@
 
 void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
 {
-	if (tfm->crt_cipher.cit_iv)
-		kfree(tfm->crt_cipher.cit_iv);
 }
diff --git a/crypto/des.c b/crypto/des.c
index 1c7e6de..a3c863d 100644
--- a/crypto/des.c
+++ b/crypto/des.c
@@ -1,18 +1,9 @@
-/* 
+/*
  * Cryptographic API.
  *
  * DES & Triple DES EDE Cipher Algorithms.
  *
- * Originally released as descore by Dana L. How <how@isl.stanford.edu>.
- * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel.
- * Derived from Cryptoapi and Nettle implementations, adapted for in-place
- * scatterlist interface.  Changed LGPL to GPL per section 3 of the LGPL.
- *
- * Copyright (c) 1992 Dana L. How.
- * Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de> 
- * Copyright (c) Gisle Sælensminde <gisle@ii.uib.no>
- * Copyright (C) 2001 Niels Möller.
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2005 Dag Arne Osvik <da@osvik.no>
  *
  * 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
@@ -20,11 +11,11 @@
  * (at your option) any later version.
  *
  */
+
+#include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/mm.h>
 #include <linux/errno.h>
-#include <asm/scatterlist.h>
 #include <linux/crypto.h>
 
 #define DES_KEY_SIZE		8
@@ -35,1157 +26,826 @@
 #define DES3_EDE_EXPKEY_WORDS	(3 * DES_EXPKEY_WORDS)
 #define DES3_EDE_BLOCK_SIZE	DES_BLOCK_SIZE
 
-#define ROR(d,c,o)	((d) = (d) >> (c) | (d) << (o))
+#define ROL(x, r) ((x) = rol32((x), (r)))
+#define ROR(x, r) ((x) = ror32((x), (r)))
 
 struct des_ctx {
-	u8 iv[DES_BLOCK_SIZE];
 	u32 expkey[DES_EXPKEY_WORDS];
 };
 
 struct des3_ede_ctx {
-	u8 iv[DES_BLOCK_SIZE];
 	u32 expkey[DES3_EDE_EXPKEY_WORDS];
 };
 
-static const u32 des_keymap[] = {
-	0x02080008, 0x02082000, 0x00002008, 0x00000000,
-	0x02002000, 0x00080008, 0x02080000, 0x02082008,
-	0x00000008, 0x02000000, 0x00082000, 0x00002008,
-	0x00082008, 0x02002008, 0x02000008, 0x02080000,
-	0x00002000, 0x00082008, 0x00080008, 0x02002000,
-	0x02082008, 0x02000008, 0x00000000, 0x00082000,
-	0x02000000, 0x00080000, 0x02002008, 0x02080008,
-	0x00080000, 0x00002000, 0x02082000, 0x00000008,
-	0x00080000, 0x00002000, 0x02000008, 0x02082008,
-	0x00002008, 0x02000000, 0x00000000, 0x00082000,
-	0x02080008, 0x02002008, 0x02002000, 0x00080008,
-	0x02082000, 0x00000008, 0x00080008, 0x02002000,
-	0x02082008, 0x00080000, 0x02080000, 0x02000008,
-	0x00082000, 0x00002008, 0x02002008, 0x02080000,
-	0x00000008, 0x02082000, 0x00082008, 0x00000000,
-	0x02000000, 0x02080008, 0x00002000, 0x00082008,
+/* Lookup tables for key expansion */
 
-	0x08000004, 0x00020004, 0x00000000, 0x08020200,
-	0x00020004, 0x00000200, 0x08000204, 0x00020000,
-	0x00000204, 0x08020204, 0x00020200, 0x08000000,
-	0x08000200, 0x08000004, 0x08020000, 0x00020204,
-	0x00020000, 0x08000204, 0x08020004, 0x00000000,
-	0x00000200, 0x00000004, 0x08020200, 0x08020004,
-	0x08020204, 0x08020000, 0x08000000, 0x00000204,
-	0x00000004, 0x00020200, 0x00020204, 0x08000200,
-	0x00000204, 0x08000000, 0x08000200, 0x00020204,
-	0x08020200, 0x00020004, 0x00000000, 0x08000200,
-	0x08000000, 0x00000200, 0x08020004, 0x00020000,
-	0x00020004, 0x08020204, 0x00020200, 0x00000004,
-	0x08020204, 0x00020200, 0x00020000, 0x08000204,
-	0x08000004, 0x08020000, 0x00020204, 0x00000000,
-	0x00000200, 0x08000004, 0x08000204, 0x08020200,
-	0x08020000, 0x00000204, 0x00000004, 0x08020004,
-
-	0x80040100, 0x01000100, 0x80000000, 0x81040100,
-	0x00000000, 0x01040000, 0x81000100, 0x80040000,
-	0x01040100, 0x81000000, 0x01000000, 0x80000100,
-	0x81000000, 0x80040100, 0x00040000, 0x01000000,
-	0x81040000, 0x00040100, 0x00000100, 0x80000000,
-	0x00040100, 0x81000100, 0x01040000, 0x00000100,
-	0x80000100, 0x00000000, 0x80040000, 0x01040100,
-	0x01000100, 0x81040000, 0x81040100, 0x00040000,
-	0x81040000, 0x80000100, 0x00040000, 0x81000000,
-	0x00040100, 0x01000100, 0x80000000, 0x01040000,
-	0x81000100, 0x00000000, 0x00000100, 0x80040000,
-	0x00000000, 0x81040000, 0x01040100, 0x00000100,
-	0x01000000, 0x81040100, 0x80040100, 0x00040000,
-	0x81040100, 0x80000000, 0x01000100, 0x80040100,
-	0x80040000, 0x00040100, 0x01040000, 0x81000100,
-	0x80000100, 0x01000000, 0x81000000, 0x01040100,
-
-	0x04010801, 0x00000000, 0x00010800, 0x04010000,
-	0x04000001, 0x00000801, 0x04000800, 0x00010800,
-	0x00000800, 0x04010001, 0x00000001, 0x04000800,
-	0x00010001, 0x04010800, 0x04010000, 0x00000001,
-	0x00010000, 0x04000801, 0x04010001, 0x00000800,
-	0x00010801, 0x04000000, 0x00000000, 0x00010001,
-	0x04000801, 0x00010801, 0x04010800, 0x04000001,
-	0x04000000, 0x00010000, 0x00000801, 0x04010801,
-	0x00010001, 0x04010800, 0x04000800, 0x00010801,
-	0x04010801, 0x00010001, 0x04000001, 0x00000000,
-	0x04000000, 0x00000801, 0x00010000, 0x04010001,
-	0x00000800, 0x04000000, 0x00010801, 0x04000801,
-	0x04010800, 0x00000800, 0x00000000, 0x04000001,
-	0x00000001, 0x04010801, 0x00010800, 0x04010000,
-	0x04010001, 0x00010000, 0x00000801, 0x04000800,
-	0x04000801, 0x00000001, 0x04010000, 0x00010800,
-
-	0x00000400, 0x00000020, 0x00100020, 0x40100000,
-	0x40100420, 0x40000400, 0x00000420, 0x00000000,
-	0x00100000, 0x40100020, 0x40000020, 0x00100400,
-	0x40000000, 0x00100420, 0x00100400, 0x40000020,
-	0x40100020, 0x00000400, 0x40000400, 0x40100420,
-	0x00000000, 0x00100020, 0x40100000, 0x00000420,
-	0x40100400, 0x40000420, 0x00100420, 0x40000000,
-	0x40000420, 0x40100400, 0x00000020, 0x00100000,
-	0x40000420, 0x00100400, 0x40100400, 0x40000020,
-	0x00000400, 0x00000020, 0x00100000, 0x40100400,
-	0x40100020, 0x40000420, 0x00000420, 0x00000000,
-	0x00000020, 0x40100000, 0x40000000, 0x00100020,
-	0x00000000, 0x40100020, 0x00100020, 0x00000420,
-	0x40000020, 0x00000400, 0x40100420, 0x00100000,
-	0x00100420, 0x40000000, 0x40000400, 0x40100420,
-	0x40100000, 0x00100420, 0x00100400, 0x40000400,
-
-	0x00800000, 0x00001000, 0x00000040, 0x00801042,
-	0x00801002, 0x00800040, 0x00001042, 0x00801000,
-	0x00001000, 0x00000002, 0x00800002, 0x00001040,
-	0x00800042, 0x00801002, 0x00801040, 0x00000000,
-	0x00001040, 0x00800000, 0x00001002, 0x00000042,
-	0x00800040, 0x00001042, 0x00000000, 0x00800002,
-	0x00000002, 0x00800042, 0x00801042, 0x00001002,
-	0x00801000, 0x00000040, 0x00000042, 0x00801040,
-	0x00801040, 0x00800042, 0x00001002, 0x00801000,
-	0x00001000, 0x00000002, 0x00800002, 0x00800040,
-	0x00800000, 0x00001040, 0x00801042, 0x00000000,
-	0x00001042, 0x00800000, 0x00000040, 0x00001002,
-	0x00800042, 0x00000040, 0x00000000, 0x00801042,
-	0x00801002, 0x00801040, 0x00000042, 0x00001000,
-	0x00001040, 0x00801002, 0x00800040, 0x00000042,
-	0x00000002, 0x00001042, 0x00801000, 0x00800002,
-
-	0x10400000, 0x00404010, 0x00000010, 0x10400010,
-	0x10004000, 0x00400000, 0x10400010, 0x00004010,
-	0x00400010, 0x00004000, 0x00404000, 0x10000000,
-	0x10404010, 0x10000010, 0x10000000, 0x10404000,
-	0x00000000, 0x10004000, 0x00404010, 0x00000010,
-	0x10000010, 0x10404010, 0x00004000, 0x10400000,
-	0x10404000, 0x00400010, 0x10004010, 0x00404000,
-	0x00004010, 0x00000000, 0x00400000, 0x10004010,
-	0x00404010, 0x00000010, 0x10000000, 0x00004000,
-	0x10000010, 0x10004000, 0x00404000, 0x10400010,
-	0x00000000, 0x00404010, 0x00004010, 0x10404000,
-	0x10004000, 0x00400000, 0x10404010, 0x10000000,
-	0x10004010, 0x10400000, 0x00400000, 0x10404010,
-	0x00004000, 0x00400010, 0x10400010, 0x00004010,
-	0x00400010, 0x00000000, 0x10404000, 0x10000010,
-	0x10400000, 0x10004010, 0x00000010, 0x00404000,
-
-	0x00208080, 0x00008000, 0x20200000, 0x20208080,
-	0x00200000, 0x20008080, 0x20008000, 0x20200000,
-	0x20008080, 0x00208080, 0x00208000, 0x20000080,
-	0x20200080, 0x00200000, 0x00000000, 0x20008000,
-	0x00008000, 0x20000000, 0x00200080, 0x00008080,
-	0x20208080, 0x00208000, 0x20000080, 0x00200080,
-	0x20000000, 0x00000080, 0x00008080, 0x20208000,
-	0x00000080, 0x20200080, 0x20208000, 0x00000000,
-	0x00000000, 0x20208080, 0x00200080, 0x20008000,
-	0x00208080, 0x00008000, 0x20000080, 0x00200080,
-	0x20208000, 0x00000080, 0x00008080, 0x20200000,
-	0x20008080, 0x20000000, 0x20200000, 0x00208000,
-	0x20208080, 0x00008080, 0x00208000, 0x20200080,
-	0x00200000, 0x20000080, 0x20008000, 0x00000000,
-	0x00008000, 0x00200000, 0x20200080, 0x00208080,
-	0x20000000, 0x20208000, 0x00000080, 0x20008080,
+static const u8 pc1[256] = {
+	0x00, 0x00, 0x40, 0x04, 0x10, 0x10, 0x50, 0x14,
+	0x04, 0x40, 0x44, 0x44, 0x14, 0x50, 0x54, 0x54,
+	0x02, 0x02, 0x42, 0x06, 0x12, 0x12, 0x52, 0x16,
+	0x06, 0x42, 0x46, 0x46, 0x16, 0x52, 0x56, 0x56,
+	0x80, 0x08, 0xc0, 0x0c, 0x90, 0x18, 0xd0, 0x1c,
+	0x84, 0x48, 0xc4, 0x4c, 0x94, 0x58, 0xd4, 0x5c,
+	0x82, 0x0a, 0xc2, 0x0e, 0x92, 0x1a, 0xd2, 0x1e,
+	0x86, 0x4a, 0xc6, 0x4e, 0x96, 0x5a, 0xd6, 0x5e,
+	0x20, 0x20, 0x60, 0x24, 0x30, 0x30, 0x70, 0x34,
+	0x24, 0x60, 0x64, 0x64, 0x34, 0x70, 0x74, 0x74,
+	0x22, 0x22, 0x62, 0x26, 0x32, 0x32, 0x72, 0x36,
+	0x26, 0x62, 0x66, 0x66, 0x36, 0x72, 0x76, 0x76,
+	0xa0, 0x28, 0xe0, 0x2c, 0xb0, 0x38, 0xf0, 0x3c,
+	0xa4, 0x68, 0xe4, 0x6c, 0xb4, 0x78, 0xf4, 0x7c,
+	0xa2, 0x2a, 0xe2, 0x2e, 0xb2, 0x3a, 0xf2, 0x3e,
+	0xa6, 0x6a, 0xe6, 0x6e, 0xb6, 0x7a, 0xf6, 0x7e,
+	0x08, 0x80, 0x48, 0x84, 0x18, 0x90, 0x58, 0x94,
+	0x0c, 0xc0, 0x4c, 0xc4, 0x1c, 0xd0, 0x5c, 0xd4,
+	0x0a, 0x82, 0x4a, 0x86, 0x1a, 0x92, 0x5a, 0x96,
+	0x0e, 0xc2, 0x4e, 0xc6, 0x1e, 0xd2, 0x5e, 0xd6,
+	0x88, 0x88, 0xc8, 0x8c, 0x98, 0x98, 0xd8, 0x9c,
+	0x8c, 0xc8, 0xcc, 0xcc, 0x9c, 0xd8, 0xdc, 0xdc,
+	0x8a, 0x8a, 0xca, 0x8e, 0x9a, 0x9a, 0xda, 0x9e,
+	0x8e, 0xca, 0xce, 0xce, 0x9e, 0xda, 0xde, 0xde,
+	0x28, 0xa0, 0x68, 0xa4, 0x38, 0xb0, 0x78, 0xb4,
+	0x2c, 0xe0, 0x6c, 0xe4, 0x3c, 0xf0, 0x7c, 0xf4,
+	0x2a, 0xa2, 0x6a, 0xa6, 0x3a, 0xb2, 0x7a, 0xb6,
+	0x2e, 0xe2, 0x6e, 0xe6, 0x3e, 0xf2, 0x7e, 0xf6,
+	0xa8, 0xa8, 0xe8, 0xac, 0xb8, 0xb8, 0xf8, 0xbc,
+	0xac, 0xe8, 0xec, 0xec, 0xbc, 0xf8, 0xfc, 0xfc,
+	0xaa, 0xaa, 0xea, 0xae, 0xba, 0xba, 0xfa, 0xbe,
+	0xae, 0xea, 0xee, 0xee, 0xbe, 0xfa, 0xfe, 0xfe
 };
 
-static const u8 rotors[] = {
-	34, 13,  5, 46, 47, 18, 32, 41, 11, 53, 33, 20,
-	14, 36, 30, 24, 49,  2, 15, 37, 42, 50,  0, 21,
-	38, 48,  6, 26, 39,  4, 52, 25, 12, 27, 31, 40,
-	1, 17, 28, 29, 23, 51, 35,  7,  3, 22,  9, 43,
-
-	41, 20, 12, 53, 54, 25, 39, 48, 18, 31, 40, 27,
-	21, 43, 37,  0,  1,  9, 22, 44, 49,  2,  7, 28,
-	45, 55, 13, 33, 46, 11,  6, 32, 19, 34, 38, 47,
-	8, 24, 35, 36, 30,  3, 42, 14, 10, 29, 16, 50,
-
-	55, 34, 26, 38, 11, 39, 53,  5, 32, 45, 54, 41,
-	35,  2, 51, 14, 15, 23, 36,  3,  8, 16, 21, 42,
-	6, 12, 27, 47, 31, 25, 20, 46, 33, 48, 52,  4,
-	22,  7, 49, 50, 44, 17,  1, 28, 24, 43, 30,  9,
-
-	12, 48, 40, 52, 25, 53, 38, 19, 46,  6, 11, 55,
-	49, 16, 10, 28, 29, 37, 50, 17, 22, 30, 35,  1,
-	20, 26, 41,  4, 45, 39, 34, 31, 47,  5, 13, 18,
-	36, 21,  8,  9,  3,  0, 15, 42,  7,  2, 44, 23,
-
-	26,  5, 54, 13, 39, 38, 52, 33, 31, 20, 25, 12,
-	8, 30, 24, 42, 43, 51,  9,  0, 36, 44, 49, 15,
-	34, 40, 55, 18,  6, 53, 48, 45,  4, 19, 27, 32,
-	50, 35, 22, 23, 17, 14, 29,  1, 21, 16,  3, 37,
-
-	40, 19, 11, 27, 53, 52, 13, 47, 45, 34, 39, 26,
-	22, 44,  7,  1,  2, 10, 23, 14, 50,  3,  8, 29,
-	48, 54, 12, 32, 20, 38,  5,  6, 18, 33, 41, 46,
-	9, 49, 36, 37,  0, 28, 43, 15, 35, 30, 17, 51,
-
-	54, 33, 25, 41, 38, 13, 27,  4,  6, 48, 53, 40,
-	36,  3, 21, 15, 16, 24, 37, 28,  9, 17, 22, 43,
-	5, 11, 26, 46, 34, 52, 19, 20, 32, 47, 55, 31,
-	23,  8, 50, 51, 14, 42,  2, 29, 49, 44,  0, 10,
-
-	11, 47, 39, 55, 52, 27, 41, 18, 20,  5, 38, 54,
-	50, 17, 35, 29, 30,  7, 51, 42, 23,  0, 36,  2,
-	19, 25, 40, 31, 48, 13, 33, 34, 46,  4, 12, 45,
-	37, 22,  9, 10, 28,  1, 16, 43,  8,  3, 14, 24,
-
-	18, 54, 46,  5,  6, 34, 48, 25, 27, 12, 45,  4,
-	2, 24, 42, 36, 37, 14,  3, 49, 30,  7, 43,  9,
-	26, 32, 47, 38, 55, 20, 40, 41, 53, 11, 19, 52,
-	44, 29, 16, 17, 35,  8, 23, 50, 15, 10, 21,  0,
-
-	32, 11, 31, 19, 20, 48,  5, 39, 41, 26,  6, 18,
-	16,  7,  1, 50, 51, 28, 17,  8, 44, 21,  2, 23,
-	40, 46,  4, 52, 12, 34, 54, 55, 38, 25, 33, 13,
-	3, 43, 30,  0, 49, 22, 37,  9, 29, 24, 35, 14,
-
-	46, 25, 45, 33, 34,  5, 19, 53, 55, 40, 20, 32,
-	30, 21, 15,  9, 10, 42,  0, 22,  3, 35, 16, 37,
-	54, 31, 18, 13, 26, 48, 11, 12, 52, 39, 47, 27,
-	17,  2, 44, 14,  8, 36, 51, 23, 43,  7, 49, 28,
-
-	31, 39,  6, 47, 48, 19, 33, 38, 12, 54, 34, 46,
-	44, 35, 29, 23, 24,  1, 14, 36, 17, 49, 30, 51,
-	11, 45, 32, 27, 40,  5, 25, 26, 13, 53,  4, 41,
-	0, 16,  3, 28, 22, 50, 10, 37,  2, 21,  8, 42,
-
-	45, 53, 20,  4,  5, 33, 47, 52, 26, 11, 48, 31,
-	3, 49, 43, 37,  7, 15, 28, 50,  0,  8, 44, 10,
-	25,  6, 46, 41, 54, 19, 39, 40, 27, 38, 18, 55,
-	14, 30, 17, 42, 36,  9, 24, 51, 16, 35, 22,  1,
-
-	6, 38, 34, 18, 19, 47,  4, 13, 40, 25,  5, 45,
-	17,  8,  2, 51, 21, 29, 42,  9, 14, 22,  3, 24,
-	39, 20, 31, 55, 11, 33, 53, 54, 41, 52, 32, 12,
-	28, 44,  0,  1, 50, 23,  7, 10, 30, 49, 36, 15,
-
-	20, 52, 48, 32, 33,  4, 18, 27, 54, 39, 19,  6,
-	0, 22, 16, 10, 35, 43,  1, 23, 28, 36, 17,  7,
-	53, 34, 45, 12, 25, 47, 38, 11, 55, 13, 46, 26,
-	42,  3, 14, 15,  9, 37, 21, 24, 44,  8, 50, 29,
-
-	27,  6, 55, 39, 40, 11, 25, 34,  4, 46, 26, 13,
-	7, 29, 23, 17, 42, 50,  8, 30, 35, 43, 24, 14,
-	31, 41, 52, 19, 32, 54, 45, 18,  5, 20, 53, 33,
-	49, 10, 21, 22, 16, 44, 28,  0, 51, 15,  2, 36,
+static const u8 rs[256] = {
+	0x00, 0x00, 0x80, 0x80, 0x02, 0x02, 0x82, 0x82,
+	0x04, 0x04, 0x84, 0x84, 0x06, 0x06, 0x86, 0x86,
+	0x08, 0x08, 0x88, 0x88, 0x0a, 0x0a, 0x8a, 0x8a,
+	0x0c, 0x0c, 0x8c, 0x8c, 0x0e, 0x0e, 0x8e, 0x8e,
+	0x10, 0x10, 0x90, 0x90, 0x12, 0x12, 0x92, 0x92,
+	0x14, 0x14, 0x94, 0x94, 0x16, 0x16, 0x96, 0x96,
+	0x18, 0x18, 0x98, 0x98, 0x1a, 0x1a, 0x9a, 0x9a,
+	0x1c, 0x1c, 0x9c, 0x9c, 0x1e, 0x1e, 0x9e, 0x9e,
+	0x20, 0x20, 0xa0, 0xa0, 0x22, 0x22, 0xa2, 0xa2,
+	0x24, 0x24, 0xa4, 0xa4, 0x26, 0x26, 0xa6, 0xa6,
+	0x28, 0x28, 0xa8, 0xa8, 0x2a, 0x2a, 0xaa, 0xaa,
+	0x2c, 0x2c, 0xac, 0xac, 0x2e, 0x2e, 0xae, 0xae,
+	0x30, 0x30, 0xb0, 0xb0, 0x32, 0x32, 0xb2, 0xb2,
+	0x34, 0x34, 0xb4, 0xb4, 0x36, 0x36, 0xb6, 0xb6,
+	0x38, 0x38, 0xb8, 0xb8, 0x3a, 0x3a, 0xba, 0xba,
+	0x3c, 0x3c, 0xbc, 0xbc, 0x3e, 0x3e, 0xbe, 0xbe,
+	0x40, 0x40, 0xc0, 0xc0, 0x42, 0x42, 0xc2, 0xc2,
+	0x44, 0x44, 0xc4, 0xc4, 0x46, 0x46, 0xc6, 0xc6,
+	0x48, 0x48, 0xc8, 0xc8, 0x4a, 0x4a, 0xca, 0xca,
+	0x4c, 0x4c, 0xcc, 0xcc, 0x4e, 0x4e, 0xce, 0xce,
+	0x50, 0x50, 0xd0, 0xd0, 0x52, 0x52, 0xd2, 0xd2,
+	0x54, 0x54, 0xd4, 0xd4, 0x56, 0x56, 0xd6, 0xd6,
+	0x58, 0x58, 0xd8, 0xd8, 0x5a, 0x5a, 0xda, 0xda,
+	0x5c, 0x5c, 0xdc, 0xdc, 0x5e, 0x5e, 0xde, 0xde,
+	0x60, 0x60, 0xe0, 0xe0, 0x62, 0x62, 0xe2, 0xe2,
+	0x64, 0x64, 0xe4, 0xe4, 0x66, 0x66, 0xe6, 0xe6,
+	0x68, 0x68, 0xe8, 0xe8, 0x6a, 0x6a, 0xea, 0xea,
+	0x6c, 0x6c, 0xec, 0xec, 0x6e, 0x6e, 0xee, 0xee,
+	0x70, 0x70, 0xf0, 0xf0, 0x72, 0x72, 0xf2, 0xf2,
+	0x74, 0x74, 0xf4, 0xf4, 0x76, 0x76, 0xf6, 0xf6,
+	0x78, 0x78, 0xf8, 0xf8, 0x7a, 0x7a, 0xfa, 0xfa,
+	0x7c, 0x7c, 0xfc, 0xfc, 0x7e, 0x7e, 0xfe, 0xfe
 };
 
-static const u8 parity[] = {
-	8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3,
-	0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
-	0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
-	8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
-	0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
-	8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
-	8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
-	4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8,
+static const u32 pc2[1024] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00040000, 0x00000000, 0x04000000, 0x00100000,
+	0x00400000, 0x00000008, 0x00000800, 0x40000000,
+	0x00440000, 0x00000008, 0x04000800, 0x40100000,
+	0x00000400, 0x00000020, 0x08000000, 0x00000100,
+	0x00040400, 0x00000020, 0x0c000000, 0x00100100,
+	0x00400400, 0x00000028, 0x08000800, 0x40000100,
+	0x00440400, 0x00000028, 0x0c000800, 0x40100100,
+	0x80000000, 0x00000010, 0x00000000, 0x00800000,
+	0x80040000, 0x00000010, 0x04000000, 0x00900000,
+	0x80400000, 0x00000018, 0x00000800, 0x40800000,
+	0x80440000, 0x00000018, 0x04000800, 0x40900000,
+	0x80000400, 0x00000030, 0x08000000, 0x00800100,
+	0x80040400, 0x00000030, 0x0c000000, 0x00900100,
+	0x80400400, 0x00000038, 0x08000800, 0x40800100,
+	0x80440400, 0x00000038, 0x0c000800, 0x40900100,
+	0x10000000, 0x00000000, 0x00200000, 0x00001000,
+	0x10040000, 0x00000000, 0x04200000, 0x00101000,
+	0x10400000, 0x00000008, 0x00200800, 0x40001000,
+	0x10440000, 0x00000008, 0x04200800, 0x40101000,
+	0x10000400, 0x00000020, 0x08200000, 0x00001100,
+	0x10040400, 0x00000020, 0x0c200000, 0x00101100,
+	0x10400400, 0x00000028, 0x08200800, 0x40001100,
+	0x10440400, 0x00000028, 0x0c200800, 0x40101100,
+	0x90000000, 0x00000010, 0x00200000, 0x00801000,
+	0x90040000, 0x00000010, 0x04200000, 0x00901000,
+	0x90400000, 0x00000018, 0x00200800, 0x40801000,
+	0x90440000, 0x00000018, 0x04200800, 0x40901000,
+	0x90000400, 0x00000030, 0x08200000, 0x00801100,
+	0x90040400, 0x00000030, 0x0c200000, 0x00901100,
+	0x90400400, 0x00000038, 0x08200800, 0x40801100,
+	0x90440400, 0x00000038, 0x0c200800, 0x40901100,
+	0x00000200, 0x00080000, 0x00000000, 0x00000004,
+	0x00040200, 0x00080000, 0x04000000, 0x00100004,
+	0x00400200, 0x00080008, 0x00000800, 0x40000004,
+	0x00440200, 0x00080008, 0x04000800, 0x40100004,
+	0x00000600, 0x00080020, 0x08000000, 0x00000104,
+	0x00040600, 0x00080020, 0x0c000000, 0x00100104,
+	0x00400600, 0x00080028, 0x08000800, 0x40000104,
+	0x00440600, 0x00080028, 0x0c000800, 0x40100104,
+	0x80000200, 0x00080010, 0x00000000, 0x00800004,
+	0x80040200, 0x00080010, 0x04000000, 0x00900004,
+	0x80400200, 0x00080018, 0x00000800, 0x40800004,
+	0x80440200, 0x00080018, 0x04000800, 0x40900004,
+	0x80000600, 0x00080030, 0x08000000, 0x00800104,
+	0x80040600, 0x00080030, 0x0c000000, 0x00900104,
+	0x80400600, 0x00080038, 0x08000800, 0x40800104,
+	0x80440600, 0x00080038, 0x0c000800, 0x40900104,
+	0x10000200, 0x00080000, 0x00200000, 0x00001004,
+	0x10040200, 0x00080000, 0x04200000, 0x00101004,
+	0x10400200, 0x00080008, 0x00200800, 0x40001004,
+	0x10440200, 0x00080008, 0x04200800, 0x40101004,
+	0x10000600, 0x00080020, 0x08200000, 0x00001104,
+	0x10040600, 0x00080020, 0x0c200000, 0x00101104,
+	0x10400600, 0x00080028, 0x08200800, 0x40001104,
+	0x10440600, 0x00080028, 0x0c200800, 0x40101104,
+	0x90000200, 0x00080010, 0x00200000, 0x00801004,
+	0x90040200, 0x00080010, 0x04200000, 0x00901004,
+	0x90400200, 0x00080018, 0x00200800, 0x40801004,
+	0x90440200, 0x00080018, 0x04200800, 0x40901004,
+	0x90000600, 0x00080030, 0x08200000, 0x00801104,
+	0x90040600, 0x00080030, 0x0c200000, 0x00901104,
+	0x90400600, 0x00080038, 0x08200800, 0x40801104,
+	0x90440600, 0x00080038, 0x0c200800, 0x40901104,
+	0x00000002, 0x00002000, 0x20000000, 0x00000001,
+	0x00040002, 0x00002000, 0x24000000, 0x00100001,
+	0x00400002, 0x00002008, 0x20000800, 0x40000001,
+	0x00440002, 0x00002008, 0x24000800, 0x40100001,
+	0x00000402, 0x00002020, 0x28000000, 0x00000101,
+	0x00040402, 0x00002020, 0x2c000000, 0x00100101,
+	0x00400402, 0x00002028, 0x28000800, 0x40000101,
+	0x00440402, 0x00002028, 0x2c000800, 0x40100101,
+	0x80000002, 0x00002010, 0x20000000, 0x00800001,
+	0x80040002, 0x00002010, 0x24000000, 0x00900001,
+	0x80400002, 0x00002018, 0x20000800, 0x40800001,
+	0x80440002, 0x00002018, 0x24000800, 0x40900001,
+	0x80000402, 0x00002030, 0x28000000, 0x00800101,
+	0x80040402, 0x00002030, 0x2c000000, 0x00900101,
+	0x80400402, 0x00002038, 0x28000800, 0x40800101,
+	0x80440402, 0x00002038, 0x2c000800, 0x40900101,
+	0x10000002, 0x00002000, 0x20200000, 0x00001001,
+	0x10040002, 0x00002000, 0x24200000, 0x00101001,
+	0x10400002, 0x00002008, 0x20200800, 0x40001001,
+	0x10440002, 0x00002008, 0x24200800, 0x40101001,
+	0x10000402, 0x00002020, 0x28200000, 0x00001101,
+	0x10040402, 0x00002020, 0x2c200000, 0x00101101,
+	0x10400402, 0x00002028, 0x28200800, 0x40001101,
+	0x10440402, 0x00002028, 0x2c200800, 0x40101101,
+	0x90000002, 0x00002010, 0x20200000, 0x00801001,
+	0x90040002, 0x00002010, 0x24200000, 0x00901001,
+	0x90400002, 0x00002018, 0x20200800, 0x40801001,
+	0x90440002, 0x00002018, 0x24200800, 0x40901001,
+	0x90000402, 0x00002030, 0x28200000, 0x00801101,
+	0x90040402, 0x00002030, 0x2c200000, 0x00901101,
+	0x90400402, 0x00002038, 0x28200800, 0x40801101,
+	0x90440402, 0x00002038, 0x2c200800, 0x40901101,
+	0x00000202, 0x00082000, 0x20000000, 0x00000005,
+	0x00040202, 0x00082000, 0x24000000, 0x00100005,
+	0x00400202, 0x00082008, 0x20000800, 0x40000005,
+	0x00440202, 0x00082008, 0x24000800, 0x40100005,
+	0x00000602, 0x00082020, 0x28000000, 0x00000105,
+	0x00040602, 0x00082020, 0x2c000000, 0x00100105,
+	0x00400602, 0x00082028, 0x28000800, 0x40000105,
+	0x00440602, 0x00082028, 0x2c000800, 0x40100105,
+	0x80000202, 0x00082010, 0x20000000, 0x00800005,
+	0x80040202, 0x00082010, 0x24000000, 0x00900005,
+	0x80400202, 0x00082018, 0x20000800, 0x40800005,
+	0x80440202, 0x00082018, 0x24000800, 0x40900005,
+	0x80000602, 0x00082030, 0x28000000, 0x00800105,
+	0x80040602, 0x00082030, 0x2c000000, 0x00900105,
+	0x80400602, 0x00082038, 0x28000800, 0x40800105,
+	0x80440602, 0x00082038, 0x2c000800, 0x40900105,
+	0x10000202, 0x00082000, 0x20200000, 0x00001005,
+	0x10040202, 0x00082000, 0x24200000, 0x00101005,
+	0x10400202, 0x00082008, 0x20200800, 0x40001005,
+	0x10440202, 0x00082008, 0x24200800, 0x40101005,
+	0x10000602, 0x00082020, 0x28200000, 0x00001105,
+	0x10040602, 0x00082020, 0x2c200000, 0x00101105,
+	0x10400602, 0x00082028, 0x28200800, 0x40001105,
+	0x10440602, 0x00082028, 0x2c200800, 0x40101105,
+	0x90000202, 0x00082010, 0x20200000, 0x00801005,
+	0x90040202, 0x00082010, 0x24200000, 0x00901005,
+	0x90400202, 0x00082018, 0x20200800, 0x40801005,
+	0x90440202, 0x00082018, 0x24200800, 0x40901005,
+	0x90000602, 0x00082030, 0x28200000, 0x00801105,
+	0x90040602, 0x00082030, 0x2c200000, 0x00901105,
+	0x90400602, 0x00082038, 0x28200800, 0x40801105,
+	0x90440602, 0x00082038, 0x2c200800, 0x40901105,
+
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000008, 0x00080000, 0x10000000,
+	0x02000000, 0x00000000, 0x00000080, 0x00001000,
+	0x02000000, 0x00000008, 0x00080080, 0x10001000,
+	0x00004000, 0x00000000, 0x00000040, 0x00040000,
+	0x00004000, 0x00000008, 0x00080040, 0x10040000,
+	0x02004000, 0x00000000, 0x000000c0, 0x00041000,
+	0x02004000, 0x00000008, 0x000800c0, 0x10041000,
+	0x00020000, 0x00008000, 0x08000000, 0x00200000,
+	0x00020000, 0x00008008, 0x08080000, 0x10200000,
+	0x02020000, 0x00008000, 0x08000080, 0x00201000,
+	0x02020000, 0x00008008, 0x08080080, 0x10201000,
+	0x00024000, 0x00008000, 0x08000040, 0x00240000,
+	0x00024000, 0x00008008, 0x08080040, 0x10240000,
+	0x02024000, 0x00008000, 0x080000c0, 0x00241000,
+	0x02024000, 0x00008008, 0x080800c0, 0x10241000,
+	0x00000000, 0x01000000, 0x00002000, 0x00000020,
+	0x00000000, 0x01000008, 0x00082000, 0x10000020,
+	0x02000000, 0x01000000, 0x00002080, 0x00001020,
+	0x02000000, 0x01000008, 0x00082080, 0x10001020,
+	0x00004000, 0x01000000, 0x00002040, 0x00040020,
+	0x00004000, 0x01000008, 0x00082040, 0x10040020,
+	0x02004000, 0x01000000, 0x000020c0, 0x00041020,
+	0x02004000, 0x01000008, 0x000820c0, 0x10041020,
+	0x00020000, 0x01008000, 0x08002000, 0x00200020,
+	0x00020000, 0x01008008, 0x08082000, 0x10200020,
+	0x02020000, 0x01008000, 0x08002080, 0x00201020,
+	0x02020000, 0x01008008, 0x08082080, 0x10201020,
+	0x00024000, 0x01008000, 0x08002040, 0x00240020,
+	0x00024000, 0x01008008, 0x08082040, 0x10240020,
+	0x02024000, 0x01008000, 0x080020c0, 0x00241020,
+	0x02024000, 0x01008008, 0x080820c0, 0x10241020,
+	0x00000400, 0x04000000, 0x00100000, 0x00000004,
+	0x00000400, 0x04000008, 0x00180000, 0x10000004,
+	0x02000400, 0x04000000, 0x00100080, 0x00001004,
+	0x02000400, 0x04000008, 0x00180080, 0x10001004,
+	0x00004400, 0x04000000, 0x00100040, 0x00040004,
+	0x00004400, 0x04000008, 0x00180040, 0x10040004,
+	0x02004400, 0x04000000, 0x001000c0, 0x00041004,
+	0x02004400, 0x04000008, 0x001800c0, 0x10041004,
+	0x00020400, 0x04008000, 0x08100000, 0x00200004,
+	0x00020400, 0x04008008, 0x08180000, 0x10200004,
+	0x02020400, 0x04008000, 0x08100080, 0x00201004,
+	0x02020400, 0x04008008, 0x08180080, 0x10201004,
+	0x00024400, 0x04008000, 0x08100040, 0x00240004,
+	0x00024400, 0x04008008, 0x08180040, 0x10240004,
+	0x02024400, 0x04008000, 0x081000c0, 0x00241004,
+	0x02024400, 0x04008008, 0x081800c0, 0x10241004,
+	0x00000400, 0x05000000, 0x00102000, 0x00000024,
+	0x00000400, 0x05000008, 0x00182000, 0x10000024,
+	0x02000400, 0x05000000, 0x00102080, 0x00001024,
+	0x02000400, 0x05000008, 0x00182080, 0x10001024,
+	0x00004400, 0x05000000, 0x00102040, 0x00040024,
+	0x00004400, 0x05000008, 0x00182040, 0x10040024,
+	0x02004400, 0x05000000, 0x001020c0, 0x00041024,
+	0x02004400, 0x05000008, 0x001820c0, 0x10041024,
+	0x00020400, 0x05008000, 0x08102000, 0x00200024,
+	0x00020400, 0x05008008, 0x08182000, 0x10200024,
+	0x02020400, 0x05008000, 0x08102080, 0x00201024,
+	0x02020400, 0x05008008, 0x08182080, 0x10201024,
+	0x00024400, 0x05008000, 0x08102040, 0x00240024,
+	0x00024400, 0x05008008, 0x08182040, 0x10240024,
+	0x02024400, 0x05008000, 0x081020c0, 0x00241024,
+	0x02024400, 0x05008008, 0x081820c0, 0x10241024,
+	0x00000800, 0x00010000, 0x20000000, 0x00000010,
+	0x00000800, 0x00010008, 0x20080000, 0x10000010,
+	0x02000800, 0x00010000, 0x20000080, 0x00001010,
+	0x02000800, 0x00010008, 0x20080080, 0x10001010,
+	0x00004800, 0x00010000, 0x20000040, 0x00040010,
+	0x00004800, 0x00010008, 0x20080040, 0x10040010,
+	0x02004800, 0x00010000, 0x200000c0, 0x00041010,
+	0x02004800, 0x00010008, 0x200800c0, 0x10041010,
+	0x00020800, 0x00018000, 0x28000000, 0x00200010,
+	0x00020800, 0x00018008, 0x28080000, 0x10200010,
+	0x02020800, 0x00018000, 0x28000080, 0x00201010,
+	0x02020800, 0x00018008, 0x28080080, 0x10201010,
+	0x00024800, 0x00018000, 0x28000040, 0x00240010,
+	0x00024800, 0x00018008, 0x28080040, 0x10240010,
+	0x02024800, 0x00018000, 0x280000c0, 0x00241010,
+	0x02024800, 0x00018008, 0x280800c0, 0x10241010,
+	0x00000800, 0x01010000, 0x20002000, 0x00000030,
+	0x00000800, 0x01010008, 0x20082000, 0x10000030,
+	0x02000800, 0x01010000, 0x20002080, 0x00001030,
+	0x02000800, 0x01010008, 0x20082080, 0x10001030,
+	0x00004800, 0x01010000, 0x20002040, 0x00040030,
+	0x00004800, 0x01010008, 0x20082040, 0x10040030,
+	0x02004800, 0x01010000, 0x200020c0, 0x00041030,
+	0x02004800, 0x01010008, 0x200820c0, 0x10041030,
+	0x00020800, 0x01018000, 0x28002000, 0x00200030,
+	0x00020800, 0x01018008, 0x28082000, 0x10200030,
+	0x02020800, 0x01018000, 0x28002080, 0x00201030,
+	0x02020800, 0x01018008, 0x28082080, 0x10201030,
+	0x00024800, 0x01018000, 0x28002040, 0x00240030,
+	0x00024800, 0x01018008, 0x28082040, 0x10240030,
+	0x02024800, 0x01018000, 0x280020c0, 0x00241030,
+	0x02024800, 0x01018008, 0x280820c0, 0x10241030,
+	0x00000c00, 0x04010000, 0x20100000, 0x00000014,
+	0x00000c00, 0x04010008, 0x20180000, 0x10000014,
+	0x02000c00, 0x04010000, 0x20100080, 0x00001014,
+	0x02000c00, 0x04010008, 0x20180080, 0x10001014,
+	0x00004c00, 0x04010000, 0x20100040, 0x00040014,
+	0x00004c00, 0x04010008, 0x20180040, 0x10040014,
+	0x02004c00, 0x04010000, 0x201000c0, 0x00041014,
+	0x02004c00, 0x04010008, 0x201800c0, 0x10041014,
+	0x00020c00, 0x04018000, 0x28100000, 0x00200014,
+	0x00020c00, 0x04018008, 0x28180000, 0x10200014,
+	0x02020c00, 0x04018000, 0x28100080, 0x00201014,
+	0x02020c00, 0x04018008, 0x28180080, 0x10201014,
+	0x00024c00, 0x04018000, 0x28100040, 0x00240014,
+	0x00024c00, 0x04018008, 0x28180040, 0x10240014,
+	0x02024c00, 0x04018000, 0x281000c0, 0x00241014,
+	0x02024c00, 0x04018008, 0x281800c0, 0x10241014,
+	0x00000c00, 0x05010000, 0x20102000, 0x00000034,
+	0x00000c00, 0x05010008, 0x20182000, 0x10000034,
+	0x02000c00, 0x05010000, 0x20102080, 0x00001034,
+	0x02000c00, 0x05010008, 0x20182080, 0x10001034,
+	0x00004c00, 0x05010000, 0x20102040, 0x00040034,
+	0x00004c00, 0x05010008, 0x20182040, 0x10040034,
+	0x02004c00, 0x05010000, 0x201020c0, 0x00041034,
+	0x02004c00, 0x05010008, 0x201820c0, 0x10041034,
+	0x00020c00, 0x05018000, 0x28102000, 0x00200034,
+	0x00020c00, 0x05018008, 0x28182000, 0x10200034,
+	0x02020c00, 0x05018000, 0x28102080, 0x00201034,
+	0x02020c00, 0x05018008, 0x28182080, 0x10201034,
+	0x00024c00, 0x05018000, 0x28102040, 0x00240034,
+	0x00024c00, 0x05018008, 0x28182040, 0x10240034,
+	0x02024c00, 0x05018000, 0x281020c0, 0x00241034,
+	0x02024c00, 0x05018008, 0x281820c0, 0x10241034
 };
 
+/* S-box lookup tables */
 
-static void des_small_fips_encrypt(u32 *expkey, u8 *dst, const u8 *src)
+static const u32 S1[64] = {
+	0x01010400, 0x00000000, 0x00010000, 0x01010404,
+	0x01010004, 0x00010404, 0x00000004, 0x00010000,
+	0x00000400, 0x01010400, 0x01010404, 0x00000400,
+	0x01000404, 0x01010004, 0x01000000, 0x00000004,
+	0x00000404, 0x01000400, 0x01000400, 0x00010400,
+	0x00010400, 0x01010000, 0x01010000, 0x01000404,
+	0x00010004, 0x01000004, 0x01000004, 0x00010004,
+	0x00000000, 0x00000404, 0x00010404, 0x01000000,
+	0x00010000, 0x01010404, 0x00000004, 0x01010000,
+	0x01010400, 0x01000000, 0x01000000, 0x00000400,
+	0x01010004, 0x00010000, 0x00010400, 0x01000004,
+	0x00000400, 0x00000004, 0x01000404, 0x00010404,
+	0x01010404, 0x00010004, 0x01010000, 0x01000404,
+	0x01000004, 0x00000404, 0x00010404, 0x01010400,
+	0x00000404, 0x01000400, 0x01000400, 0x00000000,
+	0x00010004, 0x00010400, 0x00000000, 0x01010004
+};
+
+static const u32 S2[64] = {
+	0x80108020, 0x80008000, 0x00008000, 0x00108020,
+	0x00100000, 0x00000020, 0x80100020, 0x80008020,
+	0x80000020, 0x80108020, 0x80108000, 0x80000000,
+	0x80008000, 0x00100000, 0x00000020, 0x80100020,
+	0x00108000, 0x00100020, 0x80008020, 0x00000000,
+	0x80000000, 0x00008000, 0x00108020, 0x80100000,
+	0x00100020, 0x80000020, 0x00000000, 0x00108000,
+	0x00008020, 0x80108000, 0x80100000, 0x00008020,
+	0x00000000, 0x00108020, 0x80100020, 0x00100000,
+	0x80008020, 0x80100000, 0x80108000, 0x00008000,
+	0x80100000, 0x80008000, 0x00000020, 0x80108020,
+	0x00108020, 0x00000020, 0x00008000, 0x80000000,
+	0x00008020, 0x80108000, 0x00100000, 0x80000020,
+	0x00100020, 0x80008020, 0x80000020, 0x00100020,
+	0x00108000, 0x00000000, 0x80008000, 0x00008020,
+	0x80000000, 0x80100020, 0x80108020, 0x00108000
+};
+
+static const u32 S3[64] = {
+	0x00000208, 0x08020200, 0x00000000, 0x08020008,
+	0x08000200, 0x00000000, 0x00020208, 0x08000200,
+	0x00020008, 0x08000008, 0x08000008, 0x00020000,
+	0x08020208, 0x00020008, 0x08020000, 0x00000208,
+	0x08000000, 0x00000008, 0x08020200, 0x00000200,
+	0x00020200, 0x08020000, 0x08020008, 0x00020208,
+	0x08000208, 0x00020200, 0x00020000, 0x08000208,
+	0x00000008, 0x08020208, 0x00000200, 0x08000000,
+	0x08020200, 0x08000000, 0x00020008, 0x00000208,
+	0x00020000, 0x08020200, 0x08000200, 0x00000000,
+	0x00000200, 0x00020008, 0x08020208, 0x08000200,
+	0x08000008, 0x00000200, 0x00000000, 0x08020008,
+	0x08000208, 0x00020000, 0x08000000, 0x08020208,
+	0x00000008, 0x00020208, 0x00020200, 0x08000008,
+	0x08020000, 0x08000208, 0x00000208, 0x08020000,
+	0x00020208, 0x00000008, 0x08020008, 0x00020200
+};
+
+static const u32 S4[64] = {
+	0x00802001, 0x00002081, 0x00002081, 0x00000080,
+	0x00802080, 0x00800081, 0x00800001, 0x00002001,
+	0x00000000, 0x00802000, 0x00802000, 0x00802081,
+	0x00000081, 0x00000000, 0x00800080, 0x00800001,
+	0x00000001, 0x00002000, 0x00800000, 0x00802001,
+	0x00000080, 0x00800000, 0x00002001, 0x00002080,
+	0x00800081, 0x00000001, 0x00002080, 0x00800080,
+	0x00002000, 0x00802080, 0x00802081, 0x00000081,
+	0x00800080, 0x00800001, 0x00802000, 0x00802081,
+	0x00000081, 0x00000000, 0x00000000, 0x00802000,
+	0x00002080, 0x00800080, 0x00800081, 0x00000001,
+	0x00802001, 0x00002081, 0x00002081, 0x00000080,
+	0x00802081, 0x00000081, 0x00000001, 0x00002000,
+	0x00800001, 0x00002001, 0x00802080, 0x00800081,
+	0x00002001, 0x00002080, 0x00800000, 0x00802001,
+	0x00000080, 0x00800000, 0x00002000, 0x00802080
+};
+
+static const u32 S5[64] = {
+	0x00000100, 0x02080100, 0x02080000, 0x42000100,
+	0x00080000, 0x00000100, 0x40000000, 0x02080000,
+	0x40080100, 0x00080000, 0x02000100, 0x40080100,
+	0x42000100, 0x42080000, 0x00080100, 0x40000000,
+	0x02000000, 0x40080000, 0x40080000, 0x00000000,
+	0x40000100, 0x42080100, 0x42080100, 0x02000100,
+	0x42080000, 0x40000100, 0x00000000, 0x42000000,
+	0x02080100, 0x02000000, 0x42000000, 0x00080100,
+	0x00080000, 0x42000100, 0x00000100, 0x02000000,
+	0x40000000, 0x02080000, 0x42000100, 0x40080100,
+	0x02000100, 0x40000000, 0x42080000, 0x02080100,
+	0x40080100, 0x00000100, 0x02000000, 0x42080000,
+	0x42080100, 0x00080100, 0x42000000, 0x42080100,
+	0x02080000, 0x00000000, 0x40080000, 0x42000000,
+	0x00080100, 0x02000100, 0x40000100, 0x00080000,
+	0x00000000, 0x40080000, 0x02080100, 0x40000100
+};
+
+static const u32 S6[64] = {
+	0x20000010, 0x20400000, 0x00004000, 0x20404010,
+	0x20400000, 0x00000010, 0x20404010, 0x00400000,
+	0x20004000, 0x00404010, 0x00400000, 0x20000010,
+	0x00400010, 0x20004000, 0x20000000, 0x00004010,
+	0x00000000, 0x00400010, 0x20004010, 0x00004000,
+	0x00404000, 0x20004010, 0x00000010, 0x20400010,
+	0x20400010, 0x00000000, 0x00404010, 0x20404000,
+	0x00004010, 0x00404000, 0x20404000, 0x20000000,
+	0x20004000, 0x00000010, 0x20400010, 0x00404000,
+	0x20404010, 0x00400000, 0x00004010, 0x20000010,
+	0x00400000, 0x20004000, 0x20000000, 0x00004010,
+	0x20000010, 0x20404010, 0x00404000, 0x20400000,
+	0x00404010, 0x20404000, 0x00000000, 0x20400010,
+	0x00000010, 0x00004000, 0x20400000, 0x00404010,
+	0x00004000, 0x00400010, 0x20004010, 0x00000000,
+	0x20404000, 0x20000000, 0x00400010, 0x20004010
+};
+
+static const u32 S7[64] = {
+	0x00200000, 0x04200002, 0x04000802, 0x00000000,
+	0x00000800, 0x04000802, 0x00200802, 0x04200800,
+	0x04200802, 0x00200000, 0x00000000, 0x04000002,
+	0x00000002, 0x04000000, 0x04200002, 0x00000802,
+	0x04000800, 0x00200802, 0x00200002, 0x04000800,
+	0x04000002, 0x04200000, 0x04200800, 0x00200002,
+	0x04200000, 0x00000800, 0x00000802, 0x04200802,
+	0x00200800, 0x00000002, 0x04000000, 0x00200800,
+	0x04000000, 0x00200800, 0x00200000, 0x04000802,
+	0x04000802, 0x04200002, 0x04200002, 0x00000002,
+	0x00200002, 0x04000000, 0x04000800, 0x00200000,
+	0x04200800, 0x00000802, 0x00200802, 0x04200800,
+	0x00000802, 0x04000002, 0x04200802, 0x04200000,
+	0x00200800, 0x00000000, 0x00000002, 0x04200802,
+	0x00000000, 0x00200802, 0x04200000, 0x00000800,
+	0x04000002, 0x04000800, 0x00000800, 0x00200002
+};
+
+static const u32 S8[64] = {
+	0x10001040, 0x00001000, 0x00040000, 0x10041040,
+	0x10000000, 0x10001040, 0x00000040, 0x10000000,
+	0x00040040, 0x10040000, 0x10041040, 0x00041000,
+	0x10041000, 0x00041040, 0x00001000, 0x00000040,
+	0x10040000, 0x10000040, 0x10001000, 0x00001040,
+	0x00041000, 0x00040040, 0x10040040, 0x10041000,
+	0x00001040, 0x00000000, 0x00000000, 0x10040040,
+	0x10000040, 0x10001000, 0x00041040, 0x00040000,
+	0x00041040, 0x00040000, 0x10041000, 0x00001000,
+	0x00000040, 0x10040040, 0x00001000, 0x00041040,
+	0x10001000, 0x00000040, 0x10000040, 0x10040000,
+	0x10040040, 0x10000000, 0x00040000, 0x10001040,
+	0x00000000, 0x10041040, 0x00040040, 0x10000040,
+	0x10040000, 0x10001000, 0x10001040, 0x00000000,
+	0x10041040, 0x00041000, 0x00041000, 0x00001040,
+	0x00001040, 0x00040040, 0x10000000, 0x10041000
+};
+
+/* Encryption components: IP, FP, and round function */
+
+#define IP(L, R, T)		\
+	ROL(R, 4);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xf0f0f0f0;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROL(R, 12);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xffff0000;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROR(R, 14);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xcccccccc;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROL(R, 6);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xff00ff00;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROR(R, 7);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xaaaaaaaa;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROL(L, 1);
+
+#define FP(L, R, T)		\
+	ROR(L, 1);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xaaaaaaaa;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROL(R, 7);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xff00ff00;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROR(R, 6);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xcccccccc;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROL(R, 14);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xffff0000;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROR(R, 12);		\
+	T  = L;			\
+	L ^= R;			\
+	L &= 0xf0f0f0f0;	\
+	R ^= L;			\
+	L ^= T;			\
+	ROR(R, 4);
+
+#define ROUND(L, R, A, B, K, d)					\
+	B = K[0];			A = K[1];	K += d;	\
+	B ^= R;				A ^= R;			\
+	B &= 0x3f3f3f3f;		ROR(A, 4);		\
+	L ^= S8[0xff & B];		A &= 0x3f3f3f3f;	\
+	L ^= S6[0xff & (B >> 8)];	B >>= 16;		\
+	L ^= S7[0xff & A];					\
+	L ^= S5[0xff & (A >> 8)];	A >>= 16;		\
+	L ^= S4[0xff & B];					\
+	L ^= S2[0xff & (B >> 8)];				\
+	L ^= S3[0xff & A];					\
+	L ^= S1[0xff & (A >> 8)];
+
+/*
+ * PC2 lookup tables are organized as 2 consecutive sets of 4 interleaved
+ * tables of 128 elements.  One set is for C_i and the other for D_i, while
+ * the 4 interleaved tables correspond to four 7-bit subsets of C_i or D_i.
+ *
+ * After PC1 each of the variables a,b,c,d contains a 7 bit subset of C_i
+ * or D_i in bits 7-1 (bit 0 being the least significant).
+ */
+
+#define T1(x) pt[2 * (x) + 0]
+#define T2(x) pt[2 * (x) + 1]
+#define T3(x) pt[2 * (x) + 2]
+#define T4(x) pt[2 * (x) + 3]
+
+#define PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a))
+
+/*
+ * Encryption key expansion
+ *
+ * RFC2451: Weak key checks SHOULD be performed.
+ *
+ * FIPS 74:
+ *
+ *   Keys having duals are keys which produce all zeros, all ones, or
+ *   alternating zero-one patterns in the C and D registers after Permuted
+ *   Choice 1 has operated on the key.
+ *
+ */
+static unsigned long ekey(u32 *pe, const u8 *k)
 {
-	u32 x, y, z;
-	
-	x  = src[7];
-	x <<= 8;
-	x |= src[6];
-	x <<= 8;
-	x |= src[5];
-	x <<= 8;
-	x |= src[4];
-	y  = src[3];
-	y <<= 8;
-	y |= src[2];
-	y <<= 8;
-	y |= src[1];
-	y <<= 8;
-	y |= src[0];
-	z  = ((x >> 004) ^ y) & 0x0F0F0F0FL;
-	x ^= z << 004;
-	y ^= z;
-	z  = ((y >> 020) ^ x) & 0x0000FFFFL;
-	y ^= z << 020;
-	x ^= z;
-	z  = ((x >> 002) ^ y) & 0x33333333L;
-	x ^= z << 002;
-	y ^= z;
-	z  = ((y >> 010) ^ x) & 0x00FF00FFL;
-	y ^= z << 010;
-	x ^= z;
-	x  = x >> 1 | x << 31;
-	z  = (x ^ y) & 0x55555555L;
-	y ^= z;
-	x ^= z;
-	y  = y >> 1 | y << 31;
-	z  = expkey[0];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[1];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[2];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[3];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[4];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[5];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[6];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[7];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[8];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[9];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[10];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[11];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[12];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[13];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[14];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[15];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[16];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[17];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[18];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[19];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[20];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[21];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[22];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[23];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[24];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[25];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[26];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[27];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[28];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[29];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[30];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[31];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	x  = x << 1 | x >> 31;
-	z  = (x ^ y) & 0x55555555L;
-	y ^= z;
-	x ^= z;
-	y  = y << 1 | y >> 31;
-	z  = ((x >> 010) ^ y) & 0x00FF00FFL;
-	x ^= z << 010;
-	y ^= z;
-	z  = ((y >> 002) ^ x) & 0x33333333L;
-	y ^= z << 002;
-	x ^= z;
-	z  = ((x >> 020) ^ y) & 0x0000FFFFL;
-	x ^= z << 020;
-	y ^= z;
-	z  = ((y >> 004) ^ x) & 0x0F0F0F0FL;
-	y ^= z << 004;
-	x ^= z;
-	dst[0] = x;
-	x >>= 8;
-	dst[1] = x;
-	x >>= 8;
-	dst[2] = x;
-	x >>= 8;
-	dst[3] = x;
-	dst[4] = y;
-	y >>= 8;
-	dst[5] = y;
-	y >>= 8;
-	dst[6] = y;
-	y >>= 8;
-	dst[7] = y;
-}
+	/* K&R: long is at least 32 bits */
+	unsigned long a, b, c, d, w;
+	const u32 *pt = pc2;
 
-static void des_small_fips_decrypt(u32 *expkey, u8 *dst, const u8 *src)
-{
-	u32 x, y, z;
-	
-	x  = src[7];
-	x <<= 8;
-	x |= src[6];
-	x <<= 8;
-	x |= src[5];
-	x <<= 8;
-	x |= src[4];
-	y  = src[3];
-	y <<= 8;
-	y |= src[2];
-	y <<= 8;
-	y |= src[1];
-	y <<= 8;
-	y |= src[0];
-	z  = ((x >> 004) ^ y) & 0x0F0F0F0FL;
-	x ^= z << 004;
-	y ^= z;
-	z  = ((y >> 020) ^ x) & 0x0000FFFFL;
-	y ^= z << 020;
-	x ^= z;
-	z  = ((x >> 002) ^ y) & 0x33333333L;
-	x ^= z << 002;
-	y ^= z;
-	z  = ((y >> 010) ^ x) & 0x00FF00FFL;
-	y ^= z << 010;
-	x ^= z;
-	x  = x >> 1 | x << 31;
-	z  = (x ^ y) & 0x55555555L;
-	y ^= z;
-	x ^= z;
-	y  = y >> 1 | y << 31;
-	z  = expkey[31];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[30];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[29];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[28];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[27];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[26];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[25];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[24];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[23];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[22];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[21];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[20];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[19];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[18];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[17];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[16];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[15];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[14];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[13];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[12];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[11];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[10];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[9];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[8];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[7];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[6];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[5];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[4];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[3];
-	z ^= y;
-	z  = z << 4 | z >> 28;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[2];
-	z ^= y;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	z  = expkey[1];
-	z ^= x;
-	z  = z << 4 | z >> 28;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
-	z  = expkey[0];
-	z ^= x;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
-	z >>= 8;
-	y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
-	x  = x << 1 | x >> 31;
-	z  = (x ^ y) & 0x55555555L;
-	y ^= z;
-	x ^= z;
-	y  = y << 1 | y >> 31;
-	z  = ((x >> 010) ^ y) & 0x00FF00FFL;
-	x ^= z << 010;
-	y ^= z;
-	z  = ((y >> 002) ^ x) & 0x33333333L;
-	y ^= z << 002;
-	x ^= z;
-	z  = ((x >> 020) ^ y) & 0x0000FFFFL;
-	x ^= z << 020;
-	y ^= z;
-	z  = ((y >> 004) ^ x) & 0x0F0F0F0FL;
-	y ^= z << 004;
-	x ^= z;
-	dst[0] = x;
-	x >>= 8;
-	dst[1] = x;
-	x >>= 8;
-	dst[2] = x;
-	x >>= 8;
-	dst[3] = x;
-	dst[4] = y;
-	y >>= 8;
-	dst[5] = y;
-	y >>= 8;
-	dst[6] = y;
-	y >>= 8;
-	dst[7] = y;
+	d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d];
+	c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c];
+	b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
+	a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
+
+	pe[15 * 2 + 0] = PC2(a, b, c, d); d = rs[d];
+	pe[14 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[13 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[12 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[11 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[10 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 9 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 8 * 2 + 0] = PC2(d, a, b, c); c = rs[c];
+	pe[ 7 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 6 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 5 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 4 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 3 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 2 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 1 * 2 + 0] = PC2(c, d, a, b); b = rs[b];
+	pe[ 0 * 2 + 0] = PC2(b, c, d, a);
+
+	/* Check if first half is weak */
+	w  = (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
+
+	/* Skip to next table set */
+	pt += 512;
+
+	d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1];
+	c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1];
+	b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
+	a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];
+
+	/* Check if second half is weak */
+	w |= (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
+
+	pe[15 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
+	pe[14 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[13 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[12 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[11 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[10 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 9 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 8 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
+	pe[ 7 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 6 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 5 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 4 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 3 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 2 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 1 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
+	pe[ 0 * 2 + 1] = PC2(b, c, d, a);
+
+	/* Fixup: 2413 5768 -> 1357 2468 */
+	for (d = 0; d < 16; ++d) {
+		a = pe[2 * d];
+		b = pe[2 * d + 1];
+		c = a ^ b;
+		c &= 0xffff0000;
+		a ^= c;
+		b ^= c;
+		ROL(b, 18);
+		pe[2 * d] = a;
+		pe[2 * d + 1] = b;
+	}
+
+	/* Zero if weak key */
+	return w;
 }
 
 /*
- * RFC2451: Weak key checks SHOULD be performed.
+ * Decryption key expansion
+ *
+ * No weak key checking is performed, as this is only used by triple DES
+ *
  */
-static int setkey(u32 *expkey, const u8 *key, unsigned int keylen, u32 *flags)
+static void dkey(u32 *pe, const u8 *k)
 {
-	const u8 *k;
-	u8 *b0, *b1;
-	u32 n, w;
-	u8 bits0[56], bits1[56];
+	/* K&R: long is at least 32 bits */
+	unsigned long a, b, c, d;
+	const u32 *pt = pc2;
 
-	n  = parity[key[0]]; n <<= 4;
-	n |= parity[key[1]]; n <<= 4;
-	n |= parity[key[2]]; n <<= 4;
-	n |= parity[key[3]]; n <<= 4;
-	n |= parity[key[4]]; n <<= 4;
-	n |= parity[key[5]]; n <<= 4;
-	n |= parity[key[6]]; n <<= 4;
-	n |= parity[key[7]];
-	w = 0x88888888L;
-	
-	if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY)
-	    && !((n - (w >> 3)) & w)) {  /* 1 in 10^10 keys passes this test */
-		if (n < 0x41415151) {
-			if (n < 0x31312121) {
-				if (n < 0x14141515) {
-					/* 01 01 01 01 01 01 01 01 */
-					if (n == 0x11111111) goto weak;
-					/* 01 1F 01 1F 01 0E 01 0E */
-					if (n == 0x13131212) goto weak;
-				} else {
-					/* 01 E0 01 E0 01 F1 01 F1 */
-					if (n == 0x14141515) goto weak;
-					/* 01 FE 01 FE 01 FE 01 FE */
-					if (n == 0x16161616) goto weak;
-				}
-			} else {
-				if (n < 0x34342525) {
-					/* 1F 01 1F 01 0E 01 0E 01 */
-					if (n == 0x31312121) goto weak;
-					/* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
-					if (n == 0x33332222) goto weak;
-				} else {
-					/* 1F E0 1F E0 0E F1 0E F1 */
-					if (n == 0x34342525) goto weak;
-					/* 1F FE 1F FE 0E FE 0E FE */
-					if (n == 0x36362626) goto weak;
-				}
-			}
-		} else {
-			if (n < 0x61616161) {
-				if (n < 0x44445555) {
-					/* E0 01 E0 01 F1 01 F1 01 */
-					if (n == 0x41415151) goto weak;
-					/* E0 1F E0 1F F1 0E F1 0E */
-					if (n == 0x43435252) goto weak;
-				} else {
-					/* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
-					if (n == 0x44445555) goto weak;
-					/* E0 FE E0 FE F1 FE F1 FE */
-					if (n == 0x46465656) goto weak;
-				}
-			} else {
-				if (n < 0x64646565) {
-					/* FE 01 FE 01 FE 01 FE 01 */
-					if (n == 0x61616161) goto weak;
-					/* FE 1F FE 1F FE 0E FE 0E */
-					if (n == 0x63636262) goto weak;
-				} else {
-					/* FE E0 FE E0 FE F1 FE F1 */
-					if (n == 0x64646565) goto weak;
-					/* FE FE FE FE FE FE FE FE */
-					if (n == 0x66666666) goto weak;
-				}
-			}
-		}
-	
-		goto not_weak;
-weak:
-		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
-		return -EINVAL;
+	d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d];
+	c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c];
+	b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
+	a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
+
+	pe[ 0 * 2] = PC2(a, b, c, d); d = rs[d];
+	pe[ 1 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 2 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 3 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 4 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 5 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 6 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 7 * 2] = PC2(d, a, b, c); c = rs[c];
+	pe[ 8 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 9 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[10 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[11 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[12 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[13 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[14 * 2] = PC2(c, d, a, b); b = rs[b];
+	pe[15 * 2] = PC2(b, c, d, a);
+
+	/* Skip to next table set */
+	pt += 512;
+
+	d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1];
+	c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1];
+	b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
+	a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];
+
+	pe[ 0 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
+	pe[ 1 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 2 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 3 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 4 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 5 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 6 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 7 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
+	pe[ 8 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 9 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[10 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[11 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[12 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[13 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[14 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
+	pe[15 * 2 + 1] = PC2(b, c, d, a);
+
+	/* Fixup: 2413 5768 -> 1357 2468 */
+	for (d = 0; d < 16; ++d) {
+		a = pe[2 * d];
+		b = pe[2 * d + 1];
+		c = a ^ b;
+		c &= 0xffff0000;
+		a ^= c;
+		b ^= c;
+		ROL(b, 18);
+		pe[2 * d] = a;
+		pe[2 * d + 1] = b;
 	}
-
-not_weak:
-
-	/* explode the bits */
-	n = 56;
-	b0 = bits0;
-	b1 = bits1;
-	
-	do {
-		w = (256 | *key++) << 2;
-		do {
-			--n;
-			b1[n] = 8 & w;
-			w >>= 1;
-			b0[n] = 4 & w;
-		} while ( w >= 16 );
-	} while ( n );
-	
-	/* put the bits in the correct places */
-	n = 16;
-	k = rotors;
-	
-	do {
-		w   = (b1[k[ 0   ]] | b0[k[ 1   ]]) << 4;
-		w  |= (b1[k[ 2   ]] | b0[k[ 3   ]]) << 2;
-		w  |=  b1[k[ 4   ]] | b0[k[ 5   ]];
-		w <<= 8;
-		w  |= (b1[k[ 6   ]] | b0[k[ 7   ]]) << 4;
-		w  |= (b1[k[ 8   ]] | b0[k[ 9   ]]) << 2;
-		w  |=  b1[k[10   ]] | b0[k[11   ]];
-		w <<= 8;
-		w  |= (b1[k[12   ]] | b0[k[13   ]]) << 4;
-		w  |= (b1[k[14   ]] | b0[k[15   ]]) << 2;
-		w  |=  b1[k[16   ]] | b0[k[17   ]];
-		w <<= 8;
-		w  |= (b1[k[18   ]] | b0[k[19   ]]) << 4;
-		w  |= (b1[k[20   ]] | b0[k[21   ]]) << 2;
-		w  |=  b1[k[22   ]] | b0[k[23   ]];
-		expkey[0] = w;
-		
-		w   = (b1[k[ 0+24]] | b0[k[ 1+24]]) << 4;
-		w  |= (b1[k[ 2+24]] | b0[k[ 3+24]]) << 2;
-		w  |=  b1[k[ 4+24]] | b0[k[ 5+24]];
-		w <<= 8;
-		w  |= (b1[k[ 6+24]] | b0[k[ 7+24]]) << 4;
-		w  |= (b1[k[ 8+24]] | b0[k[ 9+24]]) << 2;
-		w  |=  b1[k[10+24]] | b0[k[11+24]];
-		w <<= 8;
-		w  |= (b1[k[12+24]] | b0[k[13+24]]) << 4;
-		w  |= (b1[k[14+24]] | b0[k[15+24]]) << 2;
-		w  |=  b1[k[16+24]] | b0[k[17+24]];
-		w <<= 8;
-		w  |= (b1[k[18+24]] | b0[k[19+24]]) << 4;
-		w  |= (b1[k[20+24]] | b0[k[21+24]]) << 2;
-		w  |=  b1[k[22+24]] | b0[k[23+24]];
-		
-		ROR(w, 4, 28);      /* could be eliminated */
-		expkey[1] = w;
-
-		k += 48;
-		expkey += 2;
-	} while (--n);
-
-	return 0;
 }
 
 static int des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
 {
-	return setkey(((struct des_ctx *)ctx)->expkey, key, keylen, flags);
+	struct des_ctx *dctx = ctx;
+	u32 tmp[DES_EXPKEY_WORDS];
+	int ret;
+
+	/* Expand to tmp */
+	ret = ekey(tmp, key);
+
+	if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+		return -EINVAL;
+	}
+
+	/* Copy to output */
+	memcpy(dctx->expkey, tmp, sizeof(dctx->expkey));
+
+	return 0;
 }
 
 static void des_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	des_small_fips_encrypt(((struct des_ctx *)ctx)->expkey, dst, src);
+	const u32 *K = ((struct des_ctx *)ctx)->expkey;
+	const __le32 *s = (const __le32 *)src;
+	__le32 *d = (__le32 *)dst;
+	u32 L, R, A, B;
+	int i;
+
+	L = le32_to_cpu(s[0]);
+	R = le32_to_cpu(s[1]);
+
+	IP(L, R, A);
+	for (i = 0; i < 8; i++) {
+		ROUND(L, R, A, B, K, 2);
+		ROUND(R, L, A, B, K, 2);
+	}
+	FP(R, L, A);
+
+	d[0] = cpu_to_le32(R);
+	d[1] = cpu_to_le32(L);
 }
 
 static void des_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	des_small_fips_decrypt(((struct des_ctx *)ctx)->expkey, dst, src);
+	const u32 *K = ((struct des_ctx *)ctx)->expkey + DES_EXPKEY_WORDS - 2;
+	const __le32 *s = (const __le32 *)src;
+	__le32 *d = (__le32 *)dst;
+	u32 L, R, A, B;
+	int i;
+
+	L = le32_to_cpu(s[0]);
+	R = le32_to_cpu(s[1]);
+
+	IP(L, R, A);
+	for (i = 0; i < 8; i++) {
+		ROUND(L, R, A, B, K, -2);
+		ROUND(R, L, A, B, K, -2);
+	}
+	FP(R, L, A);
+
+	d[0] = cpu_to_le32(R);
+	d[1] = cpu_to_le32(L);
 }
 
-/* 
+/*
  * RFC2451:
  *
  *   For DES-EDE3, there is no known need to reject weak or
@@ -1199,44 +859,86 @@
  *
  */
 static int des3_ede_setkey(void *ctx, const u8 *key,
-                           unsigned int keylen, u32 *flags)
+			   unsigned int keylen, u32 *flags)
 {
-	unsigned int i, off;
+	const u32 *K = (const u32 *)key;
 	struct des3_ede_ctx *dctx = ctx;
+	u32 *expkey = dctx->expkey;
 
-	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && 
-	    memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
-	    					DES_KEY_SIZE))) {
-
+	if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
+		     !((K[2] ^ K[4]) | (K[3] ^ K[5]))))
+	{
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
 		return -EINVAL;
 	}
-	
-	for (i = 0, off = 0; i < 3; i++, off += DES_EXPKEY_WORDS,
-							key += DES_KEY_SIZE) {
-		int ret = setkey(&dctx->expkey[off], key, DES_KEY_SIZE, flags);
-		if (ret < 0)
-			return ret;
-	}	
+
+	ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
+	dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
+	ekey(expkey, key);
+
 	return 0;
 }
 
 static void des3_ede_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
 	struct des3_ede_ctx *dctx = ctx;
-	
-	des_small_fips_encrypt(dctx->expkey, dst, src);
-	des_small_fips_decrypt(&dctx->expkey[DES_EXPKEY_WORDS], dst, dst);
-	des_small_fips_encrypt(&dctx->expkey[DES_EXPKEY_WORDS * 2], dst, dst);
+	const u32 *K = dctx->expkey;
+	const __le32 *s = (const __le32 *)src;
+	__le32 *d = (__le32 *)dst;
+	u32 L, R, A, B;
+	int i;
+
+	L = le32_to_cpu(s[0]);
+	R = le32_to_cpu(s[1]);
+
+	IP(L, R, A);
+	for (i = 0; i < 8; i++) {
+		ROUND(L, R, A, B, K, 2);
+		ROUND(R, L, A, B, K, 2);
+	}
+	for (i = 0; i < 8; i++) {
+		ROUND(R, L, A, B, K, 2);
+		ROUND(L, R, A, B, K, 2);
+	}
+	for (i = 0; i < 8; i++) {
+		ROUND(L, R, A, B, K, 2);
+		ROUND(R, L, A, B, K, 2);
+	}
+	FP(R, L, A);
+
+	d[0] = cpu_to_le32(R);
+	d[1] = cpu_to_le32(L);
 }
 
 static void des3_ede_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
 	struct des3_ede_ctx *dctx = ctx;
+	const u32 *K = dctx->expkey + DES3_EDE_EXPKEY_WORDS - 2;
+	const __le32 *s = (const __le32 *)src;
+	__le32 *d = (__le32 *)dst;
+	u32 L, R, A, B;
+	int i;
 
-	des_small_fips_decrypt(&dctx->expkey[DES_EXPKEY_WORDS * 2], dst, src);
-	des_small_fips_encrypt(&dctx->expkey[DES_EXPKEY_WORDS], dst, dst);
-	des_small_fips_decrypt(dctx->expkey, dst, dst);
+	L = le32_to_cpu(s[0]);
+	R = le32_to_cpu(s[1]);
+
+	IP(L, R, A);
+	for (i = 0; i < 8; i++) {
+		ROUND(L, R, A, B, K, -2);
+		ROUND(R, L, A, B, K, -2);
+	}
+	for (i = 0; i < 8; i++) {
+		ROUND(R, L, A, B, K, -2);
+		ROUND(L, R, A, B, K, -2);
+	}
+	for (i = 0; i < 8; i++) {
+		ROUND(L, R, A, B, K, -2);
+		ROUND(R, L, A, B, K, -2);
+	}
+	FP(R, L, A);
+
+	d[0] = cpu_to_le32(R);
+	d[1] = cpu_to_le32(L);
 }
 
 static struct crypto_alg des_alg = {
@@ -1249,7 +951,7 @@
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	DES_KEY_SIZE,
 	.cia_max_keysize	=	DES_KEY_SIZE,
-	.cia_setkey		= 	des_setkey,
+	.cia_setkey		=	des_setkey,
 	.cia_encrypt		=	des_encrypt,
 	.cia_decrypt		=	des_decrypt } }
 };
@@ -1264,9 +966,9 @@
 	.cra_u			=	{ .cipher = {
 	.cia_min_keysize	=	DES3_EDE_KEY_SIZE,
 	.cia_max_keysize	=	DES3_EDE_KEY_SIZE,
-	.cia_setkey	   	= 	des3_ede_setkey,
-	.cia_encrypt	 	=	des3_ede_encrypt,
-	.cia_decrypt	  	=	des3_ede_decrypt } }
+	.cia_setkey		=	des3_ede_setkey,
+	.cia_encrypt		=	des3_ede_encrypt,
+	.cia_decrypt		=	des3_ede_decrypt } }
 };
 
 MODULE_ALIAS("des3_ede");
@@ -1274,7 +976,7 @@
 static int __init init(void)
 {
 	int ret = 0;
-	
+
 	ret = crypto_register_alg(&des_alg);
 	if (ret < 0)
 		goto out;
@@ -1282,7 +984,7 @@
 	ret = crypto_register_alg(&des3_ede_alg);
 	if (ret < 0)
 		crypto_unregister_alg(&des_alg);
-out:	
+out:
 	return ret;
 }
 
@@ -1297,3 +999,4 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
+MODULE_AUTHOR("Dag Arne Osvik <da@osvik.no>");
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 847df92..da0456b 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -49,8 +49,7 @@
 
 void crypto_free_hmac_block(struct crypto_tfm *tfm)
 {
-	if (tfm->crt_digest.dit_hmac_block)
-		kfree(tfm->crt_digest.dit_hmac_block);
+	kfree(tfm->crt_digest.dit_hmac_block);
 }
 
 void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
diff --git a/crypto/internal.h b/crypto/internal.h
index 964b9a6..6861287 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -16,7 +16,7 @@
 #include <linux/highmem.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/kmod.h>
+#include <linux/kernel.h>
 #include <asm/kmap_types.h>
 
 extern enum km_type crypto_km_types[];
@@ -42,20 +42,6 @@
 		cond_resched();
 }
 
-static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
-{
-	return (void *)&tfm[1];
-}
-
-struct crypto_alg *crypto_alg_lookup(const char *name);
-
-/* A far more intelligent version of this is planned.  For now, just
- * try an exact match on the name of the algorithm. */
-static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
-{
-	return try_then_request_module(crypto_alg_lookup(name), name);
-}
-
 #ifdef CONFIG_CRYPTO_HMAC
 int crypto_alloc_hmac_block(struct crypto_tfm *tfm);
 void crypto_free_hmac_block(struct crypto_tfm *tfm);
@@ -76,6 +62,33 @@
 { }
 #endif
 
+static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg,
+						 int flags)
+{
+	return alg->cra_ctxsize;
+}
+
+static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg,
+						 int flags)
+{
+	unsigned int len = alg->cra_ctxsize;
+	
+	switch (flags & CRYPTO_TFM_MODE_MASK) {
+	case CRYPTO_TFM_MODE_CBC:
+		len = ALIGN(len, alg->cra_alignmask + 1);
+		len += alg->cra_blocksize;
+		break;
+	}
+
+	return len;
+}
+
+static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg,
+						   int flags)
+{
+	return alg->cra_ctxsize;
+}
+
 int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
 int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
 int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
index 50c9461..47ac90e 100644
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -100,7 +100,7 @@
 int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
 			   size_t nbytes, int out)
 {
-	do {
+	while (nbytes > walk->len_this_page) {
 		memcpy_dir(buf, walk->data, walk->len_this_page, out);
 		buf += walk->len_this_page;
 		nbytes -= walk->len_this_page;
@@ -108,7 +108,7 @@
 		scatterwalk_unmap(walk, out);
 		scatterwalk_pagedone(walk, out, 1);
 		scatterwalk_map(walk, out);
-	} while (nbytes > walk->len_this_page);
+	}
 
 	memcpy_dir(buf, walk->data, nbytes, out);
 	return nbytes;
diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h
index 02aa56c..e79925c 100644
--- a/crypto/scatterwalk.h
+++ b/crypto/scatterwalk.h
@@ -40,10 +40,10 @@
 	       walk_in->offset == walk_out->offset;
 }
 
-static inline int scatterwalk_across_pages(struct scatter_walk *walk,
-					   unsigned int nbytes)
+static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk,
+					     unsigned int nbytes)
 {
-	return nbytes > walk->len_this_page;
+	return nbytes > walk->len_this_page ? walk->len_this_page : nbytes;
 }
 
 static inline void scatterwalk_advance(struct scatter_walk *walk,
@@ -55,6 +55,12 @@
 	walk->len_this_segment -= nbytes;
 }
 
+static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk,
+					       unsigned int alignmask)
+{
+	return !(walk->offset & alignmask);
+}
+
 void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
 int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out);
 void scatterwalk_map(struct scatter_walk *walk, int out);
diff --git a/crypto/serpent.c b/crypto/serpent.c
index 7d152e8..3cf2c50 100644
--- a/crypto/serpent.c
+++ b/crypto/serpent.c
@@ -210,7 +210,6 @@
 	x4 ^= x2;
 
 struct serpent_ctx {
-	u8 iv[SERPENT_BLOCK_SIZE];
 	u32 expkey[SERPENT_EXPKEY_WORDS];
 };
 
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 5ef9adb..bd2ec7e 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -40,7 +40,6 @@
 #include <linux/skbuff.h>
 #include <asm/io.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -895,11 +894,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &bluecard_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 
@@ -1103,6 +1097,7 @@
 		.name	= "bluecard_cs",
 	},
 	.attach		= bluecard_attach,
+	.event		= bluecard_event,
 	.detach		= bluecard_detach,
 	.id_table	= bluecard_ids,
 };
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 9013cd7..adf1750 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -47,7 +47,6 @@
 #include <linux/device.h>
 #include <linux/firmware.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -696,11 +695,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &bt3c_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 
@@ -947,6 +941,7 @@
 		.name	= "bt3c_cs",
 	},
 	.attach		= bt3c_attach,
+	.event		= bt3c_event,
 	.detach		= bt3c_detach,
 	.id_table	= bt3c_ids,
 };
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index c479484..e4c59fd 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -43,7 +43,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -615,11 +614,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &btuart_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 
@@ -867,6 +861,7 @@
 		.name	= "btuart_cs",
 	},
 	.attach		= btuart_attach,
+	.event		= btuart_event,
 	.detach		= btuart_detach,
 	.id_table	= btuart_ids,
 };
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index bb12f7d..e39868c 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -43,7 +43,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -594,11 +593,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &dtl1_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 
@@ -820,6 +814,7 @@
 		.name	= "dtl1_cs",
 	},
 	.attach		= dtl1_attach,
+	.event		= dtl1_event,
 	.detach		= dtl1_detach,
 	.id_table	= dtl1_ids,
 };
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 3256192..f9b956fb 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -120,7 +120,7 @@
 
 	poll_wait(file, &hci_vhci->read_wait, wait);
  
-	if (skb_queue_len(&hci_vhci->readq))
+	if (!skb_queue_empty(&hci_vhci->readq))
 		return POLLIN | POLLRDNORM;
 
 	return POLLOUT | POLLWRNORM;
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 1aff819..08f6928 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -40,7 +40,7 @@
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)		+= sx.o generic_serial.o
 obj-$(CONFIG_RIO)		+= rio/ generic_serial.o
-obj-$(CONFIG_HVC_CONSOLE)	+= hvc_console.o hvsi.o
+obj-$(CONFIG_HVC_CONSOLE)	+= hvc_console.o hvc_vio.o hvsi.o
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
 obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
 obj-$(CONFIG_MMTIMER)		+= mmtimer.o
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index c2b12ea..123417e 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -96,3 +96,10 @@
           chipset. If M is selected the module will be called sis. AGP
           support is required for this driver to work.
 
+config DRM_VIA
+	tristate "Via unichrome video cards"
+	depends on DRM
+	help
+	  Choose this option if you have a Via unichrome or compatible video
+	  chipset. If M is selected the module will be called via.
+
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index 7444dec..ddd9410 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -18,10 +18,14 @@
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
 ffb-objs    := ffb_drv.o ffb_context.o
 sis-objs    := sis_drv.o sis_ds.o sis_mm.o
+via-objs    := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o
 
 ifeq ($(CONFIG_COMPAT),y)
 drm-objs    += drm_ioc32.o
 radeon-objs += radeon_ioc32.o
+mga-objs    += mga_ioc32.o
+r128-objs   += r128_ioc32.o
+i915-objs   += i915_ioc32.o
 endif
 
 obj-$(CONFIG_DRM)	+= drm.o
@@ -35,4 +39,5 @@
 obj-$(CONFIG_DRM_I915)  += i915.o
 obj-$(CONFIG_DRM_FFB)   += ffb.o
 obj-$(CONFIG_DRM_SIS)   += sis.o
+obj-$(CONFIG_DRM_VIA)	+=via.o
 
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index fdca187..0aec5ef 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -52,7 +52,7 @@
 # define ATI_MAX_PCIGART_PAGES		8192	/**< 32 MB aperture, 4K pages */
 # define ATI_PCIGART_PAGE_SIZE		4096	/**< PCI GART page size */
 
-unsigned long drm_ati_alloc_pcigart_table( void )
+static unsigned long drm_ati_alloc_pcigart_table( void )
 {
 	unsigned long address;
 	struct page *page;
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 5873052..e8371dd 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -38,7 +38,9 @@
 #define _DRM_H_
 
 #if defined(__linux__)
+#if defined(__KERNEL__)
 #include <linux/config.h>
+#endif
 #include <asm/ioctl.h>		/* For _IO* macros */
 #define DRM_IOCTL_NR(n)		_IOC_NR(n)
 #define DRM_IOC_VOID		_IOC_NONE
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index b04ddf1..5df09cc 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -774,8 +774,6 @@
 				/* Driver support (drm_drv.h) */
 extern int           drm_init(struct drm_driver *driver);
 extern void          drm_exit(struct drm_driver *driver);
-extern int           drm_version(struct inode *inode, struct file *filp,
-				  unsigned int cmd, unsigned long arg);
 extern int           drm_ioctl(struct inode *inode, struct file *filp,
 				unsigned int cmd, unsigned long arg);
 extern long	     drm_compat_ioctl(struct file *filp,
@@ -785,28 +783,19 @@
 				/* Device support (drm_fops.h) */
 extern int           drm_open(struct inode *inode, struct file *filp);
 extern int           drm_stub_open(struct inode *inode, struct file *filp);
-extern int	     drm_open_helper(struct inode *inode, struct file *filp,
-				      drm_device_t *dev);
 extern int	     drm_flush(struct file *filp);
 extern int	     drm_fasync(int fd, struct file *filp, int on);
 extern int           drm_release(struct inode *inode, struct file *filp);
 
 				/* Mapping support (drm_vm.h) */
-extern void	     drm_vm_open(struct vm_area_struct *vma);
-extern void	     drm_vm_close(struct vm_area_struct *vma);
-extern void	     drm_vm_shm_close(struct vm_area_struct *vma);
-extern int	     drm_mmap_dma(struct file *filp,
-				   struct vm_area_struct *vma);
 extern int	     drm_mmap(struct file *filp, struct vm_area_struct *vma);
 extern unsigned int  drm_poll(struct file *filp, struct poll_table_struct *wait);
-extern ssize_t       drm_read(struct file *filp, char __user *buf, size_t count, loff_t *off);
 
 				/* Memory management support (drm_memory.h) */
 #include "drm_memory.h"
 extern void	     drm_mem_init(void);
 extern int	     drm_mem_info(char *buf, char **start, off_t offset,
 				   int request, int *eof, void *data);
-extern void	     *drm_calloc(size_t nmemb, size_t size, int area);
 extern void	     *drm_realloc(void *oldpt, size_t oldsize, size_t size,
 				   int area);
 extern unsigned long drm_alloc_pages(int order, int area);
@@ -854,9 +843,6 @@
 extern int	     drm_rmctx( struct inode *inode, struct file *filp,
 				 unsigned int cmd, unsigned long arg );
 
-extern int	     drm_context_switch(drm_device_t *dev, int old, int new);
-extern int	     drm_context_switch_complete(drm_device_t *dev, int new);
-
 extern int	     drm_ctxbitmap_init( drm_device_t *dev );
 extern void	     drm_ctxbitmap_cleanup( drm_device_t *dev );
 extern void          drm_ctxbitmap_free( drm_device_t *dev, int ctx_handle );
@@ -874,9 +860,6 @@
 
 
 				/* Authentication IOCTL support (drm_auth.h) */
-extern int	     drm_add_magic(drm_device_t *dev, drm_file_t *priv,
-				    drm_magic_t magic);
-extern int	     drm_remove_magic(drm_device_t *dev, drm_magic_t magic);
 extern int	     drm_getmagic(struct inode *inode, struct file *filp,
 				   unsigned int cmd, unsigned long arg);
 extern int	     drm_authmagic(struct inode *inode, struct file *filp,
@@ -893,13 +876,9 @@
 				 unsigned int cmd, unsigned long arg);
 extern int	     drm_lock_take(__volatile__ unsigned int *lock,
 				    unsigned int context);
-extern int	     drm_lock_transfer(drm_device_t *dev,
-					__volatile__ unsigned int *lock,
-					unsigned int context);
 extern int	     drm_lock_free(drm_device_t *dev,
 				    __volatile__ unsigned int *lock,
 				    unsigned int context);
-extern int           drm_notifier(void *priv);
 
 				/* Buffer management support (drm_bufs.h) */
 extern int	     drm_order( unsigned long size );
@@ -927,7 +906,6 @@
 				/* IRQ support (drm_irq.h) */
 extern int           drm_control( struct inode *inode, struct file *filp,
 				   unsigned int cmd, unsigned long arg );
-extern int           drm_irq_install( drm_device_t *dev );
 extern int           drm_irq_uninstall( drm_device_t *dev );
 extern irqreturn_t   drm_irq_handler( DRM_IRQ_ARGS );
 extern void          drm_driver_irq_preinstall( drm_device_t *dev );
@@ -967,7 +945,6 @@
 extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
 		     struct drm_driver *driver);
 extern int drm_put_dev(drm_device_t * dev);
-extern int drm_get_head(drm_device_t * dev, drm_head_t *head);
 extern int drm_put_head(drm_head_t * head);
 extern unsigned int   drm_debug;
 extern unsigned int   drm_cards_limit;
@@ -1064,9 +1041,16 @@
 {
 	kfree(pt);
 }
+
+/** Wrapper around kcalloc() */
+static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area)
+{
+	return kcalloc(nmemb, size, GFP_KERNEL);
+}
 #else
 extern void *drm_alloc(size_t size, int area);
 extern void drm_free(void *pt, size_t size, int area);
+extern void *drm_calloc(size_t nmemb, size_t size, int area);
 #endif
 
 /*@}*/
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index b428761..dd140bc 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -87,7 +87,7 @@
  * associated the magic number hash key in drm_device::magiclist, while holding
  * the drm_device::struct_sem lock.
  */
-int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+static int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
 {
 	int		  hash;
 	drm_magic_entry_t *entry;
@@ -124,7 +124,7 @@
  * Searches and unlinks the entry in drm_device::magiclist with the magic
  * number hash key, while holding the drm_device::struct_sem lock.
  */
-int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
+static int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
 {
 	drm_magic_entry_t *prev = NULL;
 	drm_magic_entry_t *pt;
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 3407380..4c6191d 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -356,8 +356,8 @@
  * reallocates the buffer list of the same size order to accommodate the new
  * buffers.
  */
-int drm_addbufs_agp( struct inode *inode, struct file *filp,
-		      unsigned int cmd, unsigned long arg )
+static int drm_addbufs_agp( struct inode *inode, struct file *filp,
+			    unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
@@ -521,8 +521,8 @@
 }
 #endif /* __OS_HAS_AGP */
 
-int drm_addbufs_pci( struct inode *inode, struct file *filp,
-		      unsigned int cmd, unsigned long arg )
+static int drm_addbufs_pci( struct inode *inode, struct file *filp,
+			    unsigned int cmd, unsigned long arg )
 {
    	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
@@ -751,8 +751,8 @@
 
 }
 
-int drm_addbufs_sg( struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg )
+static int drm_addbufs_sg( struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index fdf661f..a7cfabd 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -84,7 +84,7 @@
  * drm_device::context_sareas to accommodate the new entry while holding the
  * drm_device::struct_sem lock.
  */
-int drm_ctxbitmap_next( drm_device_t *dev )
+static int drm_ctxbitmap_next( drm_device_t *dev )
 {
 	int bit;
 
@@ -326,7 +326,7 @@
  * hardware lock is held, clears the drm_device::context_flag and wakes up
  * drm_device::context_wait.
  */
-int drm_context_switch_complete( drm_device_t *dev, int new )
+static int drm_context_switch_complete( drm_device_t *dev, int new )
 {
         dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
         dev->last_switch  = jiffies;
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 1e37ed0..3333c25 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -51,8 +51,11 @@
 #include "drmP.h"
 #include "drm_core.h"
 
+static int drm_version(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+
 /** Ioctl table */
-drm_ioctl_desc_t		  drm_ioctls[] = {
+static drm_ioctl_desc_t		  drm_ioctls[] = {
 	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]       = { drm_version,     0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]    = { drm_getunique,   0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]     = { drm_getmagic,    0, 0 },
@@ -447,8 +450,8 @@
  *
  * Fills in the version information in \p arg.
  */
-int drm_version( struct inode *inode, struct file *filp,
-		  unsigned int cmd, unsigned long arg )
+static int drm_version( struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 9067942..10e64fd 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -37,6 +37,8 @@
 #include "drmP.h"
 #include <linux/poll.h>
 
+static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev);
+
 static int drm_setup( drm_device_t *dev )
 {
 	int i;
@@ -251,7 +253,7 @@
 		}
 	}
 	
-	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
+	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->release)
 	{
 		dev->driver->reclaim_buffers(dev, filp);
 	}
@@ -259,7 +261,7 @@
 	drm_fasync( -1, filp, 0 );
 
 	down( &dev->ctxlist_sem );
-	if ( !list_empty( &dev->ctxlist->head ) ) {
+	if ( dev->ctxlist && (!list_empty(&dev->ctxlist->head))) {
 		drm_ctx_list_t *pos, *n;
 
 		list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) {
@@ -341,7 +343,7 @@
  * Creates and initializes a drm_file structure for the file private data in \p
  * filp and add it into the double linked list in \p dev.
  */
-int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
+static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
 {
 	int	     minor = iminor(inode);
 	drm_file_t   *priv;
@@ -443,9 +445,3 @@
 }
 EXPORT_SYMBOL(drm_poll);
 
-
-/** No-op. */
-ssize_t drm_read(struct file *filp, char __user *buf, size_t count, loff_t *off)
-{
-	return 0;
-}
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 2e236eb..cdd4aec 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -89,7 +89,7 @@
  * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
  * before and after the installation.
  */
-int drm_irq_install( drm_device_t *dev )
+static int drm_irq_install( drm_device_t *dev )
 {
 	int ret;
 	unsigned long sh_flags=0;
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index d0d6fc6..4702d86 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -35,6 +35,11 @@
 
 #include "drmP.h"
 
+static int drm_lock_transfer(drm_device_t *dev,
+			     __volatile__ unsigned int *lock,
+			     unsigned int context);
+static int drm_notifier(void *priv);
+
 /** 
  * Lock ioctl.
  *
@@ -225,8 +230,9 @@
  * Resets the lock file pointer.
  * Marks the lock as held by the given context, via the \p cmpxchg instruction.
  */
-int drm_lock_transfer(drm_device_t *dev,
-		       __volatile__ unsigned int *lock, unsigned int context)
+static int drm_lock_transfer(drm_device_t *dev,
+			     __volatile__ unsigned int *lock,
+			     unsigned int context)
 {
 	unsigned int old, new, prev;
 
@@ -282,7 +288,7 @@
  * \return one if the signal should be delivered normally, or zero if the
  * signal should be blocked.
  */
-int drm_notifier(void *priv)
+static int drm_notifier(void *priv)
 {
 	drm_sigdata_t *s = (drm_sigdata_t *)priv;
 	unsigned int  old, new, prev;
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 7f53f75..ace3d42 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -65,19 +65,6 @@
 	return 0;
 }
 
-/** Wrapper around kmalloc() */
-void *drm_calloc(size_t nmemb, size_t size, int area)
-{
-	void *addr;
-
-	addr = kmalloc(size * nmemb, GFP_KERNEL);
-	if (addr != NULL)
-		memset((void *)addr, 0, size * nmemb);
-
-	return addr;
-}
-EXPORT_SYMBOL(drm_calloc);
-
 /** Wrapper around kmalloc() and kfree() */
 void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
 {
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 11c6950..70ca4fa 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -223,3 +223,10 @@
 	{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
 
+#define viadrv_PCI_IDS \
+	{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0, 0, 0}
+
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 6e06e8c..4774087 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -57,7 +57,7 @@
 /**
  * Proc file list.
  */
-struct drm_proc_list {
+static struct drm_proc_list {
 	const char *name;	/**< file name */
 	int	   (*f)(char *, char **, off_t, int, int *, void *);	/**< proc callback*/
 } drm_proc_list[] = {
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 8ccbdef..48829a1 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -157,52 +157,6 @@
 	return err;
 }
 
-
-/**
- * Register.
- *
- * \param pdev - PCI device structure
- * \param ent entry from the PCI ID table with device type flags
- * \return zero on success or a negative number on failure.
- *
- * Attempt to gets inter module "drm" information. If we are first
- * then register the character device and inter module information.
- * Try and register, if we fail to register, backout previous work.
- */
-int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
-	      struct drm_driver *driver)
-{
-	drm_device_t *dev;
-	int ret;
-
-	DRM_DEBUG("\n");
-
-	dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
-	if (!dev)
-		return -ENOMEM;
-
-	pci_enable_device(pdev);
-
-	if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
-		printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
-		goto err_g1;
-	}
-	if ((ret = drm_get_head(dev, &dev->primary)))
-		goto err_g1;
-
-	/* postinit is a required function to display the signon banner */
-	/* drivers add secondary heads here if needed */
-	if ((ret = dev->driver->postinit(dev, ent->driver_data)))
-		goto err_g1;
-
-	return 0;
-
-err_g1:
-	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
-	return ret;
-}
-EXPORT_SYMBOL(drm_get_dev);
-
 /**
  * Get a secondary minor number.
  *
@@ -214,7 +168,7 @@
  * create the proc init entry via proc_init(). This routines assigns
  * minor numbers to secondary heads of multi-headed cards
  */
-int drm_get_head(drm_device_t *dev, drm_head_t *head)
+static int drm_get_head(drm_device_t *dev, drm_head_t *head)
 {
 	drm_head_t **heads = drm_heads;
 	int ret;
@@ -262,6 +216,50 @@
 	return ret;
 }
 		
+/**
+ * Register.
+ *
+ * \param pdev - PCI device structure
+ * \param ent entry from the PCI ID table with device type flags
+ * \return zero on success or a negative number on failure.
+ *
+ * Attempt to gets inter module "drm" information. If we are first
+ * then register the character device and inter module information.
+ * Try and register, if we fail to register, backout previous work.
+ */
+int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+	      struct drm_driver *driver)
+{
+	drm_device_t *dev;
+	int ret;
+
+	DRM_DEBUG("\n");
+
+	dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
+	if (!dev)
+		return -ENOMEM;
+
+	pci_enable_device(pdev);
+
+	if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
+		printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
+		goto err_g1;
+	}
+	if ((ret = drm_get_head(dev, &dev->primary)))
+		goto err_g1;
+
+	/* postinit is a required function to display the signon banner */
+	/* drivers add secondary heads here if needed */
+	if ((ret = dev->driver->postinit(dev, ent->driver_data)))
+		goto err_g1;
+
+	return 0;
+
+err_g1:
+	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
+	return ret;
+}
+EXPORT_SYMBOL(drm_get_dev);
 
 /**
  * Put a device minor number.
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index fc72f30..621220f 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -38,6 +38,8 @@
 #include <linux/efi.h>
 #endif
 
+static void drm_vm_open(struct vm_area_struct *vma);
+static void drm_vm_close(struct vm_area_struct *vma);
 
 /**
  * \c nopage method for AGP virtual memory.
@@ -163,7 +165,7 @@
  * Deletes map information if we are the last
  * person to close a mapping and it's not in the global maplist.
  */
-void drm_vm_shm_close(struct vm_area_struct *vma)
+static void drm_vm_shm_close(struct vm_area_struct *vma)
 {
 	drm_file_t	*priv	= vma->vm_file->private_data;
 	drm_device_t	*dev	= priv->head->dev;
@@ -399,7 +401,7 @@
  * Create a new drm_vma_entry structure as the \p vma private data entry and
  * add it to drm_device::vmalist.
  */
-void drm_vm_open(struct vm_area_struct *vma)
+static void drm_vm_open(struct vm_area_struct *vma)
 {
 	drm_file_t	*priv	= vma->vm_file->private_data;
 	drm_device_t	*dev	= priv->head->dev;
@@ -428,7 +430,7 @@
  * Search the \p vma private data entry in drm_device::vmalist, unlink it, and
  * free it.
  */
-void drm_vm_close(struct vm_area_struct *vma)
+static void drm_vm_close(struct vm_area_struct *vma)
 {
 	drm_file_t	*priv	= vma->vm_file->private_data;
 	drm_device_t	*dev	= priv->head->dev;
@@ -463,7 +465,7 @@
  * Sets the virtual memory area operations structure to vm_dma_ops, the file
  * pointer, and calls vm_open().
  */
-int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
+static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
 {
 	drm_file_t	 *priv	 = filp->private_data;
 	drm_device_t	 *dev;
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 24857cc..18e0b76 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -90,16 +90,7 @@
    	return 0;
 }
 
-static struct file_operations i810_buffer_fops = {
-	.open	 = drm_open,
-	.flush	 = drm_flush,
-	.release = drm_release,
-	.ioctl	 = drm_ioctl,
-	.mmap	 = i810_mmap_buffers,
-	.fasync  = drm_fasync,
-};
-
-int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 {
 	drm_file_t	    *priv	  = filp->private_data;
 	drm_device_t	    *dev;
@@ -126,6 +117,15 @@
 	return 0;
 }
 
+static struct file_operations i810_buffer_fops = {
+	.open	 = drm_open,
+	.flush	 = drm_flush,
+	.release = drm_release,
+	.ioctl	 = drm_ioctl,
+	.mmap	 = i810_mmap_buffers,
+	.fasync  = drm_fasync,
+};
+
 static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
 {
 	drm_file_t	  *priv	  = filp->private_data;
@@ -1003,8 +1003,8 @@
 	}
 }
 
-int i810_flush_ioctl(struct inode *inode, struct file *filp,
-		     unsigned int cmd, unsigned long arg)
+static int i810_flush_ioctl(struct inode *inode, struct file *filp,
+			    unsigned int cmd, unsigned long arg)
 {
    	drm_file_t	  *priv	  = filp->private_data;
    	drm_device_t	  *dev	  = priv->head->dev;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index fa23ca4..1b40538 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -115,7 +115,6 @@
 
 				/* i810_dma.c */
 extern void i810_reclaim_buffers(drm_device_t *dev, struct file *filp);
-extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
 
 extern int i810_driver_dma_quiescent(drm_device_t *dev);
 extern void i810_driver_release(drm_device_t *dev, struct file *filp);
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 98adccf..dc77330 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -92,16 +92,7 @@
    	return 0;
 }
 
-static struct file_operations i830_buffer_fops = {
-	.open	 = drm_open,
-	.flush	 = drm_flush,
-	.release = drm_release,
-	.ioctl	 = drm_ioctl,
-	.mmap	 = i830_mmap_buffers,
-	.fasync  = drm_fasync,
-};
-
-int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 {
 	drm_file_t	    *priv	  = filp->private_data;
 	drm_device_t	    *dev;
@@ -128,6 +119,15 @@
 	return 0;
 }
 
+static struct file_operations i830_buffer_fops = {
+	.open	 = drm_open,
+	.flush	 = drm_flush,
+	.release = drm_release,
+	.ioctl	 = drm_ioctl,
+	.mmap	 = i830_mmap_buffers,
+	.fasync  = drm_fasync,
+};
+
 static int i830_map_buffer(drm_buf_t *buf, struct file *filp)
 {
 	drm_file_t	  *priv	  = filp->private_data;
diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c
index aa80ad6..bc36be7 100644
--- a/drivers/char/drm/i830_drv.c
+++ b/drivers/char/drm/i830_drv.c
@@ -40,7 +40,7 @@
 
 #include "drm_pciids.h"
 
-int postinit( struct drm_device *dev, unsigned long flags )
+static int postinit( struct drm_device *dev, unsigned long flags )
 {
 	dev->counters += 4;
 	dev->types[6] = _DRM_STAT_IRQ;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index d4b2d09..df77461 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -123,8 +123,6 @@
 /* i830_dma.c */
 extern void i830_reclaim_buffers(drm_device_t *dev, struct file *filp);
 
-extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
-
 /* i830_irq.c */
 extern int i830_irq_emit( struct inode *inode, struct file *filp, 
 			  unsigned int cmd, unsigned long arg );
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index 6d7729f..a5923e5 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -54,8 +54,7 @@
 	return IRQ_HANDLED;
 }
 
-
-int i830_emit_irq(drm_device_t *dev)
+static int i830_emit_irq(drm_device_t *dev)
 {
 	drm_i830_private_t *dev_priv = dev->dev_private;
 	RING_LOCALS;
@@ -73,7 +72,7 @@
 }
 
 
-int i830_wait_irq(drm_device_t *dev, int irq_nr)
+static int i830_wait_irq(drm_device_t *dev, int irq_nr)
 {
   	drm_i830_private_t *dev_priv = 
 	   (drm_i830_private_t *)dev->dev_private;
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index b5903f9..acf9e52 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -32,23 +32,6 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-drm_ioctl_desc_t i915_ioctls[] = {
-	[DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, 1, 1},
-	[DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, 1, 1},
-	[DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, 1, 0},
-	[DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, 1, 1},
-	[DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, 1, 0}
-};
-
-int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
-
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
  * the head pointer changes, so that EBUSY only happens if the ring
@@ -95,7 +78,7 @@
 		dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
 }
 
-int i915_dma_cleanup(drm_device_t * dev)
+static int i915_dma_cleanup(drm_device_t * dev)
 {
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
@@ -247,7 +230,7 @@
 	return 0;
 }
 
-int i915_dma_init(DRM_IOCTL_ARGS)
+static int i915_dma_init(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_i915_private_t *dev_priv;
@@ -558,7 +541,7 @@
 	return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
 }
 
-int i915_flush_ioctl(DRM_IOCTL_ARGS)
+static int i915_flush_ioctl(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 
@@ -567,7 +550,7 @@
 	return i915_quiescent(dev);
 }
 
-int i915_batchbuffer(DRM_IOCTL_ARGS)
+static int i915_batchbuffer(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -601,7 +584,7 @@
 	return ret;
 }
 
-int i915_cmdbuffer(DRM_IOCTL_ARGS)
+static int i915_cmdbuffer(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -637,18 +620,7 @@
 	return 0;
 }
 
-int i915_do_cleanup_pageflip(drm_device_t * dev)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-
-	DRM_DEBUG("%s\n", __FUNCTION__);
-	if (dev_priv->current_page != 0)
-		i915_dispatch_flip(dev);
-
-	return 0;
-}
-
-int i915_flip_bufs(DRM_IOCTL_ARGS)
+static int i915_flip_bufs(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 
@@ -659,7 +631,7 @@
 	return i915_dispatch_flip(dev);
 }
 
-int i915_getparam(DRM_IOCTL_ARGS)
+static int i915_getparam(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -694,7 +666,7 @@
 	return 0;
 }
 
-int i915_setparam(DRM_IOCTL_ARGS)
+static int i915_setparam(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -743,3 +715,19 @@
 	}
 }
 
+drm_ioctl_desc_t i915_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, 1, 1},
+	[DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, 1, 1},
+	[DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, 1, 0},
+	[DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, 1, 1},
+	[DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, 1, 0}
+};
+
+int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index e6a9e1d..1f59d3f 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -34,7 +34,7 @@
 
 #include "drm_pciids.h"
 
-int postinit( struct drm_device *dev, unsigned long flags )
+static int postinit( struct drm_device *dev, unsigned long flags )
 {
 	dev->counters += 4;
 	dev->types[6] = _DRM_STAT_IRQ;
@@ -97,6 +97,9 @@
 		.mmap = drm_mmap,
 		.poll = drm_poll,
 		.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+		.compat_ioctl = i915_compat_ioctl,
+#endif
 	},
 	.pci_driver = {
 		.name          = DRIVER_NAME,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index fa940d6..9c37d23 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -99,14 +99,6 @@
 } drm_i915_private_t;
 
 				/* i915_dma.c */
-extern int i915_dma_init(DRM_IOCTL_ARGS);
-extern int i915_dma_cleanup(drm_device_t * dev);
-extern int i915_flush_ioctl(DRM_IOCTL_ARGS);
-extern int i915_batchbuffer(DRM_IOCTL_ARGS);
-extern int i915_flip_bufs(DRM_IOCTL_ARGS);
-extern int i915_getparam(DRM_IOCTL_ARGS);
-extern int i915_setparam(DRM_IOCTL_ARGS);
-extern int i915_cmdbuffer(DRM_IOCTL_ARGS);
 extern void i915_kernel_lost_context(drm_device_t * dev);
 extern void i915_driver_pretakedown(drm_device_t *dev);
 extern void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp);
@@ -114,8 +106,6 @@
 /* i915_irq.c */
 extern int i915_irq_emit(DRM_IOCTL_ARGS);
 extern int i915_irq_wait(DRM_IOCTL_ARGS);
-extern int i915_wait_irq(drm_device_t * dev, int irq_nr);
-extern int i915_emit_irq(drm_device_t * dev);
 
 extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(drm_device_t *dev);
@@ -130,6 +120,10 @@
 extern void i915_mem_release(drm_device_t * dev,
 			     DRMFILE filp, struct mem_block *heap);
 
+extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
+			      unsigned long arg);
+
+
 #define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, reg)
 #define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, reg, val)
 #define I915_READ16(reg) 	DRM_READ16(dev_priv->mmio_map, reg)
diff --git a/drivers/char/drm/i915_ioc32.c b/drivers/char/drm/i915_ioc32.c
new file mode 100644
index 0000000..fe009e1
--- /dev/null
+++ b/drivers/char/drm/i915_ioc32.c
@@ -0,0 +1,221 @@
+/**
+ * \file i915_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the i915 DRM.
+ *
+ * \author Alan Hourihane <alanh@fairlite.demon.co.uk> 
+ *
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Alan Hourihane 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+
+typedef struct _drm_i915_batchbuffer32 {
+	int start;		/* agp offset */
+	int used;		/* nr bytes in use */
+	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */
+	int DR4;		/* window origin for GFX_OP_DRAWRECT_INFO */
+	int num_cliprects;	/* mulitpass with multiple cliprects? */
+	u32 cliprects;	/* pointer to userspace cliprects */
+} drm_i915_batchbuffer32_t;
+
+static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	drm_i915_batchbuffer32_t batchbuffer32;
+	drm_i915_batchbuffer_t __user *batchbuffer;
+	
+	if (copy_from_user(&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32)))
+		return -EFAULT;
+	
+	batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer));
+	if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer))
+	    || __put_user(batchbuffer32.start, &batchbuffer->start)
+	    || __put_user(batchbuffer32.used, &batchbuffer->used)
+	    || __put_user(batchbuffer32.DR1, &batchbuffer->DR1)
+	    || __put_user(batchbuffer32.DR4, &batchbuffer->DR4)
+	    || __put_user(batchbuffer32.num_cliprects, &batchbuffer->num_cliprects)
+	    || __put_user((int __user *)(unsigned long)batchbuffer32.cliprects,
+			  &batchbuffer->cliprects))
+		return -EFAULT;
+	
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_I915_BATCHBUFFER, (unsigned long) batchbuffer);
+}
+
+typedef struct _drm_i915_cmdbuffer32 {
+	u32 buf;	/* pointer to userspace command buffer */
+	int sz;			/* nr bytes in buf */
+	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */
+	int DR4;		/* window origin for GFX_OP_DRAWRECT_INFO */
+	int num_cliprects;	/* mulitpass with multiple cliprects? */
+	u32 cliprects;	/* pointer to userspace cliprects */
+} drm_i915_cmdbuffer32_t;
+
+static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	drm_i915_cmdbuffer32_t cmdbuffer32;
+	drm_i915_cmdbuffer_t __user *cmdbuffer;
+	
+	if (copy_from_user(&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32)))
+		return -EFAULT;
+	
+	cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer));
+	if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer))
+	    || __put_user((int __user *)(unsigned long)cmdbuffer32.buf,
+			  &cmdbuffer->buf)
+	    || __put_user(cmdbuffer32.sz, &cmdbuffer->sz)
+	    || __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1)
+	    || __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4)
+	    || __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects)
+	    || __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects,
+			  &cmdbuffer->cliprects))
+		return -EFAULT;
+	
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_I915_CMDBUFFER, (unsigned long) cmdbuffer);
+}
+
+typedef struct drm_i915_irq_emit32 {
+	u32 irq_seq;
+} drm_i915_irq_emit32_t;
+
+static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
+				  unsigned long arg)
+{
+	drm_i915_irq_emit32_t req32;
+	drm_i915_irq_emit_t __user *request;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+
+	request = compat_alloc_user_space(sizeof(*request));
+	if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+	    || __put_user((int __user *)(unsigned long)req32.irq_seq,
+			  &request->irq_seq))
+		return -EFAULT;
+
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_I915_IRQ_EMIT, (unsigned long) request);
+}
+typedef struct drm_i915_getparam32 {
+	int param;
+	u32 value;
+} drm_i915_getparam32_t;
+
+static int compat_i915_getparam(struct file *file, unsigned int cmd,
+				     unsigned long arg)
+{
+	drm_i915_getparam32_t req32;
+	drm_i915_getparam_t __user *request;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+
+	request = compat_alloc_user_space(sizeof(*request));
+	if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+	    || __put_user(req32.param, &request->param)
+	    || __put_user((void __user *)(unsigned long)req32.value,
+			  &request->value))
+		return -EFAULT;
+
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_I915_GETPARAM, (unsigned long) request);
+}
+
+typedef struct drm_i915_mem_alloc32 {
+	int region;
+	int alignment;
+	int size;
+	u32 region_offset;	/* offset from start of fb or agp */
+} drm_i915_mem_alloc32_t;
+
+static int compat_i915_alloc(struct file *file, unsigned int cmd,
+				     unsigned long arg)
+{
+	drm_i915_mem_alloc32_t req32;
+	drm_i915_mem_alloc_t __user *request;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+
+	request = compat_alloc_user_space(sizeof(*request));
+	if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+	    || __put_user(req32.region, &request->region)
+	    || __put_user(req32.alignment, &request->alignment)
+	    || __put_user(req32.size, &request->size)
+	    || __put_user((void __user *)(unsigned long)req32.region_offset,
+			  &request->region_offset))
+		return -EFAULT;
+
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_I915_ALLOC, (unsigned long) request);
+}
+
+
+drm_ioctl_compat_t *i915_compat_ioctls[] = {
+	[DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer,
+	[DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer,
+	[DRM_I915_GETPARAM] = compat_i915_getparam,
+	[DRM_I915_IRQ_EMIT] = compat_i915_irq_emit,
+	[DRM_I915_ALLOC] = compat_i915_alloc
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long i915_compat_ioctl(struct file *filp, unsigned int cmd,
+			 unsigned long arg)
+{
+	unsigned int nr = DRM_IOCTL_NR(cmd);
+	drm_ioctl_compat_t *fn = NULL;
+	int ret;
+
+	if (nr < DRM_COMMAND_BASE)
+		return drm_compat_ioctl(filp, cmd, arg);
+	
+	if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls))
+		fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+	lock_kernel();		/* XXX for now */
+	if (fn != NULL)
+		ret = (*fn)(filp, cmd, arg);
+	else
+		ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index a101cc9..4fa448e 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -56,7 +56,7 @@
 	return IRQ_HANDLED;
 }
 
-int i915_emit_irq(drm_device_t * dev)
+static int i915_emit_irq(drm_device_t * dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 ret;
@@ -76,7 +76,7 @@
 	return ret;
 }
 
-int i915_wait_irq(drm_device_t * dev, int irq_nr)
+static int i915_wait_irq(drm_device_t * dev, int irq_nr)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	int ret = 0;
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index 22dab3e..844cca9 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -101,6 +101,9 @@
 		.mmap = drm_mmap,
 		.poll = drm_poll,
 		.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+		.compat_ioctl = mga_compat_ioctl,
+#endif
 	},
 	.pci_driver = {
 		.name = DRIVER_NAME,
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index 1d84a1e..9412e281 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -137,6 +137,8 @@
 extern void mga_driver_irq_preinstall( drm_device_t *dev );
 extern void mga_driver_irq_postinstall( drm_device_t *dev );
 extern void mga_driver_irq_uninstall( drm_device_t *dev );
+extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
+			     unsigned long arg);
 
 #define mga_flush_write_combine()	DRM_WRITEMEMORYBARRIER()
 
diff --git a/drivers/char/drm/mga_ioc32.c b/drivers/char/drm/mga_ioc32.c
new file mode 100644
index 0000000..bc745cf
--- /dev/null
+++ b/drivers/char/drm/mga_ioc32.c
@@ -0,0 +1,167 @@
+/**
+ * \file mga_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the MGA DRM.
+ *
+ * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
+ *
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Egbert Eich 2003,2004
+ * Copyright (C) Dave Airlie 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
+
+typedef struct drm32_mga_init {
+	int func;
+   	u32 sarea_priv_offset;
+	int chipset;
+   	int sgram;
+	unsigned int maccess;
+   	unsigned int fb_cpp;
+	unsigned int front_offset, front_pitch;
+   	unsigned int back_offset, back_pitch;
+   	unsigned int depth_cpp;
+   	unsigned int depth_offset, depth_pitch;
+   	unsigned int texture_offset[MGA_NR_TEX_HEAPS];
+   	unsigned int texture_size[MGA_NR_TEX_HEAPS];
+	u32 fb_offset;
+	u32 mmio_offset;
+	u32 status_offset;
+	u32 warp_offset;
+	u32 primary_offset;
+	u32 buffers_offset;
+} drm_mga_init32_t;
+
+static int compat_mga_init(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	drm_mga_init32_t init32;
+	drm_mga_init_t __user *init;
+	int err = 0, i;
+	
+	if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+		return -EFAULT;
+	
+	init = compat_alloc_user_space(sizeof(*init));
+	if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+	    || __put_user(init32.func, &init->func)
+	    || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+	    || __put_user(init32.chipset, &init->chipset)
+	    || __put_user(init32.sgram, &init->sgram)
+	    || __put_user(init32.maccess, &init->maccess)
+	    || __put_user(init32.fb_cpp, &init->fb_cpp)
+	    || __put_user(init32.front_offset, &init->front_offset)
+	    || __put_user(init32.front_pitch, &init->front_pitch)
+	    || __put_user(init32.back_offset, &init->back_offset)
+	    || __put_user(init32.back_pitch, &init->back_pitch)
+	    || __put_user(init32.depth_cpp, &init->depth_cpp)
+	    || __put_user(init32.depth_offset, &init->depth_offset)
+	    || __put_user(init32.depth_pitch, &init->depth_pitch)
+	    || __put_user(init32.fb_offset, &init->fb_offset)
+	    || __put_user(init32.mmio_offset, &init->mmio_offset)
+	    || __put_user(init32.status_offset, &init->status_offset)
+	    || __put_user(init32.warp_offset, &init->warp_offset)
+	    || __put_user(init32.primary_offset, &init->primary_offset)
+	    || __put_user(init32.buffers_offset, &init->buffers_offset))
+		return -EFAULT;
+	
+	for (i=0; i<MGA_NR_TEX_HEAPS; i++)
+	{
+		err |= __put_user(init32.texture_offset[i], &init->texture_offset[i]);
+		err |= __put_user(init32.texture_size[i], &init->texture_size[i]);
+	}
+	if (err)
+		return -EFAULT;
+	
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_MGA_INIT, (unsigned long) init);
+}
+
+
+typedef struct drm_mga_getparam32 {
+	int param;
+	u32 value;
+} drm_mga_getparam32_t;
+
+
+static int compat_mga_getparam(struct file *file, unsigned int cmd,
+			       unsigned long arg)
+{
+	drm_mga_getparam32_t getparam32;
+	drm_mga_getparam_t __user *getparam;
+	
+	if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
+		return -EFAULT;
+
+	getparam = compat_alloc_user_space(sizeof(*getparam));
+	if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
+	    || __put_user(getparam32.param, &getparam->param)
+	    || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value))
+		return -EFAULT;
+
+	return drm_ioctl(file->f_dentry->d_inode, file, 
+			 DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
+}
+
+drm_ioctl_compat_t *mga_compat_ioctls[] = {
+	[DRM_MGA_INIT] = compat_mga_init,
+	[DRM_MGA_GETPARAM] = compat_mga_getparam,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long mga_compat_ioctl(struct file *filp, unsigned int cmd,
+			 unsigned long arg)
+{
+	unsigned int nr = DRM_IOCTL_NR(cmd);
+	drm_ioctl_compat_t *fn = NULL;
+	int ret;
+
+	if (nr < DRM_COMMAND_BASE)
+		return drm_compat_ioctl(filp, cmd, arg);
+	
+	if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
+		fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+	lock_kernel();		/* XXX for now */
+	if (fn != NULL)
+		ret = (*fn)(filp, cmd, arg);
+	else
+		ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index ced6381..bc446da 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -96,6 +96,9 @@
 		.mmap = drm_mmap,
 		.poll = drm_poll,
 		.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+		.compat_ioctl = r128_compat_ioctl,
+#endif
 	},
 	.pci_driver = {
 		.name          = DRIVER_NAME,
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index cf1aa5d..0fb687c9 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -156,6 +156,9 @@
 extern void r128_driver_pretakedown(drm_device_t *dev);
 extern void r128_driver_prerelease(drm_device_t *dev, DRMFILE filp);
 
+extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
+			      unsigned long arg);
+
 /* Register definitions, register access macros and drmAddMap constants
  * for Rage 128 kernel driver.
  */
diff --git a/drivers/char/drm/r128_ioc32.c b/drivers/char/drm/r128_ioc32.c
new file mode 100644
index 0000000..60598ef
--- /dev/null
+++ b/drivers/char/drm/r128_ioc32.c
@@ -0,0 +1,219 @@
+/**
+ * \file r128_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the R128 DRM.
+ *
+ * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Egbert Eich 2003,2004
+ * Copyright (C) Dave Airlie 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "r128_drm.h"
+
+typedef struct drm_r128_init32 {
+	int func;
+	unsigned int sarea_priv_offset;
+	int is_pci;
+	int cce_mode;
+	int cce_secure;
+	int ring_size;
+	int usec_timeout;
+
+	unsigned int fb_bpp;
+	unsigned int front_offset, front_pitch;
+	unsigned int back_offset, back_pitch;
+	unsigned int depth_bpp;
+	unsigned int depth_offset, depth_pitch;
+	unsigned int span_offset;
+
+	unsigned int fb_offset;
+	unsigned int mmio_offset;
+	unsigned int ring_offset;
+	unsigned int ring_rptr_offset;
+	unsigned int buffers_offset;
+	unsigned int agp_textures_offset;
+} drm_r128_init32_t;
+
+static int compat_r128_init(struct file *file, unsigned int cmd,
+			    unsigned long arg)
+{
+	drm_r128_init32_t init32;
+	drm_r128_init_t __user *init;
+	
+	if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+		return -EFAULT;
+	
+	init = compat_alloc_user_space(sizeof(*init));
+	if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+	    || __put_user(init32.func, &init->func)
+	    || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+	    || __put_user(init32.is_pci, &init->is_pci)
+	    || __put_user(init32.cce_mode, &init->cce_mode)
+	    || __put_user(init32.cce_secure, &init->cce_secure)
+	    || __put_user(init32.ring_size, &init->ring_size)
+	    || __put_user(init32.usec_timeout, &init->usec_timeout)
+	    || __put_user(init32.fb_bpp, &init->fb_bpp)
+	    || __put_user(init32.front_offset, &init->front_offset)
+	    || __put_user(init32.front_pitch, &init->front_pitch)
+	    || __put_user(init32.back_offset, &init->back_offset)
+	    || __put_user(init32.back_pitch, &init->back_pitch)
+	    || __put_user(init32.depth_bpp, &init->depth_bpp)
+	    || __put_user(init32.depth_offset, &init->depth_offset)
+	    || __put_user(init32.depth_pitch, &init->depth_pitch)
+	    || __put_user(init32.span_offset, &init->span_offset)
+	    || __put_user(init32.fb_offset, &init->fb_offset)
+	    || __put_user(init32.mmio_offset, &init->mmio_offset)
+	    || __put_user(init32.ring_offset, &init->ring_offset)
+	    || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
+	    || __put_user(init32.buffers_offset, &init->buffers_offset)
+	    || __put_user(init32.agp_textures_offset, &init->agp_textures_offset))
+		return -EFAULT;
+	
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_R128_INIT, (unsigned long)init);
+}
+
+
+typedef struct drm_r128_depth32 {
+	int func;
+	int n;
+	u32 x;
+	u32 y;
+	u32 buffer;
+	u32 mask;
+} drm_r128_depth32_t;
+
+static int compat_r128_depth(struct file *file, unsigned int cmd,
+			     unsigned long arg)
+{
+	drm_r128_depth32_t depth32;
+	drm_r128_depth_t __user *depth;
+
+	if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
+		return -EFAULT;
+
+	depth = compat_alloc_user_space(sizeof(*depth));
+	if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth))
+	    || __put_user(depth32.func, &depth->func)
+	    || __put_user(depth32.n, &depth->n)
+	    || __put_user((int __user *)(unsigned long)depth32.x, &depth->x)
+	    || __put_user((int __user *)(unsigned long)depth32.y, &depth->y)
+	    || __put_user((unsigned int __user *)(unsigned long)depth32.buffer, &depth->buffer)
+	    || __put_user((unsigned char __user *)(unsigned long)depth32.mask, &depth->mask))
+		return -EFAULT;
+	
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_R128_DEPTH, (unsigned long)depth);	
+	
+}
+
+typedef struct drm_r128_stipple32 {
+	u32 mask;
+} drm_r128_stipple32_t;
+
+static int compat_r128_stipple(struct file *file, unsigned int cmd,
+			       unsigned long arg)
+{
+	drm_r128_stipple32_t stipple32;
+	drm_r128_stipple_t __user *stipple;
+
+	if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
+		return -EFAULT;
+
+	stipple = compat_alloc_user_space(sizeof(*stipple));
+	if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple))
+	    || __put_user((unsigned int __user *)(unsigned long)stipple32.mask, &stipple->mask))
+		return -EFAULT;
+
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
+}
+
+typedef struct drm_r128_getparam32 {
+	int param;
+	u32 value;
+} drm_r128_getparam32_t;
+
+static int compat_r128_getparam(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	drm_r128_getparam32_t getparam32;
+	drm_r128_getparam_t __user *getparam;
+
+	if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
+		return -EFAULT;
+
+	getparam = compat_alloc_user_space(sizeof(*getparam));
+	if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
+	    || __put_user(getparam32.param, &getparam->param)
+	    || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value))
+		return -EFAULT;
+	
+	return drm_ioctl(file->f_dentry->d_inode, file,
+			 DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
+}
+
+drm_ioctl_compat_t *r128_compat_ioctls[] = {
+	[DRM_R128_INIT] = compat_r128_init,
+	[DRM_R128_DEPTH] = compat_r128_depth,
+	[DRM_R128_STIPPLE] = compat_r128_stipple,
+	[DRM_R128_GETPARAM] = compat_r128_getparam,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long r128_compat_ioctl(struct file *filp, unsigned int cmd,
+			 unsigned long arg)
+{
+	unsigned int nr = DRM_IOCTL_NR(cmd);
+	drm_ioctl_compat_t *fn = NULL;
+	int ret;
+
+	if (nr < DRM_COMMAND_BASE)
+		return drm_compat_ioctl(filp, cmd, arg);
+
+	if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls))
+		fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+	lock_kernel();		/* XXX for now */
+	if (fn != NULL)
+		ret = (*fn)(filp, cmd, arg);
+	else
+		ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index 53af691..426a71c 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -1307,7 +1307,7 @@
 	return 0;
 }
 
-int r128_do_cleanup_pageflip( drm_device_t *dev )
+static int r128_do_cleanup_pageflip( drm_device_t *dev )
 {
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	DRM_DEBUG( "\n" );
diff --git a/drivers/char/drm/via_3d_reg.h b/drivers/char/drm/via_3d_reg.h
new file mode 100644
index 0000000..cf61bb5
--- /dev/null
+++ b/drivers/char/drm/via_3d_reg.h
@@ -0,0 +1,1651 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef VIA_3D_REG_H
+#define VIA_3D_REG_H
+#define HC_REG_BASE             0x0400
+
+#define HC_REG_TRANS_SPACE      0x0040
+
+#define HC_ParaN_MASK           0xffffffff
+#define HC_Para_MASK            0x00ffffff
+#define HC_SubA_MASK            0xff000000
+#define HC_SubA_SHIFT           24
+/* Transmission Setting
+ */
+#define HC_REG_TRANS_SET        0x003c
+#define HC_ParaSubType_MASK     0xff000000
+#define HC_ParaType_MASK        0x00ff0000
+#define HC_ParaOS_MASK          0x0000ff00
+#define HC_ParaAdr_MASK         0x000000ff
+#define HC_ParaSubType_SHIFT    24
+#define HC_ParaType_SHIFT       16
+#define HC_ParaOS_SHIFT         8
+#define HC_ParaAdr_SHIFT        0
+
+#define HC_ParaType_CmdVdata    0x0000
+#define HC_ParaType_NotTex      0x0001
+#define HC_ParaType_Tex         0x0002
+#define HC_ParaType_Palette     0x0003
+#define HC_ParaType_PreCR       0x0010
+#define HC_ParaType_Auto        0x00fe
+
+/* Transmission Space
+ */
+#define HC_REG_Hpara0           0x0040
+#define HC_REG_HpataAF          0x02fc
+
+/* Read
+ */
+#define HC_REG_HREngSt          0x0000
+#define HC_REG_HRFIFOempty      0x0004
+#define HC_REG_HRFIFOfull       0x0008
+#define HC_REG_HRErr            0x000c
+#define HC_REG_FIFOstatus       0x0010
+/* HC_REG_HREngSt          0x0000
+ */
+#define HC_HDASZC_MASK          0x00010000
+#define HC_HSGEMI_MASK          0x0000f000
+#define HC_HLGEMISt_MASK        0x00000f00
+#define HC_HCRSt_MASK           0x00000080
+#define HC_HSE0St_MASK          0x00000040
+#define HC_HSE1St_MASK          0x00000020
+#define HC_HPESt_MASK           0x00000010
+#define HC_HXESt_MASK           0x00000008
+#define HC_HBESt_MASK           0x00000004
+#define HC_HE2St_MASK           0x00000002
+#define HC_HE3St_MASK           0x00000001
+/* HC_REG_HRFIFOempty      0x0004
+ */
+#define HC_HRZDempty_MASK       0x00000010
+#define HC_HRTXAempty_MASK      0x00000008
+#define HC_HRTXDempty_MASK      0x00000004
+#define HC_HWZDempty_MASK       0x00000002
+#define HC_HWCDempty_MASK       0x00000001
+/* HC_REG_HRFIFOfull       0x0008
+ */
+#define HC_HRZDfull_MASK        0x00000010
+#define HC_HRTXAfull_MASK       0x00000008
+#define HC_HRTXDfull_MASK       0x00000004
+#define HC_HWZDfull_MASK        0x00000002
+#define HC_HWCDfull_MASK        0x00000001
+/* HC_REG_HRErr            0x000c
+ */
+#define HC_HAGPCMErr_MASK       0x80000000
+#define HC_HAGPCMErrC_MASK      0x70000000
+/* HC_REG_FIFOstatus       0x0010
+ */
+#define HC_HRFIFOATall_MASK     0x80000000
+#define HC_HRFIFOATbusy_MASK    0x40000000
+#define HC_HRATFGMDo_MASK       0x00000100
+#define HC_HRATFGMDi_MASK       0x00000080
+#define HC_HRATFRZD_MASK        0x00000040
+#define HC_HRATFRTXA_MASK       0x00000020
+#define HC_HRATFRTXD_MASK       0x00000010
+#define HC_HRATFWZD_MASK        0x00000008
+#define HC_HRATFWCD_MASK        0x00000004
+#define HC_HRATTXTAG_MASK       0x00000002
+#define HC_HRATTXCH_MASK        0x00000001
+
+/* AGP Command Setting
+ */
+#define HC_SubA_HAGPBstL        0x0060
+#define HC_SubA_HAGPBendL       0x0061
+#define HC_SubA_HAGPCMNT        0x0062
+#define HC_SubA_HAGPBpL         0x0063
+#define HC_SubA_HAGPBpH         0x0064
+/* HC_SubA_HAGPCMNT        0x0062
+ */
+#define HC_HAGPCMNT_MASK        0x00800000
+#define HC_HCmdErrClr_MASK      0x00400000
+#define HC_HAGPBendH_MASK       0x0000ff00
+#define HC_HAGPBstH_MASK        0x000000ff
+#define HC_HAGPBendH_SHIFT      8
+#define HC_HAGPBstH_SHIFT       0
+/* HC_SubA_HAGPBpL         0x0063
+ */
+#define HC_HAGPBpL_MASK         0x00fffffc
+#define HC_HAGPBpID_MASK        0x00000003
+#define HC_HAGPBpID_PAUSE       0x00000000
+#define HC_HAGPBpID_JUMP        0x00000001
+#define HC_HAGPBpID_STOP        0x00000002
+/* HC_SubA_HAGPBpH         0x0064
+ */
+#define HC_HAGPBpH_MASK         0x00ffffff
+
+/* Miscellaneous Settings
+ */
+#define HC_SubA_HClipTB         0x0070
+#define HC_SubA_HClipLR         0x0071
+#define HC_SubA_HFPClipTL       0x0072
+#define HC_SubA_HFPClipBL       0x0073
+#define HC_SubA_HFPClipLL       0x0074
+#define HC_SubA_HFPClipRL       0x0075
+#define HC_SubA_HFPClipTBH      0x0076
+#define HC_SubA_HFPClipLRH      0x0077
+#define HC_SubA_HLP             0x0078
+#define HC_SubA_HLPRF           0x0079
+#define HC_SubA_HSolidCL        0x007a
+#define HC_SubA_HPixGC          0x007b
+#define HC_SubA_HSPXYOS         0x007c
+#define HC_SubA_HVertexCNT      0x007d
+
+#define HC_HClipT_MASK          0x00fff000
+#define HC_HClipT_SHIFT         12
+#define HC_HClipB_MASK          0x00000fff
+#define HC_HClipB_SHIFT         0
+#define HC_HClipL_MASK          0x00fff000
+#define HC_HClipL_SHIFT         12
+#define HC_HClipR_MASK          0x00000fff
+#define HC_HClipR_SHIFT         0
+#define HC_HFPClipBH_MASK       0x0000ff00
+#define HC_HFPClipBH_SHIFT      8
+#define HC_HFPClipTH_MASK       0x000000ff
+#define HC_HFPClipTH_SHIFT      0
+#define HC_HFPClipRH_MASK       0x0000ff00
+#define HC_HFPClipRH_SHIFT      8
+#define HC_HFPClipLH_MASK       0x000000ff
+#define HC_HFPClipLH_SHIFT      0
+#define HC_HSolidCH_MASK        0x000000ff
+#define HC_HPixGC_MASK          0x00800000
+#define HC_HSPXOS_MASK          0x00fff000
+#define HC_HSPXOS_SHIFT         12
+#define HC_HSPYOS_MASK          0x00000fff
+
+/* Command
+ * Command A
+ */
+#define HC_HCmdHeader_MASK      0xfe000000	/*0xffe00000 */
+#define HC_HE3Fire_MASK         0x00100000
+#define HC_HPMType_MASK         0x000f0000
+#define HC_HEFlag_MASK          0x0000e000
+#define HC_HShading_MASK        0x00001c00
+#define HC_HPMValidN_MASK       0x00000200
+#define HC_HPLEND_MASK          0x00000100
+#define HC_HVCycle_MASK         0x000000ff
+#define HC_HVCycle_Style_MASK   0x000000c0
+#define HC_HVCycle_ChgA_MASK    0x00000030
+#define HC_HVCycle_ChgB_MASK    0x0000000c
+#define HC_HVCycle_ChgC_MASK    0x00000003
+#define HC_HPMType_Point        0x00000000
+#define HC_HPMType_Line         0x00010000
+#define HC_HPMType_Tri          0x00020000
+#define HC_HPMType_TriWF        0x00040000
+#define HC_HEFlag_NoAA          0x00000000
+#define HC_HEFlag_ab            0x00008000
+#define HC_HEFlag_bc            0x00004000
+#define HC_HEFlag_ca            0x00002000
+#define HC_HShading_Solid       0x00000000
+#define HC_HShading_FlatA       0x00000400
+#define HC_HShading_FlatB       0x00000800
+#define HC_HShading_FlatC       0x00000c00
+#define HC_HShading_Gouraud     0x00001000
+#define HC_HVCycle_Full         0x00000000
+#define HC_HVCycle_AFP          0x00000040
+#define HC_HVCycle_One          0x000000c0
+#define HC_HVCycle_NewA         0x00000000
+#define HC_HVCycle_AA           0x00000010
+#define HC_HVCycle_AB           0x00000020
+#define HC_HVCycle_AC           0x00000030
+#define HC_HVCycle_NewB         0x00000000
+#define HC_HVCycle_BA           0x00000004
+#define HC_HVCycle_BB           0x00000008
+#define HC_HVCycle_BC           0x0000000c
+#define HC_HVCycle_NewC         0x00000000
+#define HC_HVCycle_CA           0x00000001
+#define HC_HVCycle_CB           0x00000002
+#define HC_HVCycle_CC           0x00000003
+
+/* Command B
+ */
+#define HC_HLPrst_MASK          0x00010000
+#define HC_HLLastP_MASK         0x00008000
+#define HC_HVPMSK_MASK          0x00007f80
+#define HC_HBFace_MASK          0x00000040
+#define HC_H2nd1VT_MASK         0x0000003f
+#define HC_HVPMSK_X             0x00004000
+#define HC_HVPMSK_Y             0x00002000
+#define HC_HVPMSK_Z             0x00001000
+#define HC_HVPMSK_W             0x00000800
+#define HC_HVPMSK_Cd            0x00000400
+#define HC_HVPMSK_Cs            0x00000200
+#define HC_HVPMSK_S             0x00000100
+#define HC_HVPMSK_T             0x00000080
+
+/* Enable Setting
+ */
+#define HC_SubA_HEnable         0x0000
+#define HC_HenTXEnvMap_MASK     0x00200000
+#define HC_HenVertexCNT_MASK    0x00100000
+#define HC_HenCPUDAZ_MASK       0x00080000
+#define HC_HenDASZWC_MASK       0x00040000
+#define HC_HenFBCull_MASK       0x00020000
+#define HC_HenCW_MASK           0x00010000
+#define HC_HenAA_MASK           0x00008000
+#define HC_HenST_MASK           0x00004000
+#define HC_HenZT_MASK           0x00002000
+#define HC_HenZW_MASK           0x00001000
+#define HC_HenAT_MASK           0x00000800
+#define HC_HenAW_MASK           0x00000400
+#define HC_HenSP_MASK           0x00000200
+#define HC_HenLP_MASK           0x00000100
+#define HC_HenTXCH_MASK         0x00000080
+#define HC_HenTXMP_MASK         0x00000040
+#define HC_HenTXPP_MASK         0x00000020
+#define HC_HenTXTR_MASK         0x00000010
+#define HC_HenCS_MASK           0x00000008
+#define HC_HenFOG_MASK          0x00000004
+#define HC_HenABL_MASK          0x00000002
+#define HC_HenDT_MASK           0x00000001
+
+/* Z Setting
+ */
+#define HC_SubA_HZWBBasL        0x0010
+#define HC_SubA_HZWBBasH        0x0011
+#define HC_SubA_HZWBType        0x0012
+#define HC_SubA_HZBiasL         0x0013
+#define HC_SubA_HZWBend         0x0014
+#define HC_SubA_HZWTMD          0x0015
+#define HC_SubA_HZWCDL          0x0016
+#define HC_SubA_HZWCTAGnum      0x0017
+#define HC_SubA_HZCYNum         0x0018
+#define HC_SubA_HZWCFire        0x0019
+/* HC_SubA_HZWBType
+ */
+#define HC_HZWBType_MASK        0x00800000
+#define HC_HZBiasedWB_MASK      0x00400000
+#define HC_HZONEasFF_MASK       0x00200000
+#define HC_HZOONEasFF_MASK      0x00100000
+#define HC_HZWBFM_MASK          0x00030000
+#define HC_HZWBLoc_MASK         0x0000c000
+#define HC_HZWBPit_MASK         0x00003fff
+#define HC_HZWBFM_16            0x00000000
+#define HC_HZWBFM_32            0x00020000
+#define HC_HZWBFM_24            0x00030000
+#define HC_HZWBLoc_Local        0x00000000
+#define HC_HZWBLoc_SyS          0x00004000
+/* HC_SubA_HZWBend
+ */
+#define HC_HZWBend_MASK         0x00ffe000
+#define HC_HZBiasH_MASK         0x000000ff
+#define HC_HZWBend_SHIFT        10
+/* HC_SubA_HZWTMD
+ */
+#define HC_HZWTMD_MASK          0x00070000
+#define HC_HEBEBias_MASK        0x00007f00
+#define HC_HZNF_MASK            0x000000ff
+#define HC_HZWTMD_NeverPass     0x00000000
+#define HC_HZWTMD_LT            0x00010000
+#define HC_HZWTMD_EQ            0x00020000
+#define HC_HZWTMD_LE            0x00030000
+#define HC_HZWTMD_GT            0x00040000
+#define HC_HZWTMD_NE            0x00050000
+#define HC_HZWTMD_GE            0x00060000
+#define HC_HZWTMD_AllPass       0x00070000
+#define HC_HEBEBias_SHIFT       8
+/* HC_SubA_HZWCDL          0x0016
+ */
+#define HC_HZWCDL_MASK          0x00ffffff
+/* HC_SubA_HZWCTAGnum      0x0017
+ */
+#define HC_HZWCTAGnum_MASK      0x00ff0000
+#define HC_HZWCTAGnum_SHIFT     16
+#define HC_HZWCDH_MASK          0x000000ff
+#define HC_HZWCDH_SHIFT         0
+/* HC_SubA_HZCYNum         0x0018
+ */
+#define HC_HZCYNum_MASK         0x00030000
+#define HC_HZCYNum_SHIFT        16
+#define HC_HZWCQWnum_MASK       0x00003fff
+#define HC_HZWCQWnum_SHIFT      0
+/* HC_SubA_HZWCFire        0x0019
+ */
+#define HC_ZWCFire_MASK         0x00010000
+#define HC_HZWCQWnumLast_MASK   0x00003fff
+#define HC_HZWCQWnumLast_SHIFT  0
+
+/* Stencil Setting
+ */
+#define HC_SubA_HSTREF          0x0023
+#define HC_SubA_HSTMD           0x0024
+/* HC_SubA_HSBFM
+ */
+#define HC_HSBFM_MASK           0x00030000
+#define HC_HSBLoc_MASK          0x0000c000
+#define HC_HSBPit_MASK          0x00003fff
+/* HC_SubA_HSTREF
+ */
+#define HC_HSTREF_MASK          0x00ff0000
+#define HC_HSTOPMSK_MASK        0x0000ff00
+#define HC_HSTBMSK_MASK         0x000000ff
+#define HC_HSTREF_SHIFT         16
+#define HC_HSTOPMSK_SHIFT       8
+/* HC_SubA_HSTMD
+ */
+#define HC_HSTMD_MASK           0x00070000
+#define HC_HSTOPSF_MASK         0x000001c0
+#define HC_HSTOPSPZF_MASK       0x00000038
+#define HC_HSTOPSPZP_MASK       0x00000007
+#define HC_HSTMD_NeverPass      0x00000000
+#define HC_HSTMD_LT             0x00010000
+#define HC_HSTMD_EQ             0x00020000
+#define HC_HSTMD_LE             0x00030000
+#define HC_HSTMD_GT             0x00040000
+#define HC_HSTMD_NE             0x00050000
+#define HC_HSTMD_GE             0x00060000
+#define HC_HSTMD_AllPass        0x00070000
+#define HC_HSTOPSF_KEEP         0x00000000
+#define HC_HSTOPSF_ZERO         0x00000040
+#define HC_HSTOPSF_REPLACE      0x00000080
+#define HC_HSTOPSF_INCRSAT      0x000000c0
+#define HC_HSTOPSF_DECRSAT      0x00000100
+#define HC_HSTOPSF_INVERT       0x00000140
+#define HC_HSTOPSF_INCR         0x00000180
+#define HC_HSTOPSF_DECR         0x000001c0
+#define HC_HSTOPSPZF_KEEP       0x00000000
+#define HC_HSTOPSPZF_ZERO       0x00000008
+#define HC_HSTOPSPZF_REPLACE    0x00000010
+#define HC_HSTOPSPZF_INCRSAT    0x00000018
+#define HC_HSTOPSPZF_DECRSAT    0x00000020
+#define HC_HSTOPSPZF_INVERT     0x00000028
+#define HC_HSTOPSPZF_INCR       0x00000030
+#define HC_HSTOPSPZF_DECR       0x00000038
+#define HC_HSTOPSPZP_KEEP       0x00000000
+#define HC_HSTOPSPZP_ZERO       0x00000001
+#define HC_HSTOPSPZP_REPLACE    0x00000002
+#define HC_HSTOPSPZP_INCRSAT    0x00000003
+#define HC_HSTOPSPZP_DECRSAT    0x00000004
+#define HC_HSTOPSPZP_INVERT     0x00000005
+#define HC_HSTOPSPZP_INCR       0x00000006
+#define HC_HSTOPSPZP_DECR       0x00000007
+
+/* Alpha Setting
+ */
+#define HC_SubA_HABBasL         0x0030
+#define HC_SubA_HABBasH         0x0031
+#define HC_SubA_HABFM           0x0032
+#define HC_SubA_HATMD           0x0033
+#define HC_SubA_HABLCsat        0x0034
+#define HC_SubA_HABLCop         0x0035
+#define HC_SubA_HABLAsat        0x0036
+#define HC_SubA_HABLAop         0x0037
+#define HC_SubA_HABLRCa         0x0038
+#define HC_SubA_HABLRFCa        0x0039
+#define HC_SubA_HABLRCbias      0x003a
+#define HC_SubA_HABLRCb         0x003b
+#define HC_SubA_HABLRFCb        0x003c
+#define HC_SubA_HABLRAa         0x003d
+#define HC_SubA_HABLRAb         0x003e
+/* HC_SubA_HABFM
+ */
+#define HC_HABFM_MASK           0x00030000
+#define HC_HABLoc_MASK          0x0000c000
+#define HC_HABPit_MASK          0x000007ff
+/* HC_SubA_HATMD
+ */
+#define HC_HATMD_MASK           0x00000700
+#define HC_HATREF_MASK          0x000000ff
+#define HC_HATMD_NeverPass      0x00000000
+#define HC_HATMD_LT             0x00000100
+#define HC_HATMD_EQ             0x00000200
+#define HC_HATMD_LE             0x00000300
+#define HC_HATMD_GT             0x00000400
+#define HC_HATMD_NE             0x00000500
+#define HC_HATMD_GE             0x00000600
+#define HC_HATMD_AllPass        0x00000700
+/* HC_SubA_HABLCsat
+ */
+#define HC_HABLCsat_MASK        0x00010000
+#define HC_HABLCa_MASK          0x0000fc00
+#define HC_HABLCa_C_MASK        0x0000c000
+#define HC_HABLCa_OPC_MASK      0x00003c00
+#define HC_HABLFCa_MASK         0x000003f0
+#define HC_HABLFCa_C_MASK       0x00000300
+#define HC_HABLFCa_OPC_MASK     0x000000f0
+#define HC_HABLCbias_MASK       0x0000000f
+#define HC_HABLCbias_C_MASK     0x00000008
+#define HC_HABLCbias_OPC_MASK   0x00000007
+/*-- Define the input color.
+ */
+#define HC_XC_Csrc              0x00000000
+#define HC_XC_Cdst              0x00000001
+#define HC_XC_Asrc              0x00000002
+#define HC_XC_Adst              0x00000003
+#define HC_XC_Fog               0x00000004
+#define HC_XC_HABLRC            0x00000005
+#define HC_XC_minSrcDst         0x00000006
+#define HC_XC_maxSrcDst         0x00000007
+#define HC_XC_mimAsrcInvAdst    0x00000008
+#define HC_XC_OPC               0x00000000
+#define HC_XC_InvOPC            0x00000010
+#define HC_XC_OPCp5             0x00000020
+/*-- Define the input Alpha
+ */
+#define HC_XA_OPA               0x00000000
+#define HC_XA_InvOPA            0x00000010
+#define HC_XA_OPAp5             0x00000020
+#define HC_XA_0                 0x00000000
+#define HC_XA_Asrc              0x00000001
+#define HC_XA_Adst              0x00000002
+#define HC_XA_Fog               0x00000003
+#define HC_XA_minAsrcFog        0x00000004
+#define HC_XA_minAsrcAdst       0x00000005
+#define HC_XA_maxAsrcFog        0x00000006
+#define HC_XA_maxAsrcAdst       0x00000007
+#define HC_XA_HABLRA            0x00000008
+#define HC_XA_minAsrcInvAdst    0x00000008
+#define HC_XA_HABLFRA           0x00000009
+/*--
+ */
+#define HC_HABLCa_OPC           (HC_XC_OPC << 10)
+#define HC_HABLCa_InvOPC        (HC_XC_InvOPC << 10)
+#define HC_HABLCa_OPCp5         (HC_XC_OPCp5 << 10)
+#define HC_HABLCa_Csrc          (HC_XC_Csrc << 10)
+#define HC_HABLCa_Cdst          (HC_XC_Cdst << 10)
+#define HC_HABLCa_Asrc          (HC_XC_Asrc << 10)
+#define HC_HABLCa_Adst          (HC_XC_Adst << 10)
+#define HC_HABLCa_Fog           (HC_XC_Fog << 10)
+#define HC_HABLCa_HABLRCa       (HC_XC_HABLRC << 10)
+#define HC_HABLCa_minSrcDst     (HC_XC_minSrcDst << 10)
+#define HC_HABLCa_maxSrcDst     (HC_XC_maxSrcDst << 10)
+#define HC_HABLFCa_OPC              (HC_XC_OPC << 4)
+#define HC_HABLFCa_InvOPC           (HC_XC_InvOPC << 4)
+#define HC_HABLFCa_OPCp5            (HC_XC_OPCp5 << 4)
+#define HC_HABLFCa_Csrc             (HC_XC_Csrc << 4)
+#define HC_HABLFCa_Cdst             (HC_XC_Cdst << 4)
+#define HC_HABLFCa_Asrc             (HC_XC_Asrc << 4)
+#define HC_HABLFCa_Adst             (HC_XC_Adst << 4)
+#define HC_HABLFCa_Fog              (HC_XC_Fog << 4)
+#define HC_HABLFCa_HABLRCa          (HC_XC_HABLRC << 4)
+#define HC_HABLFCa_minSrcDst        (HC_XC_minSrcDst << 4)
+#define HC_HABLFCa_maxSrcDst        (HC_XC_maxSrcDst << 4)
+#define HC_HABLFCa_mimAsrcInvAdst   (HC_XC_mimAsrcInvAdst << 4)
+#define HC_HABLCbias_HABLRCbias 0x00000000
+#define HC_HABLCbias_Asrc       0x00000001
+#define HC_HABLCbias_Adst       0x00000002
+#define HC_HABLCbias_Fog        0x00000003
+#define HC_HABLCbias_Cin        0x00000004
+/* HC_SubA_HABLCop         0x0035
+ */
+#define HC_HABLdot_MASK         0x00010000
+#define HC_HABLCop_MASK         0x00004000
+#define HC_HABLCb_MASK          0x00003f00
+#define HC_HABLCb_C_MASK        0x00003000
+#define HC_HABLCb_OPC_MASK      0x00000f00
+#define HC_HABLFCb_MASK         0x000000fc
+#define HC_HABLFCb_C_MASK       0x000000c0
+#define HC_HABLFCb_OPC_MASK     0x0000003c
+#define HC_HABLCshift_MASK      0x00000003
+#define HC_HABLCb_OPC           (HC_XC_OPC << 8)
+#define HC_HABLCb_InvOPC        (HC_XC_InvOPC << 8)
+#define HC_HABLCb_OPCp5         (HC_XC_OPCp5 << 8)
+#define HC_HABLCb_Csrc          (HC_XC_Csrc << 8)
+#define HC_HABLCb_Cdst          (HC_XC_Cdst << 8)
+#define HC_HABLCb_Asrc          (HC_XC_Asrc << 8)
+#define HC_HABLCb_Adst          (HC_XC_Adst << 8)
+#define HC_HABLCb_Fog           (HC_XC_Fog << 8)
+#define HC_HABLCb_HABLRCa       (HC_XC_HABLRC << 8)
+#define HC_HABLCb_minSrcDst     (HC_XC_minSrcDst << 8)
+#define HC_HABLCb_maxSrcDst     (HC_XC_maxSrcDst << 8)
+#define HC_HABLFCb_OPC              (HC_XC_OPC << 2)
+#define HC_HABLFCb_InvOPC           (HC_XC_InvOPC << 2)
+#define HC_HABLFCb_OPCp5            (HC_XC_OPCp5 << 2)
+#define HC_HABLFCb_Csrc             (HC_XC_Csrc << 2)
+#define HC_HABLFCb_Cdst             (HC_XC_Cdst << 2)
+#define HC_HABLFCb_Asrc             (HC_XC_Asrc << 2)
+#define HC_HABLFCb_Adst             (HC_XC_Adst << 2)
+#define HC_HABLFCb_Fog              (HC_XC_Fog << 2)
+#define HC_HABLFCb_HABLRCb          (HC_XC_HABLRC << 2)
+#define HC_HABLFCb_minSrcDst        (HC_XC_minSrcDst << 2)
+#define HC_HABLFCb_maxSrcDst        (HC_XC_maxSrcDst << 2)
+#define HC_HABLFCb_mimAsrcInvAdst   (HC_XC_mimAsrcInvAdst << 2)
+/* HC_SubA_HABLAsat        0x0036
+ */
+#define HC_HABLAsat_MASK        0x00010000
+#define HC_HABLAa_MASK          0x0000fc00
+#define HC_HABLAa_A_MASK        0x0000c000
+#define HC_HABLAa_OPA_MASK      0x00003c00
+#define HC_HABLFAa_MASK         0x000003f0
+#define HC_HABLFAa_A_MASK       0x00000300
+#define HC_HABLFAa_OPA_MASK     0x000000f0
+#define HC_HABLAbias_MASK       0x0000000f
+#define HC_HABLAbias_A_MASK     0x00000008
+#define HC_HABLAbias_OPA_MASK   0x00000007
+#define HC_HABLAa_OPA           (HC_XA_OPA << 10)
+#define HC_HABLAa_InvOPA        (HC_XA_InvOPA << 10)
+#define HC_HABLAa_OPAp5         (HC_XA_OPAp5 << 10)
+#define HC_HABLAa_0             (HC_XA_0 << 10)
+#define HC_HABLAa_Asrc          (HC_XA_Asrc << 10)
+#define HC_HABLAa_Adst          (HC_XA_Adst << 10)
+#define HC_HABLAa_Fog           (HC_XA_Fog << 10)
+#define HC_HABLAa_minAsrcFog    (HC_XA_minAsrcFog << 10)
+#define HC_HABLAa_minAsrcAdst   (HC_XA_minAsrcAdst << 10)
+#define HC_HABLAa_maxAsrcFog    (HC_XA_maxAsrcFog << 10)
+#define HC_HABLAa_maxAsrcAdst   (HC_XA_maxAsrcAdst << 10)
+#define HC_HABLAa_HABLRA        (HC_XA_HABLRA << 10)
+#define HC_HABLFAa_OPA          (HC_XA_OPA << 4)
+#define HC_HABLFAa_InvOPA       (HC_XA_InvOPA << 4)
+#define HC_HABLFAa_OPAp5        (HC_XA_OPAp5 << 4)
+#define HC_HABLFAa_0            (HC_XA_0 << 4)
+#define HC_HABLFAa_Asrc         (HC_XA_Asrc << 4)
+#define HC_HABLFAa_Adst         (HC_XA_Adst << 4)
+#define HC_HABLFAa_Fog          (HC_XA_Fog << 4)
+#define HC_HABLFAa_minAsrcFog   (HC_XA_minAsrcFog << 4)
+#define HC_HABLFAa_minAsrcAdst  (HC_XA_minAsrcAdst << 4)
+#define HC_HABLFAa_maxAsrcFog   (HC_XA_maxAsrcFog << 4)
+#define HC_HABLFAa_maxAsrcAdst  (HC_XA_maxAsrcAdst << 4)
+#define HC_HABLFAa_minAsrcInvAdst   (HC_XA_minAsrcInvAdst << 4)
+#define HC_HABLFAa_HABLFRA          (HC_XA_HABLFRA << 4)
+#define HC_HABLAbias_HABLRAbias 0x00000000
+#define HC_HABLAbias_Asrc       0x00000001
+#define HC_HABLAbias_Adst       0x00000002
+#define HC_HABLAbias_Fog        0x00000003
+#define HC_HABLAbias_Aaa        0x00000004
+/* HC_SubA_HABLAop         0x0037
+ */
+#define HC_HABLAop_MASK         0x00004000
+#define HC_HABLAb_MASK          0x00003f00
+#define HC_HABLAb_OPA_MASK      0x00000f00
+#define HC_HABLFAb_MASK         0x000000fc
+#define HC_HABLFAb_OPA_MASK     0x0000003c
+#define HC_HABLAshift_MASK      0x00000003
+#define HC_HABLAb_OPA           (HC_XA_OPA << 8)
+#define HC_HABLAb_InvOPA        (HC_XA_InvOPA << 8)
+#define HC_HABLAb_OPAp5         (HC_XA_OPAp5 << 8)
+#define HC_HABLAb_0             (HC_XA_0 << 8)
+#define HC_HABLAb_Asrc          (HC_XA_Asrc << 8)
+#define HC_HABLAb_Adst          (HC_XA_Adst << 8)
+#define HC_HABLAb_Fog           (HC_XA_Fog << 8)
+#define HC_HABLAb_minAsrcFog    (HC_XA_minAsrcFog << 8)
+#define HC_HABLAb_minAsrcAdst   (HC_XA_minAsrcAdst << 8)
+#define HC_HABLAb_maxAsrcFog    (HC_XA_maxAsrcFog << 8)
+#define HC_HABLAb_maxAsrcAdst   (HC_XA_maxAsrcAdst << 8)
+#define HC_HABLAb_HABLRA        (HC_XA_HABLRA << 8)
+#define HC_HABLFAb_OPA          (HC_XA_OPA << 2)
+#define HC_HABLFAb_InvOPA       (HC_XA_InvOPA << 2)
+#define HC_HABLFAb_OPAp5        (HC_XA_OPAp5 << 2)
+#define HC_HABLFAb_0            (HC_XA_0 << 2)
+#define HC_HABLFAb_Asrc         (HC_XA_Asrc << 2)
+#define HC_HABLFAb_Adst         (HC_XA_Adst << 2)
+#define HC_HABLFAb_Fog          (HC_XA_Fog << 2)
+#define HC_HABLFAb_minAsrcFog   (HC_XA_minAsrcFog << 2)
+#define HC_HABLFAb_minAsrcAdst  (HC_XA_minAsrcAdst << 2)
+#define HC_HABLFAb_maxAsrcFog   (HC_XA_maxAsrcFog << 2)
+#define HC_HABLFAb_maxAsrcAdst  (HC_XA_maxAsrcAdst << 2)
+#define HC_HABLFAb_minAsrcInvAdst   (HC_XA_minAsrcInvAdst << 2)
+#define HC_HABLFAb_HABLFRA          (HC_XA_HABLFRA << 2)
+/* HC_SubA_HABLRAa         0x003d
+ */
+#define HC_HABLRAa_MASK         0x00ff0000
+#define HC_HABLRFAa_MASK        0x0000ff00
+#define HC_HABLRAbias_MASK      0x000000ff
+#define HC_HABLRAa_SHIFT        16
+#define HC_HABLRFAa_SHIFT       8
+/* HC_SubA_HABLRAb         0x003e
+ */
+#define HC_HABLRAb_MASK         0x0000ff00
+#define HC_HABLRFAb_MASK        0x000000ff
+#define HC_HABLRAb_SHIFT        8
+
+/* Destination Setting
+ */
+#define HC_SubA_HDBBasL         0x0040
+#define HC_SubA_HDBBasH         0x0041
+#define HC_SubA_HDBFM           0x0042
+#define HC_SubA_HFBBMSKL        0x0043
+#define HC_SubA_HROP            0x0044
+/* HC_SubA_HDBFM           0x0042
+ */
+#define HC_HDBFM_MASK           0x001f0000
+#define HC_HDBLoc_MASK          0x0000c000
+#define HC_HDBPit_MASK          0x00003fff
+#define HC_HDBFM_RGB555         0x00000000
+#define HC_HDBFM_RGB565         0x00010000
+#define HC_HDBFM_ARGB4444       0x00020000
+#define HC_HDBFM_ARGB1555       0x00030000
+#define HC_HDBFM_BGR555         0x00040000
+#define HC_HDBFM_BGR565         0x00050000
+#define HC_HDBFM_ABGR4444       0x00060000
+#define HC_HDBFM_ABGR1555       0x00070000
+#define HC_HDBFM_ARGB0888       0x00080000
+#define HC_HDBFM_ARGB8888       0x00090000
+#define HC_HDBFM_ABGR0888       0x000a0000
+#define HC_HDBFM_ABGR8888       0x000b0000
+#define HC_HDBLoc_Local         0x00000000
+#define HC_HDBLoc_Sys           0x00004000
+/* HC_SubA_HROP            0x0044
+ */
+#define HC_HROP_MASK            0x00000f00
+#define HC_HFBBMSKH_MASK        0x000000ff
+#define HC_HROP_BLACK           0x00000000
+#define HC_HROP_DPon            0x00000100
+#define HC_HROP_DPna            0x00000200
+#define HC_HROP_Pn              0x00000300
+#define HC_HROP_PDna            0x00000400
+#define HC_HROP_Dn              0x00000500
+#define HC_HROP_DPx             0x00000600
+#define HC_HROP_DPan            0x00000700
+#define HC_HROP_DPa             0x00000800
+#define HC_HROP_DPxn            0x00000900
+#define HC_HROP_D               0x00000a00
+#define HC_HROP_DPno            0x00000b00
+#define HC_HROP_P               0x00000c00
+#define HC_HROP_PDno            0x00000d00
+#define HC_HROP_DPo             0x00000e00
+#define HC_HROP_WHITE           0x00000f00
+
+/* Fog Setting
+ */
+#define HC_SubA_HFogLF          0x0050
+#define HC_SubA_HFogCL          0x0051
+#define HC_SubA_HFogCH          0x0052
+#define HC_SubA_HFogStL         0x0053
+#define HC_SubA_HFogStH         0x0054
+#define HC_SubA_HFogOOdMF       0x0055
+#define HC_SubA_HFogOOdEF       0x0056
+#define HC_SubA_HFogEndL        0x0057
+#define HC_SubA_HFogDenst       0x0058
+/* HC_SubA_FogLF           0x0050
+ */
+#define HC_FogLF_MASK           0x00000010
+#define HC_FogEq_MASK           0x00000008
+#define HC_FogMD_MASK           0x00000007
+#define HC_FogMD_LocalFog        0x00000000
+#define HC_FogMD_LinearFog       0x00000002
+#define HC_FogMD_ExponentialFog  0x00000004
+#define HC_FogMD_Exponential2Fog 0x00000005
+/* #define HC_FogMD_FogTable       0x00000003 */
+
+/* HC_SubA_HFogDenst        0x0058
+ */
+#define HC_FogDenst_MASK        0x001fff00
+#define HC_FogEndL_MASK         0x000000ff
+
+/* Texture subtype definitions
+ */
+#define HC_SubType_Tex0         0x00000000
+#define HC_SubType_Tex1         0x00000001
+#define HC_SubType_TexGeneral   0x000000fe
+
+/* Attribute of texture n
+ */
+#define HC_SubA_HTXnL0BasL      0x0000
+#define HC_SubA_HTXnL1BasL      0x0001
+#define HC_SubA_HTXnL2BasL      0x0002
+#define HC_SubA_HTXnL3BasL      0x0003
+#define HC_SubA_HTXnL4BasL      0x0004
+#define HC_SubA_HTXnL5BasL      0x0005
+#define HC_SubA_HTXnL6BasL      0x0006
+#define HC_SubA_HTXnL7BasL      0x0007
+#define HC_SubA_HTXnL8BasL      0x0008
+#define HC_SubA_HTXnL9BasL      0x0009
+#define HC_SubA_HTXnLaBasL      0x000a
+#define HC_SubA_HTXnLbBasL      0x000b
+#define HC_SubA_HTXnLcBasL      0x000c
+#define HC_SubA_HTXnLdBasL      0x000d
+#define HC_SubA_HTXnLeBasL      0x000e
+#define HC_SubA_HTXnLfBasL      0x000f
+#define HC_SubA_HTXnL10BasL     0x0010
+#define HC_SubA_HTXnL11BasL     0x0011
+#define HC_SubA_HTXnL012BasH    0x0020
+#define HC_SubA_HTXnL345BasH    0x0021
+#define HC_SubA_HTXnL678BasH    0x0022
+#define HC_SubA_HTXnL9abBasH    0x0023
+#define HC_SubA_HTXnLcdeBasH    0x0024
+#define HC_SubA_HTXnLf1011BasH  0x0025
+#define HC_SubA_HTXnL0Pit       0x002b
+#define HC_SubA_HTXnL1Pit       0x002c
+#define HC_SubA_HTXnL2Pit       0x002d
+#define HC_SubA_HTXnL3Pit       0x002e
+#define HC_SubA_HTXnL4Pit       0x002f
+#define HC_SubA_HTXnL5Pit       0x0030
+#define HC_SubA_HTXnL6Pit       0x0031
+#define HC_SubA_HTXnL7Pit       0x0032
+#define HC_SubA_HTXnL8Pit       0x0033
+#define HC_SubA_HTXnL9Pit       0x0034
+#define HC_SubA_HTXnLaPit       0x0035
+#define HC_SubA_HTXnLbPit       0x0036
+#define HC_SubA_HTXnLcPit       0x0037
+#define HC_SubA_HTXnLdPit       0x0038
+#define HC_SubA_HTXnLePit       0x0039
+#define HC_SubA_HTXnLfPit       0x003a
+#define HC_SubA_HTXnL10Pit      0x003b
+#define HC_SubA_HTXnL11Pit      0x003c
+#define HC_SubA_HTXnL0_5WE      0x004b
+#define HC_SubA_HTXnL6_bWE      0x004c
+#define HC_SubA_HTXnLc_11WE     0x004d
+#define HC_SubA_HTXnL0_5HE      0x0051
+#define HC_SubA_HTXnL6_bHE      0x0052
+#define HC_SubA_HTXnLc_11HE     0x0053
+#define HC_SubA_HTXnL0OS        0x0077
+#define HC_SubA_HTXnTB          0x0078
+#define HC_SubA_HTXnMPMD        0x0079
+#define HC_SubA_HTXnCLODu       0x007a
+#define HC_SubA_HTXnFM          0x007b
+#define HC_SubA_HTXnTRCH        0x007c
+#define HC_SubA_HTXnTRCL        0x007d
+#define HC_SubA_HTXnTBC         0x007e
+#define HC_SubA_HTXnTRAH        0x007f
+#define HC_SubA_HTXnTBLCsat     0x0080
+#define HC_SubA_HTXnTBLCop      0x0081
+#define HC_SubA_HTXnTBLMPfog    0x0082
+#define HC_SubA_HTXnTBLAsat     0x0083
+#define HC_SubA_HTXnTBLRCa      0x0085
+#define HC_SubA_HTXnTBLRCb      0x0086
+#define HC_SubA_HTXnTBLRCc      0x0087
+#define HC_SubA_HTXnTBLRCbias   0x0088
+#define HC_SubA_HTXnTBLRAa      0x0089
+#define HC_SubA_HTXnTBLRFog     0x008a
+#define HC_SubA_HTXnBumpM00     0x0090
+#define HC_SubA_HTXnBumpM01     0x0091
+#define HC_SubA_HTXnBumpM10     0x0092
+#define HC_SubA_HTXnBumpM11     0x0093
+#define HC_SubA_HTXnLScale      0x0094
+#define HC_SubA_HTXSMD          0x0000
+/* HC_SubA_HTXnL012BasH    0x0020
+ */
+#define HC_HTXnL0BasH_MASK      0x000000ff
+#define HC_HTXnL1BasH_MASK      0x0000ff00
+#define HC_HTXnL2BasH_MASK      0x00ff0000
+#define HC_HTXnL1BasH_SHIFT     8
+#define HC_HTXnL2BasH_SHIFT     16
+/* HC_SubA_HTXnL345BasH    0x0021
+ */
+#define HC_HTXnL3BasH_MASK      0x000000ff
+#define HC_HTXnL4BasH_MASK      0x0000ff00
+#define HC_HTXnL5BasH_MASK      0x00ff0000
+#define HC_HTXnL4BasH_SHIFT     8
+#define HC_HTXnL5BasH_SHIFT     16
+/* HC_SubA_HTXnL678BasH    0x0022
+ */
+#define HC_HTXnL6BasH_MASK      0x000000ff
+#define HC_HTXnL7BasH_MASK      0x0000ff00
+#define HC_HTXnL8BasH_MASK      0x00ff0000
+#define HC_HTXnL7BasH_SHIFT     8
+#define HC_HTXnL8BasH_SHIFT     16
+/* HC_SubA_HTXnL9abBasH    0x0023
+ */
+#define HC_HTXnL9BasH_MASK      0x000000ff
+#define HC_HTXnLaBasH_MASK      0x0000ff00
+#define HC_HTXnLbBasH_MASK      0x00ff0000
+#define HC_HTXnLaBasH_SHIFT     8
+#define HC_HTXnLbBasH_SHIFT     16
+/* HC_SubA_HTXnLcdeBasH    0x0024
+ */
+#define HC_HTXnLcBasH_MASK      0x000000ff
+#define HC_HTXnLdBasH_MASK      0x0000ff00
+#define HC_HTXnLeBasH_MASK      0x00ff0000
+#define HC_HTXnLdBasH_SHIFT     8
+#define HC_HTXnLeBasH_SHIFT     16
+/* HC_SubA_HTXnLcdeBasH    0x0025
+ */
+#define HC_HTXnLfBasH_MASK      0x000000ff
+#define HC_HTXnL10BasH_MASK      0x0000ff00
+#define HC_HTXnL11BasH_MASK      0x00ff0000
+#define HC_HTXnL10BasH_SHIFT     8
+#define HC_HTXnL11BasH_SHIFT     16
+/* HC_SubA_HTXnL0Pit       0x002b
+ */
+#define HC_HTXnLnPit_MASK       0x00003fff
+#define HC_HTXnEnPit_MASK       0x00080000
+#define HC_HTXnLnPitE_MASK      0x00f00000
+#define HC_HTXnLnPitE_SHIFT     20
+/* HC_SubA_HTXnL0_5WE      0x004b
+ */
+#define HC_HTXnL0WE_MASK        0x0000000f
+#define HC_HTXnL1WE_MASK        0x000000f0
+#define HC_HTXnL2WE_MASK        0x00000f00
+#define HC_HTXnL3WE_MASK        0x0000f000
+#define HC_HTXnL4WE_MASK        0x000f0000
+#define HC_HTXnL5WE_MASK        0x00f00000
+#define HC_HTXnL1WE_SHIFT       4
+#define HC_HTXnL2WE_SHIFT       8
+#define HC_HTXnL3WE_SHIFT       12
+#define HC_HTXnL4WE_SHIFT       16
+#define HC_HTXnL5WE_SHIFT       20
+/* HC_SubA_HTXnL6_bWE      0x004c
+ */
+#define HC_HTXnL6WE_MASK        0x0000000f
+#define HC_HTXnL7WE_MASK        0x000000f0
+#define HC_HTXnL8WE_MASK        0x00000f00
+#define HC_HTXnL9WE_MASK        0x0000f000
+#define HC_HTXnLaWE_MASK        0x000f0000
+#define HC_HTXnLbWE_MASK        0x00f00000
+#define HC_HTXnL7WE_SHIFT       4
+#define HC_HTXnL8WE_SHIFT       8
+#define HC_HTXnL9WE_SHIFT       12
+#define HC_HTXnLaWE_SHIFT       16
+#define HC_HTXnLbWE_SHIFT       20
+/* HC_SubA_HTXnLc_11WE      0x004d
+ */
+#define HC_HTXnLcWE_MASK        0x0000000f
+#define HC_HTXnLdWE_MASK        0x000000f0
+#define HC_HTXnLeWE_MASK        0x00000f00
+#define HC_HTXnLfWE_MASK        0x0000f000
+#define HC_HTXnL10WE_MASK       0x000f0000
+#define HC_HTXnL11WE_MASK       0x00f00000
+#define HC_HTXnLdWE_SHIFT       4
+#define HC_HTXnLeWE_SHIFT       8
+#define HC_HTXnLfWE_SHIFT       12
+#define HC_HTXnL10WE_SHIFT      16
+#define HC_HTXnL11WE_SHIFT      20
+/* HC_SubA_HTXnL0_5HE      0x0051
+ */
+#define HC_HTXnL0HE_MASK        0x0000000f
+#define HC_HTXnL1HE_MASK        0x000000f0
+#define HC_HTXnL2HE_MASK        0x00000f00
+#define HC_HTXnL3HE_MASK        0x0000f000
+#define HC_HTXnL4HE_MASK        0x000f0000
+#define HC_HTXnL5HE_MASK        0x00f00000
+#define HC_HTXnL1HE_SHIFT       4
+#define HC_HTXnL2HE_SHIFT       8
+#define HC_HTXnL3HE_SHIFT       12
+#define HC_HTXnL4HE_SHIFT       16
+#define HC_HTXnL5HE_SHIFT       20
+/* HC_SubA_HTXnL6_bHE      0x0052
+ */
+#define HC_HTXnL6HE_MASK        0x0000000f
+#define HC_HTXnL7HE_MASK        0x000000f0
+#define HC_HTXnL8HE_MASK        0x00000f00
+#define HC_HTXnL9HE_MASK        0x0000f000
+#define HC_HTXnLaHE_MASK        0x000f0000
+#define HC_HTXnLbHE_MASK        0x00f00000
+#define HC_HTXnL7HE_SHIFT       4
+#define HC_HTXnL8HE_SHIFT       8
+#define HC_HTXnL9HE_SHIFT       12
+#define HC_HTXnLaHE_SHIFT       16
+#define HC_HTXnLbHE_SHIFT       20
+/* HC_SubA_HTXnLc_11HE      0x0053
+ */
+#define HC_HTXnLcHE_MASK        0x0000000f
+#define HC_HTXnLdHE_MASK        0x000000f0
+#define HC_HTXnLeHE_MASK        0x00000f00
+#define HC_HTXnLfHE_MASK        0x0000f000
+#define HC_HTXnL10HE_MASK       0x000f0000
+#define HC_HTXnL11HE_MASK       0x00f00000
+#define HC_HTXnLdHE_SHIFT       4
+#define HC_HTXnLeHE_SHIFT       8
+#define HC_HTXnLfHE_SHIFT       12
+#define HC_HTXnL10HE_SHIFT      16
+#define HC_HTXnL11HE_SHIFT      20
+/* HC_SubA_HTXnL0OS        0x0077
+ */
+#define HC_HTXnL0OS_MASK        0x003ff000
+#define HC_HTXnLVmax_MASK       0x00000fc0
+#define HC_HTXnLVmin_MASK       0x0000003f
+#define HC_HTXnL0OS_SHIFT       12
+#define HC_HTXnLVmax_SHIFT      6
+/* HC_SubA_HTXnTB          0x0078
+ */
+#define HC_HTXnTB_MASK          0x00f00000
+#define HC_HTXnFLSe_MASK        0x0000e000
+#define HC_HTXnFLSs_MASK        0x00001c00
+#define HC_HTXnFLTe_MASK        0x00000380
+#define HC_HTXnFLTs_MASK        0x00000070
+#define HC_HTXnFLDs_MASK        0x0000000f
+#define HC_HTXnTB_NoTB          0x00000000
+#define HC_HTXnTB_TBC_S         0x00100000
+#define HC_HTXnTB_TBC_T         0x00200000
+#define HC_HTXnTB_TB_S          0x00400000
+#define HC_HTXnTB_TB_T          0x00800000
+#define HC_HTXnFLSe_Nearest     0x00000000
+#define HC_HTXnFLSe_Linear      0x00002000
+#define HC_HTXnFLSe_NonLinear   0x00004000
+#define HC_HTXnFLSe_Sharp       0x00008000
+#define HC_HTXnFLSe_Flat_Gaussian_Cubic 0x0000c000
+#define HC_HTXnFLSs_Nearest     0x00000000
+#define HC_HTXnFLSs_Linear      0x00000400
+#define HC_HTXnFLSs_NonLinear   0x00000800
+#define HC_HTXnFLSs_Flat_Gaussian_Cubic 0x00001800
+#define HC_HTXnFLTe_Nearest     0x00000000
+#define HC_HTXnFLTe_Linear      0x00000080
+#define HC_HTXnFLTe_NonLinear   0x00000100
+#define HC_HTXnFLTe_Sharp       0x00000180
+#define HC_HTXnFLTe_Flat_Gaussian_Cubic 0x00000300
+#define HC_HTXnFLTs_Nearest     0x00000000
+#define HC_HTXnFLTs_Linear      0x00000010
+#define HC_HTXnFLTs_NonLinear   0x00000020
+#define HC_HTXnFLTs_Flat_Gaussian_Cubic 0x00000060
+#define HC_HTXnFLDs_Tex0        0x00000000
+#define HC_HTXnFLDs_Nearest     0x00000001
+#define HC_HTXnFLDs_Linear      0x00000002
+#define HC_HTXnFLDs_NonLinear   0x00000003
+#define HC_HTXnFLDs_Dither      0x00000004
+#define HC_HTXnFLDs_ConstLOD    0x00000005
+#define HC_HTXnFLDs_Ani         0x00000006
+#define HC_HTXnFLDs_AniDither   0x00000007
+/* HC_SubA_HTXnMPMD        0x0079
+ */
+#define HC_HTXnMPMD_SMASK       0x00070000
+#define HC_HTXnMPMD_TMASK       0x00380000
+#define HC_HTXnLODDTf_MASK      0x00000007
+#define HC_HTXnXY2ST_MASK       0x00000008
+#define HC_HTXnMPMD_Tsingle     0x00000000
+#define HC_HTXnMPMD_Tclamp      0x00080000
+#define HC_HTXnMPMD_Trepeat     0x00100000
+#define HC_HTXnMPMD_Tmirror     0x00180000
+#define HC_HTXnMPMD_Twrap       0x00200000
+#define HC_HTXnMPMD_Ssingle     0x00000000
+#define HC_HTXnMPMD_Sclamp      0x00010000
+#define HC_HTXnMPMD_Srepeat     0x00020000
+#define HC_HTXnMPMD_Smirror     0x00030000
+#define HC_HTXnMPMD_Swrap       0x00040000
+/* HC_SubA_HTXnCLODu       0x007a
+ */
+#define HC_HTXnCLODu_MASK       0x000ffc00
+#define HC_HTXnCLODd_MASK       0x000003ff
+#define HC_HTXnCLODu_SHIFT      10
+/* HC_SubA_HTXnFM          0x007b
+ */
+#define HC_HTXnFM_MASK          0x00ff0000
+#define HC_HTXnLoc_MASK         0x00000003
+#define HC_HTXnFM_INDEX         0x00000000
+#define HC_HTXnFM_Intensity     0x00080000
+#define HC_HTXnFM_Lum           0x00100000
+#define HC_HTXnFM_Alpha         0x00180000
+#define HC_HTXnFM_DX            0x00280000
+#define HC_HTXnFM_ARGB16        0x00880000
+#define HC_HTXnFM_ARGB32        0x00980000
+#define HC_HTXnFM_ABGR16        0x00a80000
+#define HC_HTXnFM_ABGR32        0x00b80000
+#define HC_HTXnFM_RGBA16        0x00c80000
+#define HC_HTXnFM_RGBA32        0x00d80000
+#define HC_HTXnFM_BGRA16        0x00e80000
+#define HC_HTXnFM_BGRA32        0x00f80000
+#define HC_HTXnFM_BUMPMAP       0x00380000
+#define HC_HTXnFM_Index1        (HC_HTXnFM_INDEX     | 0x00000000)
+#define HC_HTXnFM_Index2        (HC_HTXnFM_INDEX     | 0x00010000)
+#define HC_HTXnFM_Index4        (HC_HTXnFM_INDEX     | 0x00020000)
+#define HC_HTXnFM_Index8        (HC_HTXnFM_INDEX     | 0x00030000)
+#define HC_HTXnFM_T1            (HC_HTXnFM_Intensity | 0x00000000)
+#define HC_HTXnFM_T2            (HC_HTXnFM_Intensity | 0x00010000)
+#define HC_HTXnFM_T4            (HC_HTXnFM_Intensity | 0x00020000)
+#define HC_HTXnFM_T8            (HC_HTXnFM_Intensity | 0x00030000)
+#define HC_HTXnFM_L1            (HC_HTXnFM_Lum       | 0x00000000)
+#define HC_HTXnFM_L2            (HC_HTXnFM_Lum       | 0x00010000)
+#define HC_HTXnFM_L4            (HC_HTXnFM_Lum       | 0x00020000)
+#define HC_HTXnFM_L8            (HC_HTXnFM_Lum       | 0x00030000)
+#define HC_HTXnFM_AL44          (HC_HTXnFM_Lum       | 0x00040000)
+#define HC_HTXnFM_AL88          (HC_HTXnFM_Lum       | 0x00050000)
+#define HC_HTXnFM_A1            (HC_HTXnFM_Alpha     | 0x00000000)
+#define HC_HTXnFM_A2            (HC_HTXnFM_Alpha     | 0x00010000)
+#define HC_HTXnFM_A4            (HC_HTXnFM_Alpha     | 0x00020000)
+#define HC_HTXnFM_A8            (HC_HTXnFM_Alpha     | 0x00030000)
+#define HC_HTXnFM_DX1           (HC_HTXnFM_DX        | 0x00010000)
+#define HC_HTXnFM_DX23          (HC_HTXnFM_DX        | 0x00020000)
+#define HC_HTXnFM_DX45          (HC_HTXnFM_DX        | 0x00030000)
+#define HC_HTXnFM_RGB555        (HC_HTXnFM_ARGB16    | 0x00000000)
+#define HC_HTXnFM_RGB565        (HC_HTXnFM_ARGB16    | 0x00010000)
+#define HC_HTXnFM_ARGB1555      (HC_HTXnFM_ARGB16    | 0x00020000)
+#define HC_HTXnFM_ARGB4444      (HC_HTXnFM_ARGB16    | 0x00030000)
+#define HC_HTXnFM_ARGB0888      (HC_HTXnFM_ARGB32    | 0x00000000)
+#define HC_HTXnFM_ARGB8888      (HC_HTXnFM_ARGB32    | 0x00010000)
+#define HC_HTXnFM_BGR555        (HC_HTXnFM_ABGR16    | 0x00000000)
+#define HC_HTXnFM_BGR565        (HC_HTXnFM_ABGR16    | 0x00010000)
+#define HC_HTXnFM_ABGR1555      (HC_HTXnFM_ABGR16    | 0x00020000)
+#define HC_HTXnFM_ABGR4444      (HC_HTXnFM_ABGR16    | 0x00030000)
+#define HC_HTXnFM_ABGR0888      (HC_HTXnFM_ABGR32    | 0x00000000)
+#define HC_HTXnFM_ABGR8888      (HC_HTXnFM_ABGR32    | 0x00010000)
+#define HC_HTXnFM_RGBA5550      (HC_HTXnFM_RGBA16    | 0x00000000)
+#define HC_HTXnFM_RGBA5551      (HC_HTXnFM_RGBA16    | 0x00020000)
+#define HC_HTXnFM_RGBA4444      (HC_HTXnFM_RGBA16    | 0x00030000)
+#define HC_HTXnFM_RGBA8880      (HC_HTXnFM_RGBA32    | 0x00000000)
+#define HC_HTXnFM_RGBA8888      (HC_HTXnFM_RGBA32    | 0x00010000)
+#define HC_HTXnFM_BGRA5550      (HC_HTXnFM_BGRA16    | 0x00000000)
+#define HC_HTXnFM_BGRA5551      (HC_HTXnFM_BGRA16    | 0x00020000)
+#define HC_HTXnFM_BGRA4444      (HC_HTXnFM_BGRA16    | 0x00030000)
+#define HC_HTXnFM_BGRA8880      (HC_HTXnFM_BGRA32    | 0x00000000)
+#define HC_HTXnFM_BGRA8888      (HC_HTXnFM_BGRA32    | 0x00010000)
+#define HC_HTXnFM_VU88          (HC_HTXnFM_BUMPMAP   | 0x00000000)
+#define HC_HTXnFM_LVU655        (HC_HTXnFM_BUMPMAP   | 0x00010000)
+#define HC_HTXnFM_LVU888        (HC_HTXnFM_BUMPMAP   | 0x00020000)
+#define HC_HTXnLoc_Local        0x00000000
+#define HC_HTXnLoc_Sys          0x00000002
+#define HC_HTXnLoc_AGP          0x00000003
+/* HC_SubA_HTXnTRAH        0x007f
+ */
+#define HC_HTXnTRAH_MASK        0x00ff0000
+#define HC_HTXnTRAL_MASK        0x0000ff00
+#define HC_HTXnTBA_MASK         0x000000ff
+#define HC_HTXnTRAH_SHIFT       16
+#define HC_HTXnTRAL_SHIFT       8
+/* HC_SubA_HTXnTBLCsat     0x0080
+ *-- Define the input texture.
+ */
+#define HC_XTC_TOPC             0x00000000
+#define HC_XTC_InvTOPC          0x00000010
+#define HC_XTC_TOPCp5           0x00000020
+#define HC_XTC_Cbias            0x00000000
+#define HC_XTC_InvCbias         0x00000010
+#define HC_XTC_0                0x00000000
+#define HC_XTC_Dif              0x00000001
+#define HC_XTC_Spec             0x00000002
+#define HC_XTC_Tex              0x00000003
+#define HC_XTC_Cur              0x00000004
+#define HC_XTC_Adif             0x00000005
+#define HC_XTC_Fog              0x00000006
+#define HC_XTC_Atex             0x00000007
+#define HC_XTC_Acur             0x00000008
+#define HC_XTC_HTXnTBLRC        0x00000009
+#define HC_XTC_Ctexnext         0x0000000a
+/*--
+ */
+#define HC_HTXnTBLCsat_MASK     0x00800000
+#define HC_HTXnTBLCa_MASK       0x000fc000
+#define HC_HTXnTBLCb_MASK       0x00001f80
+#define HC_HTXnTBLCc_MASK       0x0000003f
+#define HC_HTXnTBLCa_TOPC       (HC_XTC_TOPC << 14)
+#define HC_HTXnTBLCa_InvTOPC    (HC_XTC_InvTOPC << 14)
+#define HC_HTXnTBLCa_TOPCp5     (HC_XTC_TOPCp5 << 14)
+#define HC_HTXnTBLCa_0          (HC_XTC_0 << 14)
+#define HC_HTXnTBLCa_Dif        (HC_XTC_Dif << 14)
+#define HC_HTXnTBLCa_Spec       (HC_XTC_Spec << 14)
+#define HC_HTXnTBLCa_Tex        (HC_XTC_Tex << 14)
+#define HC_HTXnTBLCa_Cur        (HC_XTC_Cur << 14)
+#define HC_HTXnTBLCa_Adif       (HC_XTC_Adif << 14)
+#define HC_HTXnTBLCa_Fog        (HC_XTC_Fog << 14)
+#define HC_HTXnTBLCa_Atex       (HC_XTC_Atex << 14)
+#define HC_HTXnTBLCa_Acur       (HC_XTC_Acur << 14)
+#define HC_HTXnTBLCa_HTXnTBLRC  (HC_XTC_HTXnTBLRC << 14)
+#define HC_HTXnTBLCa_Ctexnext   (HC_XTC_Ctexnext << 14)
+#define HC_HTXnTBLCb_TOPC       (HC_XTC_TOPC << 7)
+#define HC_HTXnTBLCb_InvTOPC    (HC_XTC_InvTOPC << 7)
+#define HC_HTXnTBLCb_TOPCp5     (HC_XTC_TOPCp5 << 7)
+#define HC_HTXnTBLCb_0          (HC_XTC_0 << 7)
+#define HC_HTXnTBLCb_Dif        (HC_XTC_Dif << 7)
+#define HC_HTXnTBLCb_Spec       (HC_XTC_Spec << 7)
+#define HC_HTXnTBLCb_Tex        (HC_XTC_Tex << 7)
+#define HC_HTXnTBLCb_Cur        (HC_XTC_Cur << 7)
+#define HC_HTXnTBLCb_Adif       (HC_XTC_Adif << 7)
+#define HC_HTXnTBLCb_Fog        (HC_XTC_Fog << 7)
+#define HC_HTXnTBLCb_Atex       (HC_XTC_Atex << 7)
+#define HC_HTXnTBLCb_Acur       (HC_XTC_Acur << 7)
+#define HC_HTXnTBLCb_HTXnTBLRC  (HC_XTC_HTXnTBLRC << 7)
+#define HC_HTXnTBLCb_Ctexnext   (HC_XTC_Ctexnext << 7)
+#define HC_HTXnTBLCc_TOPC       (HC_XTC_TOPC << 0)
+#define HC_HTXnTBLCc_InvTOPC    (HC_XTC_InvTOPC << 0)
+#define HC_HTXnTBLCc_TOPCp5     (HC_XTC_TOPCp5 << 0)
+#define HC_HTXnTBLCc_0          (HC_XTC_0 << 0)
+#define HC_HTXnTBLCc_Dif        (HC_XTC_Dif << 0)
+#define HC_HTXnTBLCc_Spec       (HC_XTC_Spec << 0)
+#define HC_HTXnTBLCc_Tex        (HC_XTC_Tex << 0)
+#define HC_HTXnTBLCc_Cur        (HC_XTC_Cur << 0)
+#define HC_HTXnTBLCc_Adif       (HC_XTC_Adif << 0)
+#define HC_HTXnTBLCc_Fog        (HC_XTC_Fog << 0)
+#define HC_HTXnTBLCc_Atex       (HC_XTC_Atex << 0)
+#define HC_HTXnTBLCc_Acur       (HC_XTC_Acur << 0)
+#define HC_HTXnTBLCc_HTXnTBLRC  (HC_XTC_HTXnTBLRC << 0)
+#define HC_HTXnTBLCc_Ctexnext   (HC_XTC_Ctexnext << 0)
+/* HC_SubA_HTXnTBLCop      0x0081
+ */
+#define HC_HTXnTBLdot_MASK      0x00c00000
+#define HC_HTXnTBLCop_MASK      0x00380000
+#define HC_HTXnTBLCbias_MASK    0x0007c000
+#define HC_HTXnTBLCshift_MASK   0x00001800
+#define HC_HTXnTBLAop_MASK      0x00000380
+#define HC_HTXnTBLAbias_MASK    0x00000078
+#define HC_HTXnTBLAshift_MASK   0x00000003
+#define HC_HTXnTBLCop_Add       0x00000000
+#define HC_HTXnTBLCop_Sub       0x00080000
+#define HC_HTXnTBLCop_Min       0x00100000
+#define HC_HTXnTBLCop_Max       0x00180000
+#define HC_HTXnTBLCop_Mask      0x00200000
+#define HC_HTXnTBLCbias_Cbias           (HC_XTC_Cbias << 14)
+#define HC_HTXnTBLCbias_InvCbias        (HC_XTC_InvCbias << 14)
+#define HC_HTXnTBLCbias_0               (HC_XTC_0 << 14)
+#define HC_HTXnTBLCbias_Dif             (HC_XTC_Dif << 14)
+#define HC_HTXnTBLCbias_Spec            (HC_XTC_Spec << 14)
+#define HC_HTXnTBLCbias_Tex             (HC_XTC_Tex << 14)
+#define HC_HTXnTBLCbias_Cur             (HC_XTC_Cur << 14)
+#define HC_HTXnTBLCbias_Adif            (HC_XTC_Adif << 14)
+#define HC_HTXnTBLCbias_Fog             (HC_XTC_Fog << 14)
+#define HC_HTXnTBLCbias_Atex            (HC_XTC_Atex << 14)
+#define HC_HTXnTBLCbias_Acur            (HC_XTC_Acur << 14)
+#define HC_HTXnTBLCbias_HTXnTBLRC       (HC_XTC_HTXnTBLRC << 14)
+#define HC_HTXnTBLCshift_1      0x00000000
+#define HC_HTXnTBLCshift_2      0x00000800
+#define HC_HTXnTBLCshift_No     0x00001000
+#define HC_HTXnTBLCshift_DotP   0x00001800
+/*=* John Sheng [2003.7.18] texture combine *=*/
+#define HC_HTXnTBLDOT3   0x00080000
+#define HC_HTXnTBLDOT4   0x000C0000
+
+#define HC_HTXnTBLAop_Add       0x00000000
+#define HC_HTXnTBLAop_Sub       0x00000080
+#define HC_HTXnTBLAop_Min       0x00000100
+#define HC_HTXnTBLAop_Max       0x00000180
+#define HC_HTXnTBLAop_Mask      0x00000200
+#define HC_HTXnTBLAbias_Inv             0x00000040
+#define HC_HTXnTBLAbias_Adif            0x00000000
+#define HC_HTXnTBLAbias_Fog             0x00000008
+#define HC_HTXnTBLAbias_Acur            0x00000010
+#define HC_HTXnTBLAbias_HTXnTBLRAbias   0x00000018
+#define HC_HTXnTBLAbias_Atex            0x00000020
+#define HC_HTXnTBLAshift_1      0x00000000
+#define HC_HTXnTBLAshift_2      0x00000001
+#define HC_HTXnTBLAshift_No     0x00000002
+/* #define HC_HTXnTBLAshift_DotP   0x00000003 */
+/* HC_SubA_HTXnTBLMPFog    0x0082
+ */
+#define HC_HTXnTBLMPfog_MASK    0x00e00000
+#define HC_HTXnTBLMPfog_0       0x00000000
+#define HC_HTXnTBLMPfog_Adif    0x00200000
+#define HC_HTXnTBLMPfog_Fog     0x00400000
+#define HC_HTXnTBLMPfog_Atex    0x00600000
+#define HC_HTXnTBLMPfog_Acur    0x00800000
+#define HC_HTXnTBLMPfog_GHTXnTBLRFog    0x00a00000
+/* HC_SubA_HTXnTBLAsat     0x0083
+ *-- Define the texture alpha input.
+ */
+#define HC_XTA_TOPA             0x00000000
+#define HC_XTA_InvTOPA          0x00000008
+#define HC_XTA_TOPAp5           0x00000010
+#define HC_XTA_Adif             0x00000000
+#define HC_XTA_Fog              0x00000001
+#define HC_XTA_Acur             0x00000002
+#define HC_XTA_HTXnTBLRA        0x00000003
+#define HC_XTA_Atex             0x00000004
+#define HC_XTA_Atexnext         0x00000005
+/*--
+ */
+#define HC_HTXnTBLAsat_MASK     0x00800000
+#define HC_HTXnTBLAMB_MASK      0x00700000
+#define HC_HTXnTBLAa_MASK       0x0007c000
+#define HC_HTXnTBLAb_MASK       0x00000f80
+#define HC_HTXnTBLAc_MASK       0x0000001f
+#define HC_HTXnTBLAMB_SHIFT     20
+#define HC_HTXnTBLAa_TOPA       (HC_XTA_TOPA << 14)
+#define HC_HTXnTBLAa_InvTOPA    (HC_XTA_InvTOPA << 14)
+#define HC_HTXnTBLAa_TOPAp5     (HC_XTA_TOPAp5 << 14)
+#define HC_HTXnTBLAa_Adif       (HC_XTA_Adif << 14)
+#define HC_HTXnTBLAa_Fog        (HC_XTA_Fog << 14)
+#define HC_HTXnTBLAa_Acur       (HC_XTA_Acur << 14)
+#define HC_HTXnTBLAa_HTXnTBLRA  (HC_XTA_HTXnTBLRA << 14)
+#define HC_HTXnTBLAa_Atex       (HC_XTA_Atex << 14)
+#define HC_HTXnTBLAa_Atexnext   (HC_XTA_Atexnext << 14)
+#define HC_HTXnTBLAb_TOPA       (HC_XTA_TOPA << 7)
+#define HC_HTXnTBLAb_InvTOPA    (HC_XTA_InvTOPA << 7)
+#define HC_HTXnTBLAb_TOPAp5     (HC_XTA_TOPAp5 << 7)
+#define HC_HTXnTBLAb_Adif       (HC_XTA_Adif << 7)
+#define HC_HTXnTBLAb_Fog        (HC_XTA_Fog << 7)
+#define HC_HTXnTBLAb_Acur       (HC_XTA_Acur << 7)
+#define HC_HTXnTBLAb_HTXnTBLRA  (HC_XTA_HTXnTBLRA << 7)
+#define HC_HTXnTBLAb_Atex       (HC_XTA_Atex << 7)
+#define HC_HTXnTBLAb_Atexnext   (HC_XTA_Atexnext << 7)
+#define HC_HTXnTBLAc_TOPA       (HC_XTA_TOPA << 0)
+#define HC_HTXnTBLAc_InvTOPA    (HC_XTA_InvTOPA << 0)
+#define HC_HTXnTBLAc_TOPAp5     (HC_XTA_TOPAp5 << 0)
+#define HC_HTXnTBLAc_Adif       (HC_XTA_Adif << 0)
+#define HC_HTXnTBLAc_Fog        (HC_XTA_Fog << 0)
+#define HC_HTXnTBLAc_Acur       (HC_XTA_Acur << 0)
+#define HC_HTXnTBLAc_HTXnTBLRA  (HC_XTA_HTXnTBLRA << 0)
+#define HC_HTXnTBLAc_Atex       (HC_XTA_Atex << 0)
+#define HC_HTXnTBLAc_Atexnext   (HC_XTA_Atexnext << 0)
+/* HC_SubA_HTXnTBLRAa      0x0089
+ */
+#define HC_HTXnTBLRAa_MASK      0x00ff0000
+#define HC_HTXnTBLRAb_MASK      0x0000ff00
+#define HC_HTXnTBLRAc_MASK      0x000000ff
+#define HC_HTXnTBLRAa_SHIFT     16
+#define HC_HTXnTBLRAb_SHIFT     8
+#define HC_HTXnTBLRAc_SHIFT     0
+/* HC_SubA_HTXnTBLRFog     0x008a
+ */
+#define HC_HTXnTBLRFog_MASK     0x0000ff00
+#define HC_HTXnTBLRAbias_MASK   0x000000ff
+#define HC_HTXnTBLRFog_SHIFT    8
+#define HC_HTXnTBLRAbias_SHIFT  0
+/* HC_SubA_HTXnLScale      0x0094
+ */
+#define HC_HTXnLScale_MASK      0x0007fc00
+#define HC_HTXnLOff_MASK        0x000001ff
+#define HC_HTXnLScale_SHIFT     10
+/* HC_SubA_HTXSMD          0x0000
+ */
+#define HC_HTXSMD_MASK          0x00000080
+#define HC_HTXTMD_MASK          0x00000040
+#define HC_HTXNum_MASK          0x00000038
+#define HC_HTXTRMD_MASK         0x00000006
+#define HC_HTXCHCLR_MASK        0x00000001
+#define HC_HTXNum_SHIFT         3
+
+/* Texture Palette n
+ */
+#define HC_SubType_TexPalette0  0x00000000
+#define HC_SubType_TexPalette1  0x00000001
+#define HC_SubType_FogTable     0x00000010
+#define HC_SubType_Stipple      0x00000014
+/* HC_SubA_TexPalette0     0x0000
+ */
+#define HC_HTPnA_MASK           0xff000000
+#define HC_HTPnR_MASK           0x00ff0000
+#define HC_HTPnG_MASK           0x0000ff00
+#define HC_HTPnB_MASK           0x000000ff
+/* HC_SubA_FogTable        0x0010
+ */
+#define HC_HFPn3_MASK           0xff000000
+#define HC_HFPn2_MASK           0x00ff0000
+#define HC_HFPn1_MASK           0x0000ff00
+#define HC_HFPn_MASK            0x000000ff
+#define HC_HFPn3_SHIFT          24
+#define HC_HFPn2_SHIFT          16
+#define HC_HFPn1_SHIFT          8
+
+/* Auto Testing & Security
+ */
+#define HC_SubA_HenFIFOAT       0x0000
+#define HC_SubA_HFBDrawFirst    0x0004
+#define HC_SubA_HFBBasL         0x0005
+#define HC_SubA_HFBDst          0x0006
+/* HC_SubA_HenFIFOAT       0x0000
+ */
+#define HC_HenFIFOAT_MASK       0x00000020
+#define HC_HenGEMILock_MASK     0x00000010
+#define HC_HenFBASwap_MASK      0x00000008
+#define HC_HenOT_MASK           0x00000004
+#define HC_HenCMDQ_MASK         0x00000002
+#define HC_HenTXCTSU_MASK       0x00000001
+/* HC_SubA_HFBDrawFirst    0x0004
+ */
+#define HC_HFBDrawFirst_MASK    0x00000800
+#define HC_HFBQueue_MASK        0x00000400
+#define HC_HFBLock_MASK         0x00000200
+#define HC_HEOF_MASK            0x00000100
+#define HC_HFBBasH_MASK         0x000000ff
+
+/* GEMI Setting
+ */
+#define HC_SubA_HTArbRCM        0x0008
+#define HC_SubA_HTArbRZ         0x000a
+#define HC_SubA_HTArbWZ         0x000b
+#define HC_SubA_HTArbRTX        0x000c
+#define HC_SubA_HTArbRCW        0x000d
+#define HC_SubA_HTArbE2         0x000e
+#define HC_SubA_HArbRQCM        0x0010
+#define HC_SubA_HArbWQCM        0x0011
+#define HC_SubA_HGEMITout       0x0020
+#define HC_SubA_HFthRTXD        0x0040
+#define HC_SubA_HFthRTXA        0x0044
+#define HC_SubA_HCMDQstL        0x0050
+#define HC_SubA_HCMDQendL       0x0051
+#define HC_SubA_HCMDQLen        0x0052
+/* HC_SubA_HTArbRCM        0x0008
+ */
+#define HC_HTArbRCM_MASK        0x0000ffff
+/* HC_SubA_HTArbRZ         0x000a
+ */
+#define HC_HTArbRZ_MASK         0x0000ffff
+/* HC_SubA_HTArbWZ         0x000b
+ */
+#define HC_HTArbWZ_MASK         0x0000ffff
+/* HC_SubA_HTArbRTX        0x000c
+ */
+#define HC_HTArbRTX_MASK        0x0000ffff
+/* HC_SubA_HTArbRCW        0x000d
+ */
+#define HC_HTArbRCW_MASK        0x0000ffff
+/* HC_SubA_HTArbE2         0x000e
+ */
+#define HC_HTArbE2_MASK         0x0000ffff
+/* HC_SubA_HArbRQCM        0x0010
+ */
+#define HC_HTArbRQCM_MASK       0x0000ffff
+/* HC_SubA_HArbWQCM        0x0011
+ */
+#define HC_HArbWQCM_MASK        0x0000ffff
+/* HC_SubA_HGEMITout       0x0020
+ */
+#define HC_HGEMITout_MASK       0x000f0000
+#define HC_HNPArbZC_MASK        0x0000ffff
+#define HC_HGEMITout_SHIFT      16
+/* HC_SubA_HFthRTXD        0x0040
+ */
+#define HC_HFthRTXD_MASK        0x00ff0000
+#define HC_HFthRZD_MASK         0x0000ff00
+#define HC_HFthWZD_MASK         0x000000ff
+#define HC_HFthRTXD_SHIFT       16
+#define HC_HFthRZD_SHIFT        8
+/* HC_SubA_HFthRTXA        0x0044
+ */
+#define HC_HFthRTXA_MASK        0x000000ff
+
+/******************************************************************************
+** Define the Halcyon Internal register access constants. For simulator only.
+******************************************************************************/
+#define HC_SIMA_HAGPBstL        0x0000
+#define HC_SIMA_HAGPBendL       0x0001
+#define HC_SIMA_HAGPCMNT        0x0002
+#define HC_SIMA_HAGPBpL         0x0003
+#define HC_SIMA_HAGPBpH         0x0004
+#define HC_SIMA_HClipTB         0x0005
+#define HC_SIMA_HClipLR         0x0006
+#define HC_SIMA_HFPClipTL       0x0007
+#define HC_SIMA_HFPClipBL       0x0008
+#define HC_SIMA_HFPClipLL       0x0009
+#define HC_SIMA_HFPClipRL       0x000a
+#define HC_SIMA_HFPClipTBH      0x000b
+#define HC_SIMA_HFPClipLRH      0x000c
+#define HC_SIMA_HLP             0x000d
+#define HC_SIMA_HLPRF           0x000e
+#define HC_SIMA_HSolidCL        0x000f
+#define HC_SIMA_HPixGC          0x0010
+#define HC_SIMA_HSPXYOS         0x0011
+#define HC_SIMA_HCmdA           0x0012
+#define HC_SIMA_HCmdB           0x0013
+#define HC_SIMA_HEnable         0x0014
+#define HC_SIMA_HZWBBasL        0x0015
+#define HC_SIMA_HZWBBasH        0x0016
+#define HC_SIMA_HZWBType        0x0017
+#define HC_SIMA_HZBiasL         0x0018
+#define HC_SIMA_HZWBend         0x0019
+#define HC_SIMA_HZWTMD          0x001a
+#define HC_SIMA_HZWCDL          0x001b
+#define HC_SIMA_HZWCTAGnum      0x001c
+#define HC_SIMA_HZCYNum         0x001d
+#define HC_SIMA_HZWCFire        0x001e
+/* #define HC_SIMA_HSBBasL         0x001d */
+/* #define HC_SIMA_HSBBasH         0x001e */
+/* #define HC_SIMA_HSBFM           0x001f */
+#define HC_SIMA_HSTREF          0x0020
+#define HC_SIMA_HSTMD           0x0021
+#define HC_SIMA_HABBasL         0x0022
+#define HC_SIMA_HABBasH         0x0023
+#define HC_SIMA_HABFM           0x0024
+#define HC_SIMA_HATMD           0x0025
+#define HC_SIMA_HABLCsat        0x0026
+#define HC_SIMA_HABLCop         0x0027
+#define HC_SIMA_HABLAsat        0x0028
+#define HC_SIMA_HABLAop         0x0029
+#define HC_SIMA_HABLRCa         0x002a
+#define HC_SIMA_HABLRFCa        0x002b
+#define HC_SIMA_HABLRCbias      0x002c
+#define HC_SIMA_HABLRCb         0x002d
+#define HC_SIMA_HABLRFCb        0x002e
+#define HC_SIMA_HABLRAa         0x002f
+#define HC_SIMA_HABLRAb         0x0030
+#define HC_SIMA_HDBBasL         0x0031
+#define HC_SIMA_HDBBasH         0x0032
+#define HC_SIMA_HDBFM           0x0033
+#define HC_SIMA_HFBBMSKL        0x0034
+#define HC_SIMA_HROP            0x0035
+#define HC_SIMA_HFogLF          0x0036
+#define HC_SIMA_HFogCL          0x0037
+#define HC_SIMA_HFogCH          0x0038
+#define HC_SIMA_HFogStL         0x0039
+#define HC_SIMA_HFogStH         0x003a
+#define HC_SIMA_HFogOOdMF       0x003b
+#define HC_SIMA_HFogOOdEF       0x003c
+#define HC_SIMA_HFogEndL        0x003d
+#define HC_SIMA_HFogDenst       0x003e
+/*---- start of texture 0 setting ----
+ */
+#define HC_SIMA_HTX0L0BasL      0x0040
+#define HC_SIMA_HTX0L1BasL      0x0041
+#define HC_SIMA_HTX0L2BasL      0x0042
+#define HC_SIMA_HTX0L3BasL      0x0043
+#define HC_SIMA_HTX0L4BasL      0x0044
+#define HC_SIMA_HTX0L5BasL      0x0045
+#define HC_SIMA_HTX0L6BasL      0x0046
+#define HC_SIMA_HTX0L7BasL      0x0047
+#define HC_SIMA_HTX0L8BasL      0x0048
+#define HC_SIMA_HTX0L9BasL      0x0049
+#define HC_SIMA_HTX0LaBasL      0x004a
+#define HC_SIMA_HTX0LbBasL      0x004b
+#define HC_SIMA_HTX0LcBasL      0x004c
+#define HC_SIMA_HTX0LdBasL      0x004d
+#define HC_SIMA_HTX0LeBasL      0x004e
+#define HC_SIMA_HTX0LfBasL      0x004f
+#define HC_SIMA_HTX0L10BasL     0x0050
+#define HC_SIMA_HTX0L11BasL     0x0051
+#define HC_SIMA_HTX0L012BasH    0x0052
+#define HC_SIMA_HTX0L345BasH    0x0053
+#define HC_SIMA_HTX0L678BasH    0x0054
+#define HC_SIMA_HTX0L9abBasH    0x0055
+#define HC_SIMA_HTX0LcdeBasH    0x0056
+#define HC_SIMA_HTX0Lf1011BasH  0x0057
+#define HC_SIMA_HTX0L0Pit       0x0058
+#define HC_SIMA_HTX0L1Pit       0x0059
+#define HC_SIMA_HTX0L2Pit       0x005a
+#define HC_SIMA_HTX0L3Pit       0x005b
+#define HC_SIMA_HTX0L4Pit       0x005c
+#define HC_SIMA_HTX0L5Pit       0x005d
+#define HC_SIMA_HTX0L6Pit       0x005e
+#define HC_SIMA_HTX0L7Pit       0x005f
+#define HC_SIMA_HTX0L8Pit       0x0060
+#define HC_SIMA_HTX0L9Pit       0x0061
+#define HC_SIMA_HTX0LaPit       0x0062
+#define HC_SIMA_HTX0LbPit       0x0063
+#define HC_SIMA_HTX0LcPit       0x0064
+#define HC_SIMA_HTX0LdPit       0x0065
+#define HC_SIMA_HTX0LePit       0x0066
+#define HC_SIMA_HTX0LfPit       0x0067
+#define HC_SIMA_HTX0L10Pit      0x0068
+#define HC_SIMA_HTX0L11Pit      0x0069
+#define HC_SIMA_HTX0L0_5WE      0x006a
+#define HC_SIMA_HTX0L6_bWE      0x006b
+#define HC_SIMA_HTX0Lc_11WE     0x006c
+#define HC_SIMA_HTX0L0_5HE      0x006d
+#define HC_SIMA_HTX0L6_bHE      0x006e
+#define HC_SIMA_HTX0Lc_11HE     0x006f
+#define HC_SIMA_HTX0L0OS        0x0070
+#define HC_SIMA_HTX0TB          0x0071
+#define HC_SIMA_HTX0MPMD        0x0072
+#define HC_SIMA_HTX0CLODu       0x0073
+#define HC_SIMA_HTX0FM          0x0074
+#define HC_SIMA_HTX0TRCH        0x0075
+#define HC_SIMA_HTX0TRCL        0x0076
+#define HC_SIMA_HTX0TBC         0x0077
+#define HC_SIMA_HTX0TRAH        0x0078
+#define HC_SIMA_HTX0TBLCsat     0x0079
+#define HC_SIMA_HTX0TBLCop      0x007a
+#define HC_SIMA_HTX0TBLMPfog    0x007b
+#define HC_SIMA_HTX0TBLAsat     0x007c
+#define HC_SIMA_HTX0TBLRCa      0x007d
+#define HC_SIMA_HTX0TBLRCb      0x007e
+#define HC_SIMA_HTX0TBLRCc      0x007f
+#define HC_SIMA_HTX0TBLRCbias   0x0080
+#define HC_SIMA_HTX0TBLRAa      0x0081
+#define HC_SIMA_HTX0TBLRFog     0x0082
+#define HC_SIMA_HTX0BumpM00     0x0083
+#define HC_SIMA_HTX0BumpM01     0x0084
+#define HC_SIMA_HTX0BumpM10     0x0085
+#define HC_SIMA_HTX0BumpM11     0x0086
+#define HC_SIMA_HTX0LScale      0x0087
+/*---- end of texture 0 setting ----      0x008f
+ */
+#define HC_SIMA_TX0TX1_OFF      0x0050
+/*---- start of texture 1 setting ----
+ */
+#define HC_SIMA_HTX1L0BasL      (HC_SIMA_HTX0L0BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L1BasL      (HC_SIMA_HTX0L1BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L2BasL      (HC_SIMA_HTX0L2BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L3BasL      (HC_SIMA_HTX0L3BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L4BasL      (HC_SIMA_HTX0L4BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L5BasL      (HC_SIMA_HTX0L5BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6BasL      (HC_SIMA_HTX0L6BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L7BasL      (HC_SIMA_HTX0L7BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L8BasL      (HC_SIMA_HTX0L8BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L9BasL      (HC_SIMA_HTX0L9BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LaBasL      (HC_SIMA_HTX0LaBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LbBasL      (HC_SIMA_HTX0LbBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LcBasL      (HC_SIMA_HTX0LcBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LdBasL      (HC_SIMA_HTX0LdBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LeBasL      (HC_SIMA_HTX0LeBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LfBasL      (HC_SIMA_HTX0LfBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L10BasL     (HC_SIMA_HTX0L10BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L11BasL     (HC_SIMA_HTX0L11BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L012BasH    (HC_SIMA_HTX0L012BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L345BasH    (HC_SIMA_HTX0L345BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L678BasH    (HC_SIMA_HTX0L678BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L9abBasH    (HC_SIMA_HTX0L9abBasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LcdeBasH    (HC_SIMA_HTX0LcdeBasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1Lf1011BasH  (HC_SIMA_HTX0Lf1011BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0Pit       (HC_SIMA_HTX0L0Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L1Pit       (HC_SIMA_HTX0L1Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L2Pit       (HC_SIMA_HTX0L2Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L3Pit       (HC_SIMA_HTX0L3Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L4Pit       (HC_SIMA_HTX0L4Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L5Pit       (HC_SIMA_HTX0L5Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6Pit       (HC_SIMA_HTX0L6Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L7Pit       (HC_SIMA_HTX0L7Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L8Pit       (HC_SIMA_HTX0L8Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L9Pit       (HC_SIMA_HTX0L9Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LaPit       (HC_SIMA_HTX0LaPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LbPit       (HC_SIMA_HTX0LbPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LcPit       (HC_SIMA_HTX0LcPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LdPit       (HC_SIMA_HTX0LdPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LePit       (HC_SIMA_HTX0LePit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LfPit       (HC_SIMA_HTX0LfPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L10Pit      (HC_SIMA_HTX0L10Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L11Pit      (HC_SIMA_HTX0L11Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0_5WE      (HC_SIMA_HTX0L0_5WE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6_bWE      (HC_SIMA_HTX0L6_bWE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1Lc_11WE     (HC_SIMA_HTX0Lc_11WE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0_5HE      (HC_SIMA_HTX0L0_5HE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6_bHE      (HC_SIMA_HTX0L6_bHE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1Lc_11HE      (HC_SIMA_HTX0Lc_11HE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0OS        (HC_SIMA_HTX0L0OS + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TB          (HC_SIMA_HTX0TB + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1MPMD        (HC_SIMA_HTX0MPMD + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1CLODu       (HC_SIMA_HTX0CLODu + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1FM          (HC_SIMA_HTX0FM + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TRCH        (HC_SIMA_HTX0TRCH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TRCL        (HC_SIMA_HTX0TRCL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBC         (HC_SIMA_HTX0TBC + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TRAH        (HC_SIMA_HTX0TRAH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LTC         (HC_SIMA_HTX0LTC + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LTA         (HC_SIMA_HTX0LTA + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLCsat     (HC_SIMA_HTX0TBLCsat + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLCop      (HC_SIMA_HTX0TBLCop + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLMPfog    (HC_SIMA_HTX0TBLMPfog + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLAsat     (HC_SIMA_HTX0TBLAsat + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCa      (HC_SIMA_HTX0TBLRCa + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCb      (HC_SIMA_HTX0TBLRCb + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCc      (HC_SIMA_HTX0TBLRCc + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCbias   (HC_SIMA_HTX0TBLRCbias + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRAa      (HC_SIMA_HTX0TBLRAa + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRFog     (HC_SIMA_HTX0TBLRFog + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM00     (HC_SIMA_HTX0BumpM00 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM01     (HC_SIMA_HTX0BumpM01 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM10     (HC_SIMA_HTX0BumpM10 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM11     (HC_SIMA_HTX0BumpM11 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LScale      (HC_SIMA_HTX0LScale + HC_SIMA_TX0TX1_OFF)
+/*---- end of texture 1 setting ---- 0xaf
+ */
+#define HC_SIMA_HTXSMD          0x00b0
+#define HC_SIMA_HenFIFOAT       0x00b1
+#define HC_SIMA_HFBDrawFirst    0x00b2
+#define HC_SIMA_HFBBasL         0x00b3
+#define HC_SIMA_HTArbRCM        0x00b4
+#define HC_SIMA_HTArbRZ         0x00b5
+#define HC_SIMA_HTArbWZ         0x00b6
+#define HC_SIMA_HTArbRTX        0x00b7
+#define HC_SIMA_HTArbRCW        0x00b8
+#define HC_SIMA_HTArbE2         0x00b9
+#define HC_SIMA_HGEMITout       0x00ba
+#define HC_SIMA_HFthRTXD        0x00bb
+#define HC_SIMA_HFthRTXA        0x00bc
+/* Define the texture palette 0
+ */
+#define HC_SIMA_HTP0            0x0100
+#define HC_SIMA_HTP1            0x0200
+#define HC_SIMA_FOGTABLE        0x0300
+#define HC_SIMA_STIPPLE         0x0400
+#define HC_SIMA_HE3Fire         0x0440
+#define HC_SIMA_TRANS_SET       0x0441
+#define HC_SIMA_HREngSt         0x0442
+#define HC_SIMA_HRFIFOempty     0x0443
+#define HC_SIMA_HRFIFOfull      0x0444
+#define HC_SIMA_HRErr           0x0445
+#define HC_SIMA_FIFOstatus      0x0446
+
+/******************************************************************************
+** Define the AGP command header.
+******************************************************************************/
+#define HC_ACMD_MASK            0xfe000000
+#define HC_ACMD_SUB_MASK        0x0c000000
+#define HC_ACMD_HCmdA           0xee000000
+#define HC_ACMD_HCmdB           0xec000000
+#define HC_ACMD_HCmdC           0xea000000
+#define HC_ACMD_H1              0xf0000000
+#define HC_ACMD_H2              0xf2000000
+#define HC_ACMD_H3              0xf4000000
+#define HC_ACMD_H4              0xf6000000
+
+#define HC_ACMD_H1IO_MASK       0x000001ff
+#define HC_ACMD_H2IO1_MASK      0x001ff000
+#define HC_ACMD_H2IO2_MASK      0x000001ff
+#define HC_ACMD_H2IO1_SHIFT     12
+#define HC_ACMD_H2IO2_SHIFT     0
+#define HC_ACMD_H3IO_MASK       0x000001ff
+#define HC_ACMD_H3COUNT_MASK    0x01fff000
+#define HC_ACMD_H3COUNT_SHIFT   12
+#define HC_ACMD_H4ID_MASK       0x000001ff
+#define HC_ACMD_H4COUNT_MASK    0x01fffe00
+#define HC_ACMD_H4COUNT_SHIFT   9
+
+/********************************************************************************
+** Define Header
+********************************************************************************/
+#define HC_HEADER2		0xF210F110
+
+/********************************************************************************
+** Define Dummy Value
+********************************************************************************/
+#define HC_DUMMY		0xCCCCCCCC
+/********************************************************************************
+** Define for DMA use
+********************************************************************************/
+#define HALCYON_HEADER2     0XF210F110
+#define HALCYON_FIRECMD     0XEE100000
+#define HALCYON_FIREMASK    0XFFF00000
+#define HALCYON_CMDB        0XEC000000
+#define HALCYON_CMDBMASK    0XFFFE0000
+#define HALCYON_SUB_ADDR0   0X00000000
+#define HALCYON_HEADER1MASK 0XFFFFFC00
+#define HALCYON_HEADER1     0XF0000000
+#define HC_SubA_HAGPBstL        0x0060
+#define HC_SubA_HAGPBendL       0x0061
+#define HC_SubA_HAGPCMNT        0x0062
+#define HC_SubA_HAGPBpL         0x0063
+#define HC_SubA_HAGPBpH         0x0064
+#define HC_HAGPCMNT_MASK        0x00800000
+#define HC_HCmdErrClr_MASK      0x00400000
+#define HC_HAGPBendH_MASK       0x0000ff00
+#define HC_HAGPBstH_MASK        0x000000ff
+#define HC_HAGPBendH_SHIFT      8
+#define HC_HAGPBstH_SHIFT       0
+#define HC_HAGPBpL_MASK         0x00fffffc
+#define HC_HAGPBpID_MASK        0x00000003
+#define HC_HAGPBpID_PAUSE       0x00000000
+#define HC_HAGPBpID_JUMP        0x00000001
+#define HC_HAGPBpID_STOP        0x00000002
+#define HC_HAGPBpH_MASK         0x00ffffff
+
+
+#define VIA_VIDEO_HEADER5       0xFE040000
+#define VIA_VIDEO_HEADER6       0xFE050000
+#define VIA_VIDEO_HEADER7       0xFE060000
+#define VIA_VIDEOMASK           0xFFFF0000
+#endif
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
new file mode 100644
index 0000000..82f8394
--- /dev/null
+++ b/drivers/char/drm/via_dma.c
@@ -0,0 +1,741 @@
+/* via_dma.c -- DMA support for the VIA Unichrome/Pro
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.
+ * All Rights Reserved.
+ * 
+ * Copyright 2004 The Unichrome project.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: 
+ *    Tungsten Graphics, 
+ *    Erdi Chen, 
+ *    Thomas Hellstrom.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "via_drm.h"
+#include "via_drv.h"
+#include "via_3d_reg.h"
+
+#define CMDBUF_ALIGNMENT_SIZE   (0x100)
+#define CMDBUF_ALIGNMENT_MASK   (0x0ff)
+
+/* defines for VIA 3D registers */
+#define VIA_REG_STATUS          0x400
+#define VIA_REG_TRANSET         0x43C
+#define VIA_REG_TRANSPACE       0x440
+
+/* VIA_REG_STATUS(0x400): Engine Status */
+#define VIA_CMD_RGTR_BUSY       0x00000080	/* Command Regulator is busy */
+#define VIA_2D_ENG_BUSY         0x00000001	/* 2D Engine is busy */
+#define VIA_3D_ENG_BUSY         0x00000002	/* 3D Engine is busy */
+#define VIA_VR_QUEUE_BUSY       0x00020000	/* Virtual Queue is busy */
+
+#define SetReg2DAGP(nReg, nData) {				\
+	*((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1;	\
+	*((uint32_t *)(vb) + 1) = (nData);			\
+	vb = ((uint32_t *)vb) + 2;				\
+	dev_priv->dma_low +=8;					\
+}
+
+#define via_flush_write_combine() DRM_MEMORYBARRIER() 
+
+#define VIA_OUT_RING_QW(w1,w2)			\
+	*vb++ = (w1);				\
+	*vb++ = (w2);				\
+	dev_priv->dma_low += 8; 
+
+static void via_cmdbuf_start(drm_via_private_t * dev_priv);
+static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
+static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
+static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);
+static int via_wait_idle(drm_via_private_t * dev_priv);
+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords);
+
+
+/*
+ * Free space in command buffer.
+ */
+
+static uint32_t
+via_cmdbuf_space(drm_via_private_t *dev_priv)
+{
+	uint32_t agp_base = dev_priv->dma_offset + 
+		(uint32_t) dev_priv->agpAddr;
+	uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
+	
+	return ((hw_addr <= dev_priv->dma_low) ? 
+		(dev_priv->dma_high + hw_addr - dev_priv->dma_low) : 
+		(hw_addr - dev_priv->dma_low));
+}
+
+/*
+ * How much does the command regulator lag behind?
+ */
+
+static uint32_t
+via_cmdbuf_lag(drm_via_private_t *dev_priv)
+{
+	uint32_t agp_base = dev_priv->dma_offset + 
+		(uint32_t) dev_priv->agpAddr;
+	uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
+	
+	return ((hw_addr <= dev_priv->dma_low) ? 
+		(dev_priv->dma_low - hw_addr) : 
+		(dev_priv->dma_wrap + dev_priv->dma_low - hw_addr));
+}
+
+/*
+ * Check that the given size fits in the buffer, otherwise wait.
+ */
+
+static inline int
+via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
+{
+	uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+	uint32_t cur_addr, hw_addr, next_addr;
+	volatile uint32_t *hw_addr_ptr;
+	uint32_t count;
+	hw_addr_ptr = dev_priv->hw_addr_ptr;
+	cur_addr = dev_priv->dma_low;
+	next_addr = cur_addr + size + 512*1024;
+	count = 1000000;
+	do {
+	        hw_addr = *hw_addr_ptr - agp_base;
+		if (count-- == 0) {
+			DRM_ERROR("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",
+				  hw_addr, cur_addr, next_addr);
+			return -1;
+		}
+	} while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
+	return 0;
+}
+
+
+/*
+ * Checks whether buffer head has reach the end. Rewind the ring buffer
+ * when necessary.
+ *
+ * Returns virtual pointer to ring buffer.
+ */
+
+static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
+				      unsigned int size)
+{
+	if ((dev_priv->dma_low + size + 4*CMDBUF_ALIGNMENT_SIZE) > dev_priv->dma_high) {
+		via_cmdbuf_rewind(dev_priv);
+	}
+	if (via_cmdbuf_wait(dev_priv, size) != 0) {
+		return NULL;
+	}
+
+	return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
+}
+
+int via_dma_cleanup(drm_device_t * dev)
+{
+	if (dev->dev_private) {
+		drm_via_private_t *dev_priv =
+			(drm_via_private_t *) dev->dev_private;
+
+		if (dev_priv->ring.virtual_start) {
+			via_cmdbuf_reset(dev_priv);
+
+			drm_core_ioremapfree(&dev_priv->ring.map, dev);
+			dev_priv->ring.virtual_start = NULL;
+		}
+
+	}
+
+	return 0;
+}
+
+static int via_initialize(drm_device_t * dev,
+			  drm_via_private_t * dev_priv,
+			  drm_via_dma_init_t * init)
+{
+	if (!dev_priv || !dev_priv->mmio) {
+		DRM_ERROR("via_dma_init called before via_map_init\n");
+		return DRM_ERR(EFAULT);
+	}
+
+	if (dev_priv->ring.virtual_start != NULL) {
+		DRM_ERROR("%s called again without calling cleanup\n",
+			  __FUNCTION__);
+		return DRM_ERR(EFAULT);
+	}
+
+	if (!dev->agp || !dev->agp->base) {
+		DRM_ERROR("%s called with no agp memory available\n", 
+			  __FUNCTION__);
+		return DRM_ERR(EFAULT);
+	}
+
+	dev_priv->ring.map.offset = dev->agp->base + init->offset;
+	dev_priv->ring.map.size = init->size;
+	dev_priv->ring.map.type = 0;
+	dev_priv->ring.map.flags = 0;
+	dev_priv->ring.map.mtrr = 0;
+
+	drm_core_ioremap(&dev_priv->ring.map, dev);
+
+	if (dev_priv->ring.map.handle == NULL) {
+		via_dma_cleanup(dev);
+		DRM_ERROR("can not ioremap virtual address for"
+			  " ring buffer\n");
+		return DRM_ERR(ENOMEM);
+	}
+
+	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
+	dev_priv->dma_ptr = dev_priv->ring.virtual_start;
+	dev_priv->dma_low = 0;
+	dev_priv->dma_high = init->size;
+	dev_priv->dma_wrap = init->size;
+	dev_priv->dma_offset = init->offset;
+	dev_priv->last_pause_ptr = NULL;
+	dev_priv->hw_addr_ptr = dev_priv->mmio->handle + init->reg_pause_addr;
+
+	via_cmdbuf_start(dev_priv);
+
+	return 0;
+}
+
+int via_dma_init(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	drm_via_dma_init_t init;
+	int retcode = 0;
+
+	DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t *) data,
+				 sizeof(init));
+
+	switch (init.func) {
+	case VIA_INIT_DMA:
+		if (!capable(CAP_SYS_ADMIN))
+			retcode = DRM_ERR(EPERM);
+		else
+			retcode = via_initialize(dev, dev_priv, &init);
+		break;
+	case VIA_CLEANUP_DMA:
+		if (!capable(CAP_SYS_ADMIN))
+			retcode = DRM_ERR(EPERM);
+		else
+			retcode = via_dma_cleanup(dev);
+		break;
+        case VIA_DMA_INITIALIZED:
+		retcode = (dev_priv->ring.virtual_start != NULL) ? 
+			0: DRM_ERR( EFAULT );
+	        break;
+	default:
+		retcode = DRM_ERR(EINVAL);
+		break;
+	}
+
+	return retcode;
+}
+
+
+
+static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
+{
+	drm_via_private_t *dev_priv;
+	uint32_t *vb;
+	int ret;
+
+	dev_priv = (drm_via_private_t *) dev->dev_private;
+
+	if (dev_priv->ring.virtual_start == NULL) {
+		DRM_ERROR("%s called without initializing AGP ring buffer.\n",
+			  __FUNCTION__);
+		return DRM_ERR(EFAULT);
+	}
+
+	if (cmd->size > VIA_PCI_BUF_SIZE) {
+		return DRM_ERR(ENOMEM);
+	} 
+
+
+	if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
+		return DRM_ERR(EFAULT);
+
+	/*
+	 * Running this function on AGP memory is dead slow. Therefore
+	 * we run it on a temporary cacheable system memory buffer and
+	 * copy it to AGP memory when ready.
+	 */
+
+		
+	if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 1))) {
+		return ret;
+	}
+       	
+	
+	vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
+	if (vb == NULL) {
+		return DRM_ERR(EAGAIN);
+	}
+
+	memcpy(vb, dev_priv->pci_buf, cmd->size);
+	
+	dev_priv->dma_low += cmd->size;
+
+	/*
+	 * Small submissions somehow stalls the CPU. (AGP cache effects?)
+	 * pad to greater size.
+	 */
+
+	if (cmd->size < 0x100)
+	  via_pad_cache(dev_priv,(0x100 - cmd->size) >> 3);
+	via_cmdbuf_pause(dev_priv);
+
+	return 0;
+}
+
+int via_driver_dma_quiescent(drm_device_t * dev)
+{
+	drm_via_private_t *dev_priv = dev->dev_private;
+
+	if (!via_wait_idle(dev_priv)) {
+		return DRM_ERR(EBUSY);
+	}
+	return 0;
+}
+
+int via_flush_ioctl(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+
+	LOCK_TEST_WITH_RETURN( dev, filp );
+
+	return via_driver_dma_quiescent(dev);
+}
+
+int via_cmdbuffer(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_via_cmdbuffer_t cmdbuf;
+	int ret;
+
+	LOCK_TEST_WITH_RETURN( dev, filp );
+
+	DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data,
+				 sizeof(cmdbuf));
+
+	DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
+
+	ret = via_dispatch_cmdbuffer(dev, &cmdbuf);
+	if (ret) {
+		return ret;
+	}
+
+	return 0;
+}
+
+extern int 
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size);
+static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
+				      drm_via_cmdbuffer_t * cmd)
+{
+	drm_via_private_t *dev_priv = dev->dev_private;
+	int ret;
+
+	if (cmd->size > VIA_PCI_BUF_SIZE) {
+		return DRM_ERR(ENOMEM);
+	} 
+	if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
+		return DRM_ERR(EFAULT);
+	
+	if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 0))) {
+		return ret;
+	}
+	
+	ret = via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, cmd->size);
+	return ret;
+}
+
+int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_via_cmdbuffer_t cmdbuf;
+	int ret;
+
+	LOCK_TEST_WITH_RETURN( dev, filp );
+
+	DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data,
+				 sizeof(cmdbuf));
+
+	DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,
+		  cmdbuf.size);
+
+	ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);
+	if (ret) {
+		return ret;
+	}
+
+	return 0;
+}
+
+
+static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
+					 uint32_t * vb, int qw_count)
+{
+        for (; qw_count > 0; --qw_count) {
+		VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
+	}
+	return vb;
+}
+
+
+/*
+ * This function is used internally by ring buffer mangement code.
+ *
+ * Returns virtual pointer to ring buffer.
+ */
+static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)
+{
+	return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
+}
+
+/*
+ * Hooks a segment of data into the tail of the ring-buffer by
+ * modifying the pause address stored in the buffer itself. If
+ * the regulator has already paused, restart it.
+ */
+static int via_hook_segment(drm_via_private_t *dev_priv,
+			    uint32_t pause_addr_hi, uint32_t pause_addr_lo,
+			    int no_pci_fire)
+{
+	int paused, count;
+	volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
+
+	via_flush_write_combine();
+	while(! *(via_get_dma(dev_priv)-1));
+	*dev_priv->last_pause_ptr = pause_addr_lo;
+	via_flush_write_combine();
+
+	/*
+	 * The below statement is inserted to really force the flush.
+	 * Not sure it is needed.
+	 */
+
+	while(! *dev_priv->last_pause_ptr);
+	dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
+	while(! *dev_priv->last_pause_ptr);
+
+
+	paused = 0;
+	count = 20; 
+
+	while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
+	if ((count <= 8) && (count >= 0)) {
+		uint32_t rgtr, ptr;
+		rgtr = *(dev_priv->hw_addr_ptr);
+		ptr = ((char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + 
+			dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4 - 
+			CMDBUF_ALIGNMENT_SIZE;
+		if (rgtr <= ptr) {
+			DRM_ERROR("Command regulator\npaused at count %d, address %x, "
+				  "while current pause address is %x.\n"
+				  "Please mail this message to "
+				  "<unichrome-devel@lists.sourceforge.net>\n",
+				  count, rgtr, ptr);
+		}
+	}
+		
+	if (paused && !no_pci_fire) {
+	        uint32_t rgtr,ptr;
+		uint32_t ptr_low;
+
+		count = 1000000;
+		while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) && count--);
+		
+		rgtr = *(dev_priv->hw_addr_ptr);
+		ptr = ((char *)paused_at - dev_priv->dma_ptr) + 
+			dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
+		
+
+		ptr_low = (ptr > 3*CMDBUF_ALIGNMENT_SIZE) ? 
+			ptr - 3*CMDBUF_ALIGNMENT_SIZE : 0;
+		if (rgtr <= ptr && rgtr >= ptr_low) {
+			VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
+			VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
+			VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+		} 
+	}
+	return paused;
+}
+
+
+
+static int via_wait_idle(drm_via_private_t * dev_priv)
+{
+	int count = 10000000;
+	while (count-- && (VIA_READ(VIA_REG_STATUS) &
+			   (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
+			    VIA_3D_ENG_BUSY))) ;
+	return count;
+}
+
+static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,
+			       uint32_t addr, uint32_t *cmd_addr_hi, 
+			       uint32_t *cmd_addr_lo,
+			       int skip_wait)
+{
+	uint32_t agp_base;
+	uint32_t cmd_addr, addr_lo, addr_hi;
+	uint32_t *vb;
+	uint32_t qw_pad_count;
+
+	if (!skip_wait)
+		via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE);
+
+	vb = via_get_dma(dev_priv);
+	VIA_OUT_RING_QW( HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
+			 (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16); 
+	agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+	qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -
+		((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
+
+	
+	cmd_addr = (addr) ? addr : 
+		agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);
+	addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) |
+		   (cmd_addr & HC_HAGPBpL_MASK));
+	addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));
+
+	vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);
+	VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, 
+			*cmd_addr_lo = addr_lo);
+	return vb;
+}
+
+
+
+
+static void via_cmdbuf_start(drm_via_private_t * dev_priv)
+{
+	uint32_t pause_addr_lo, pause_addr_hi;
+	uint32_t start_addr, start_addr_lo;
+	uint32_t end_addr, end_addr_lo;
+	uint32_t command;
+	uint32_t agp_base;
+
+
+	dev_priv->dma_low = 0;
+
+	agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+	start_addr = agp_base;
+	end_addr = agp_base + dev_priv->dma_high;
+
+	start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
+	end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
+	command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
+		   ((end_addr & 0xff000000) >> 16));
+
+	dev_priv->last_pause_ptr = 
+		via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, 
+			      &pause_addr_hi, & pause_addr_lo, 1) - 1;
+
+	via_flush_write_combine();
+	while(! *dev_priv->last_pause_ptr);
+
+	VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
+	VIA_WRITE(VIA_REG_TRANSPACE, command);
+	VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo);
+	VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo);
+
+	VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
+	VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+
+	VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+}
+
+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords)
+{
+	uint32_t *vb;
+
+	via_cmdbuf_wait(dev_priv, qwords + 2);
+	vb = via_get_dma(dev_priv);
+	VIA_OUT_RING_QW( HC_HEADER2, HC_ParaType_NotTex << 16);
+	via_align_buffer(dev_priv,vb,qwords);
+}
+
+static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)
+{
+	uint32_t *vb = via_get_dma(dev_priv);
+	SetReg2DAGP(0x0C, (0 | (0 << 16)));
+	SetReg2DAGP(0x10, 0 | (0 << 16));
+	SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); 
+}
+
+
+static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
+{
+	uint32_t agp_base;
+	uint32_t pause_addr_lo, pause_addr_hi;
+	uint32_t jump_addr_lo, jump_addr_hi;
+	volatile uint32_t *last_pause_ptr;
+	uint32_t dma_low_save1, dma_low_save2;
+
+	agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+	via_align_cmd(dev_priv,  HC_HAGPBpID_JUMP, 0, &jump_addr_hi, 
+		      &jump_addr_lo, 0);
+	
+	dev_priv->dma_wrap = dev_priv->dma_low;
+
+
+	/*
+	 * Wrap command buffer to the beginning.
+	 */
+
+	dev_priv->dma_low = 0;
+	if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) {
+		DRM_ERROR("via_cmdbuf_jump failed\n");
+	}
+
+	via_dummy_bitblt(dev_priv);
+	via_dummy_bitblt(dev_priv); 
+
+	last_pause_ptr = via_align_cmd(dev_priv,  HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 
+				       &pause_addr_lo, 0) -1;
+	via_align_cmd(dev_priv,  HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 
+		      &pause_addr_lo, 0);
+
+	*last_pause_ptr = pause_addr_lo;
+	dma_low_save1 = dev_priv->dma_low;
+
+	/*
+	 * Now, set a trap that will pause the regulator if it tries to rerun the old
+	 * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
+	 * and reissues the jump command over PCI, while the regulator has already taken the jump
+	 * and actually paused at the current buffer end).
+	 * There appears to be no other way to detect this condition, since the hw_addr_pointer
+	 * does not seem to get updated immediately when a jump occurs.
+	 */
+
+	last_pause_ptr = via_align_cmd(dev_priv,  HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 
+				       &pause_addr_lo, 0) -1;
+	via_align_cmd(dev_priv,  HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, 
+		      &pause_addr_lo, 0);
+	*last_pause_ptr = pause_addr_lo;
+
+	dma_low_save2 = dev_priv->dma_low;
+	dev_priv->dma_low = dma_low_save1;	
+	via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
+	dev_priv->dma_low = dma_low_save2;
+	via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);
+}
+
+
+static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
+{
+	via_cmdbuf_jump(dev_priv); 
+}
+
+static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
+{
+	uint32_t pause_addr_lo, pause_addr_hi;
+
+	via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);
+	via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);
+}
+
+
+static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
+{
+	via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
+}
+
+static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
+{
+	via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
+	via_wait_idle(dev_priv);
+}
+
+/*
+ * User interface to the space and lag functions.
+ */
+
+int 
+via_cmdbuf_size(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_via_cmdbuf_size_t d_siz;
+	int ret = 0;
+	uint32_t tmp_size, count;
+	drm_via_private_t *dev_priv;
+
+	DRM_DEBUG("via cmdbuf_size\n");
+	LOCK_TEST_WITH_RETURN( dev, filp );
+
+	dev_priv = (drm_via_private_t *) dev->dev_private;
+
+	if (dev_priv->ring.virtual_start == NULL) {
+		DRM_ERROR("%s called without initializing AGP ring buffer.\n",
+			  __FUNCTION__);
+		return DRM_ERR(EFAULT);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t *) data,
+				 sizeof(d_siz));
+
+
+	count = 1000000;
+	tmp_size = d_siz.size;
+	switch(d_siz.func) {
+	case VIA_CMDBUF_SPACE:
+		while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size) && count--) {
+			if (!d_siz.wait) {
+				break;
+			}
+		}
+		if (!count) {
+			DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
+			ret = DRM_ERR(EAGAIN);
+		}
+		break;
+	case VIA_CMDBUF_LAG:
+		while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size) && count--) {
+			if (!d_siz.wait) {
+				break;
+			}
+		}
+		if (!count) {
+			DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
+			ret = DRM_ERR(EAGAIN);
+		}
+		break;
+	default:
+		ret = DRM_ERR(EFAULT);
+	}
+	d_siz.size = tmp_size;
+
+	DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t *) data, d_siz,
+			       sizeof(d_siz));
+	return ret;
+}
diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h
new file mode 100644
index 0000000..4588c9b
--- /dev/null
+++ b/drivers/char/drm/via_drm.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _VIA_DRM_H_
+#define _VIA_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+#ifndef _VIA_DEFINES_
+#define _VIA_DEFINES_
+
+#ifndef __KERNEL__
+#include "via_drmclient.h"
+#endif
+
+#define VIA_NR_SAREA_CLIPRECTS 		8
+#define VIA_NR_XVMC_PORTS               10
+#define VIA_NR_XVMC_LOCKS               5
+#define VIA_MAX_CACHELINE_SIZE          64
+#define XVMCLOCKPTR(saPriv,lockNo)					\
+	((volatile drm_hw_lock_t *)(((((unsigned long) (saPriv)->XvMCLockArea) + \
+				      (VIA_MAX_CACHELINE_SIZE - 1)) &	\
+				     ~(VIA_MAX_CACHELINE_SIZE - 1)) +	\
+				    VIA_MAX_CACHELINE_SIZE*(lockNo)))
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define VIA_NR_TEX_REGIONS 64
+#define VIA_LOG_MIN_TEX_REGION_SIZE 16
+#endif
+
+#define VIA_UPLOAD_TEX0IMAGE  0x1	/* handled clientside */
+#define VIA_UPLOAD_TEX1IMAGE  0x2	/* handled clientside */
+#define VIA_UPLOAD_CTX        0x4
+#define VIA_UPLOAD_BUFFERS    0x8
+#define VIA_UPLOAD_TEX0       0x10
+#define VIA_UPLOAD_TEX1       0x20
+#define VIA_UPLOAD_CLIPRECTS  0x40
+#define VIA_UPLOAD_ALL        0xff
+
+/* VIA specific ioctls */
+#define DRM_VIA_ALLOCMEM	0x00
+#define DRM_VIA_FREEMEM	        0x01
+#define DRM_VIA_AGP_INIT	0x02
+#define DRM_VIA_FB_INIT	        0x03
+#define DRM_VIA_MAP_INIT	0x04
+#define DRM_VIA_DEC_FUTEX       0x05
+#define NOT_USED
+#define DRM_VIA_DMA_INIT	0x07
+#define DRM_VIA_CMDBUFFER	0x08
+#define DRM_VIA_FLUSH	        0x09
+#define DRM_VIA_PCICMD	        0x0a
+#define DRM_VIA_CMDBUF_SIZE	0x0b
+#define NOT_USED
+#define DRM_VIA_WAIT_IRQ        0x0d
+
+#define DRM_IOCTL_VIA_ALLOCMEM	  DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t)
+#define DRM_IOCTL_VIA_FREEMEM	  DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t)
+#define DRM_IOCTL_VIA_AGP_INIT	  DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_AGP_INIT, drm_via_agp_t)
+#define DRM_IOCTL_VIA_FB_INIT	  DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t)
+#define DRM_IOCTL_VIA_MAP_INIT	  DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t)
+#define DRM_IOCTL_VIA_DEC_FUTEX   DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t)
+#define DRM_IOCTL_VIA_DMA_INIT	  DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t)
+#define DRM_IOCTL_VIA_CMDBUFFER	  DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t)
+#define DRM_IOCTL_VIA_FLUSH	  DRM_IO(  DRM_COMMAND_BASE + DRM_VIA_FLUSH)
+#define DRM_IOCTL_VIA_PCICMD	  DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t)
+#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \
+					    drm_via_cmdbuf_size_t)
+#define DRM_IOCTL_VIA_WAIT_IRQ    DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t)
+
+/* Indices into buf.Setup where various bits of state are mirrored per
+ * context and per buffer.  These can be fired at the card as a unit,
+ * or in a piecewise fashion as required.
+ */
+
+#define VIA_TEX_SETUP_SIZE 8
+
+/* Flags for clear ioctl
+ */
+#define VIA_FRONT   0x1
+#define VIA_BACK    0x2
+#define VIA_DEPTH   0x4
+#define VIA_STENCIL 0x8
+#define VIDEO 0
+#define AGP 1
+typedef struct {
+	uint32_t offset;
+	uint32_t size;
+} drm_via_agp_t;
+
+typedef struct {
+	uint32_t offset;
+	uint32_t size;
+} drm_via_fb_t;
+
+typedef struct {
+	uint32_t context;
+	uint32_t type;
+	uint32_t size;
+	unsigned long index;
+	unsigned long offset;
+} drm_via_mem_t;
+
+typedef struct _drm_via_init {
+	enum {
+		VIA_INIT_MAP = 0x01,
+		VIA_CLEANUP_MAP = 0x02
+	} func;
+
+	unsigned long sarea_priv_offset;
+	unsigned long fb_offset;
+	unsigned long mmio_offset;
+	unsigned long agpAddr;
+} drm_via_init_t;
+
+typedef struct _drm_via_futex {
+	enum {
+		VIA_FUTEX_WAIT = 0x00,
+		VIA_FUTEX_WAKE = 0X01
+	} func;
+	uint32_t ms;
+	uint32_t lock;
+	uint32_t val;
+} drm_via_futex_t;
+
+typedef struct _drm_via_dma_init {
+	enum {
+		VIA_INIT_DMA = 0x01,
+		VIA_CLEANUP_DMA = 0x02,
+                VIA_DMA_INITIALIZED = 0x03
+	} func;
+
+	unsigned long offset;
+	unsigned long size;
+	unsigned long reg_pause_addr;
+} drm_via_dma_init_t;
+
+typedef struct _drm_via_cmdbuffer {
+	char *buf;
+	unsigned long size;
+} drm_via_cmdbuffer_t;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_via_tex_region {
+	unsigned char next, prev;	/* indices to form a circular LRU  */
+	unsigned char inUse;	/* owned by a client, or free? */
+	int age;		/* tracked by clients to update local LRU's */
+} drm_via_tex_region_t;
+
+typedef struct _drm_via_sarea {
+	unsigned int dirty;
+	unsigned int nbox;
+	drm_clip_rect_t boxes[VIA_NR_SAREA_CLIPRECTS];
+	drm_via_tex_region_t texList[VIA_NR_TEX_REGIONS + 1];
+	int texAge;		/* last time texture was uploaded */
+	int ctxOwner;		/* last context to upload state */
+	int vertexPrim;
+
+	/*
+	 * Below is for XvMC.
+	 * We want the lock integers alone on, and aligned to, a cache line.
+	 * Therefore this somewhat strange construct.
+	 */
+
+	char XvMCLockArea[VIA_MAX_CACHELINE_SIZE * (VIA_NR_XVMC_LOCKS + 1)];
+
+	unsigned int XvMCDisplaying[VIA_NR_XVMC_PORTS];
+	unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS];
+	unsigned int XvMCCtxNoGrabbed;	/* Last context to hold decoder */
+
+} drm_via_sarea_t;
+
+typedef struct _drm_via_cmdbuf_size {
+	enum {
+		VIA_CMDBUF_SPACE = 0x01,
+		VIA_CMDBUF_LAG = 0x02
+	} func;
+	int wait;
+	uint32_t size;
+} drm_via_cmdbuf_size_t;
+
+typedef enum {
+	VIA_IRQ_ABSOLUTE = 0x0,
+	VIA_IRQ_RELATIVE = 0x1,
+	VIA_IRQ_SIGNAL = 0x10000000,
+	VIA_IRQ_FORCE_SEQUENCE = 0x20000000
+} via_irq_seq_type_t;
+
+#define VIA_IRQ_FLAGS_MASK 0xF0000000
+
+struct drm_via_wait_irq_request{
+	unsigned irq;
+	via_irq_seq_type_t type;
+	uint32_t sequence;
+	uint32_t signal;
+};
+
+typedef union drm_via_irqwait {
+	struct drm_via_wait_irq_request request;
+	struct drm_wait_vblank_reply reply;
+} drm_via_irqwait_t;
+
+#ifdef __KERNEL__
+
+int via_fb_init(DRM_IOCTL_ARGS);
+int via_mem_alloc(DRM_IOCTL_ARGS);
+int via_mem_free(DRM_IOCTL_ARGS);
+int via_agp_init(DRM_IOCTL_ARGS);
+int via_map_init(DRM_IOCTL_ARGS);
+int via_decoder_futex(DRM_IOCTL_ARGS);
+int via_dma_init(DRM_IOCTL_ARGS);
+int via_cmdbuffer(DRM_IOCTL_ARGS);
+int via_flush_ioctl(DRM_IOCTL_ARGS);
+int via_pci_cmdbuffer(DRM_IOCTL_ARGS);
+int via_cmdbuf_size(DRM_IOCTL_ARGS);
+int via_wait_irq(DRM_IOCTL_ARGS);
+
+#endif
+#endif				/* _VIA_DRM_H_ */
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
new file mode 100644
index 0000000..275eefc
--- /dev/null
+++ b/drivers/char/drm/via_drv.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+#include "drm_pciids.h"
+
+static int postinit(struct drm_device *dev, unsigned long flags)
+{
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n",
+		 DRIVER_NAME,
+		 DRIVER_MAJOR,
+		 DRIVER_MINOR,
+		 DRIVER_PATCHLEVEL,
+		 DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev)
+	    );
+	return 0;
+}
+
+static int version(drm_version_t * version)
+{
+	int len;
+
+	version->version_major = DRIVER_MAJOR;
+	version->version_minor = DRIVER_MINOR;
+	version->version_patchlevel = DRIVER_PATCHLEVEL;
+	DRM_COPY(version->name, DRIVER_NAME);
+	DRM_COPY(version->date, DRIVER_DATE);
+	DRM_COPY(version->desc, DRIVER_DESC);
+	return 0;
+}
+
+static struct pci_device_id pciidlist[] = {
+	viadrv_PCI_IDS
+};
+
+static drm_ioctl_desc_t ioctls[] = {
+	[DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0},
+	[DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0}
+};
+
+static struct drm_driver driver = {
+	.driver_features =
+	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
+	    DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+	.context_ctor = via_init_context,
+	.context_dtor = via_final_context,
+	.vblank_wait = via_driver_vblank_wait,
+	.irq_preinstall = via_driver_irq_preinstall,
+	.irq_postinstall = via_driver_irq_postinstall,
+	.irq_uninstall = via_driver_irq_uninstall,
+	.irq_handler = via_driver_irq_handler,
+	.dma_quiescent = via_driver_dma_quiescent,
+	.reclaim_buffers = drm_core_reclaim_buffers,
+	.get_map_ofs = drm_core_get_map_ofs,
+	.get_reg_ofs = drm_core_get_reg_ofs,
+	.postinit = postinit,
+	.version = version,
+	.ioctls = ioctls,
+	.num_ioctls = DRM_ARRAY_SIZE(ioctls),
+	.fops = {
+		.owner = THIS_MODULE,
+		.open = drm_open,
+		.release = drm_release,
+		.ioctl = drm_ioctl,
+		.mmap = drm_mmap,
+		.poll = drm_poll,
+		.fasync = drm_fasync,
+		},
+	.pci_driver = {
+		.name = DRIVER_NAME,
+		.id_table = pciidlist,
+	}
+};
+
+static int __init via_init(void)
+{
+	via_init_command_verifier();
+	return drm_init(&driver);
+}
+
+static void __exit via_exit(void)
+{
+	drm_exit(&driver);
+}
+
+module_init(via_init);
+module_exit(via_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
new file mode 100644
index 0000000..4eaa8b7
--- /dev/null
+++ b/drivers/char/drm/via_drv.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _VIA_DRV_H_
+#define _VIA_DRV_H_
+
+#define DRIVER_AUTHOR	"VIA"
+
+#define DRIVER_NAME		"via"
+#define DRIVER_DESC		"VIA Unichrome / Pro"
+#define DRIVER_DATE		"20050523"
+
+#define DRIVER_MAJOR		2
+#define DRIVER_MINOR		6
+#define DRIVER_PATCHLEVEL	3
+
+#include "via_verifier.h"
+
+#define VIA_PCI_BUF_SIZE 60000
+#define VIA_FIRE_BUF_SIZE  1024
+#define VIA_NUM_IRQS 2
+
+
+
+typedef struct drm_via_ring_buffer {
+	drm_map_t map;
+	char *virtual_start;
+} drm_via_ring_buffer_t;
+
+typedef uint32_t maskarray_t[5];
+
+typedef struct drm_via_irq {
+	atomic_t irq_received;
+	uint32_t pending_mask;
+	uint32_t enable_mask;
+	wait_queue_head_t irq_queue;
+} drm_via_irq_t;
+	
+typedef struct drm_via_private {
+	drm_via_sarea_t *sarea_priv;
+	drm_map_t *sarea;
+	drm_map_t *fb;
+	drm_map_t *mmio;
+	unsigned long agpAddr;
+	wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];
+	char *dma_ptr;
+	unsigned int dma_low;
+	unsigned int dma_high;
+	unsigned int dma_offset;
+	uint32_t dma_wrap;
+	volatile uint32_t *last_pause_ptr;
+	volatile uint32_t *hw_addr_ptr;
+	drm_via_ring_buffer_t ring;
+        struct timeval last_vblank;
+        int last_vblank_valid;
+        unsigned usec_per_vblank;
+	drm_via_state_t hc_state;
+	char pci_buf[VIA_PCI_BUF_SIZE];
+	const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
+	uint32_t num_fire_offsets;
+	int pro_group_a;
+	drm_via_irq_t via_irqs[VIA_NUM_IRQS];
+	unsigned num_irqs;
+	maskarray_t *irq_masks;
+	uint32_t irq_enable_mask; 
+	uint32_t irq_pending_mask;	
+} drm_via_private_t;
+
+/* VIA MMIO register access */
+#define VIA_BASE ((dev_priv->mmio))
+
+#define VIA_READ(reg)		DRM_READ32(VIA_BASE, reg)
+#define VIA_WRITE(reg,val)	DRM_WRITE32(VIA_BASE, reg, val)
+#define VIA_READ8(reg)		DRM_READ8(VIA_BASE, reg)
+#define VIA_WRITE8(reg,val)	DRM_WRITE8(VIA_BASE, reg, val)
+
+extern int via_init_context(drm_device_t * dev, int context);
+extern int via_final_context(drm_device_t * dev, int context);
+
+extern int via_do_cleanup_map(drm_device_t * dev);
+extern int via_map_init(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+
+extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
+extern void via_driver_irq_preinstall(drm_device_t * dev);
+extern void via_driver_irq_postinstall(drm_device_t * dev);
+extern void via_driver_irq_uninstall(drm_device_t * dev);
+
+extern int via_dma_cleanup(drm_device_t * dev);
+extern void via_init_command_verifier(void);
+extern int via_driver_dma_quiescent(drm_device_t * dev);
+extern void via_init_futex(drm_via_private_t *dev_priv);
+extern void via_cleanup_futex(drm_via_private_t *dev_priv);
+extern void via_release_futex(drm_via_private_t *dev_priv, int context);
+
+
+#endif
diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c
new file mode 100644
index 0000000..daf3df7
--- /dev/null
+++ b/drivers/char/drm/via_ds.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "via_ds.h"
+extern unsigned int VIA_DEBUG;
+
+set_t *via_setInit(void)
+{
+	int i;
+	set_t *set;
+	set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
+	for (i = 0; i < SET_SIZE; i++) {
+		set->list[i].free_next = i + 1;
+		set->list[i].alloc_next = -1;
+	}
+	set->list[SET_SIZE - 1].free_next = -1;
+	set->free = 0;
+	set->alloc = -1;
+	set->trace = -1;
+	return set;
+}
+
+int via_setAdd(set_t * set, ITEM_TYPE item)
+{
+	int free = set->free;
+	if (free != -1) {
+		set->list[free].val = item;
+		set->free = set->list[free].free_next;
+	} else {
+		return 0;
+	}
+	set->list[free].alloc_next = set->alloc;
+	set->alloc = free;
+	set->list[free].free_next = -1;
+	return 1;
+}
+
+int via_setDel(set_t * set, ITEM_TYPE item)
+{
+	int alloc = set->alloc;
+	int prev = -1;
+
+	while (alloc != -1) {
+		if (set->list[alloc].val == item) {
+			if (prev != -1)
+				set->list[prev].alloc_next =
+				    set->list[alloc].alloc_next;
+			else
+				set->alloc = set->list[alloc].alloc_next;
+			break;
+		}
+		prev = alloc;
+		alloc = set->list[alloc].alloc_next;
+	}
+
+	if (alloc == -1)
+		return 0;
+
+	set->list[alloc].free_next = set->free;
+	set->free = alloc;
+	set->list[alloc].alloc_next = -1;
+
+	return 1;
+}
+
+/* setFirst -> setAdd -> setNext is wrong */
+
+int via_setFirst(set_t * set, ITEM_TYPE * item)
+{
+	if (set->alloc == -1)
+		return 0;
+
+	*item = set->list[set->alloc].val;
+	set->trace = set->list[set->alloc].alloc_next;
+
+	return 1;
+}
+
+int via_setNext(set_t * set, ITEM_TYPE * item)
+{
+	if (set->trace == -1)
+		return 0;
+
+	*item = set->list[set->trace].val;
+	set->trace = set->list[set->trace].alloc_next;
+
+	return 1;
+}
+
+int via_setDestroy(set_t * set)
+{
+	drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
+
+	return 1;
+}
+
+#define ISFREE(bptr) ((bptr)->free)
+
+#define fprintf(fmt, arg...) do{}while(0)
+
+memHeap_t *via_mmInit(int ofs, int size)
+{
+	PMemBlock blocks;
+
+	if (size <= 0)
+		return 0;
+
+	blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
+
+	if (blocks) {
+		blocks->ofs = ofs;
+		blocks->size = size;
+		blocks->free = 1;
+		return (memHeap_t *) blocks;
+	} else
+		return 0;
+}
+
+static TMemBlock *SliceBlock(TMemBlock * p,
+			     int startofs, int size,
+			     int reserved, int alignment)
+{
+	TMemBlock *newblock;
+
+	/* break left */
+	if (startofs > p->ofs) {
+		newblock =
+		    (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
+					     DRM_MEM_DRIVER);
+		newblock->ofs = startofs;
+		newblock->size = p->size - (startofs - p->ofs);
+		newblock->free = 1;
+		newblock->next = p->next;
+		p->size -= newblock->size;
+		p->next = newblock;
+		p = newblock;
+	}
+
+	/* break right */
+	if (size < p->size) {
+		newblock =
+		    (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
+					     DRM_MEM_DRIVER);
+		newblock->ofs = startofs + size;
+		newblock->size = p->size - size;
+		newblock->free = 1;
+		newblock->next = p->next;
+		p->size = size;
+		p->next = newblock;
+	}
+
+	/* p = middle block */
+	p->align = alignment;
+	p->free = 0;
+	p->reserved = reserved;
+	return p;
+}
+
+PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
+			 int startSearch)
+{
+	int mask, startofs, endofs;
+	TMemBlock *p;
+
+	if (!heap || align2 < 0 || size <= 0)
+		return NULL;
+
+	mask = (1 << align2) - 1;
+	startofs = 0;
+	p = (TMemBlock *) heap;
+
+	while (p) {
+		if (ISFREE(p)) {
+			startofs = (p->ofs + mask) & ~mask;
+
+			if (startofs < startSearch)
+				startofs = startSearch;
+
+			endofs = startofs + size;
+
+			if (endofs <= (p->ofs + p->size))
+				break;
+		}
+
+		p = p->next;
+	}
+
+	if (!p)
+		return NULL;
+
+	p = SliceBlock(p, startofs, size, 0, mask + 1);
+	p->heap = heap;
+
+	return p;
+}
+
+static __inline__ int Join2Blocks(TMemBlock * p)
+{
+	if (p->free && p->next && p->next->free) {
+		TMemBlock *q = p->next;
+		p->size += q->size;
+		p->next = q->next;
+		drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+int via_mmFreeMem(PMemBlock b)
+{
+	TMemBlock *p, *prev;
+
+	if (!b)
+		return 0;
+
+	if (!b->heap) {
+		fprintf(stderr, "no heap\n");
+
+		return -1;
+	}
+
+	p = b->heap;
+	prev = NULL;
+
+	while (p && p != b) {
+		prev = p;
+		p = p->next;
+	}
+
+	if (!p || p->free || p->reserved) {
+		if (!p)
+			fprintf(stderr, "block not found in heap\n");
+		else if (p->free)
+			fprintf(stderr, "block already free\n");
+		else
+			fprintf(stderr, "block is reserved\n");
+
+		return -1;
+	}
+
+	p->free = 1;
+	Join2Blocks(p);
+
+	if (prev)
+		Join2Blocks(prev);
+
+	return 0;
+}
diff --git a/drivers/char/drm/via_ds.h b/drivers/char/drm/via_ds.h
new file mode 100644
index 0000000..be9c7f9
--- /dev/null
+++ b/drivers/char/drm/via_ds.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _via_ds_h_
+#define _via_ds_h_
+
+#include "drmP.h"
+
+/* Set Data Structure */
+#define SET_SIZE 5000
+typedef unsigned long ITEM_TYPE;
+
+typedef struct {
+	ITEM_TYPE val;
+	int alloc_next, free_next;
+} list_item_t;
+
+typedef struct {
+	int alloc;
+	int free;
+	int trace;
+	list_item_t list[SET_SIZE];
+} set_t;
+
+set_t *via_setInit(void);
+int via_setAdd(set_t * set, ITEM_TYPE item);
+int via_setDel(set_t * set, ITEM_TYPE item);
+int via_setFirst(set_t * set, ITEM_TYPE * item);
+int via_setNext(set_t * set, ITEM_TYPE * item);
+int via_setDestroy(set_t * set);
+
+#endif
+
+#ifndef MM_INC
+#define MM_INC
+
+struct mem_block_t {
+	struct mem_block_t *next;
+	struct mem_block_t *heap;
+	int ofs, size;
+	int align;
+	int free:1;
+	int reserved:1;
+};
+typedef struct mem_block_t TMemBlock;
+typedef struct mem_block_t *PMemBlock;
+
+/* a heap is just the first block in a chain */
+typedef struct mem_block_t memHeap_t;
+
+static __inline__ int mmBlockSize(PMemBlock b)
+{
+	return b->size;
+}
+
+static __inline__ int mmOffset(PMemBlock b)
+{
+	return b->ofs;
+}
+
+static __inline__ void mmMarkReserved(PMemBlock b)
+{
+	b->reserved = 1;
+}
+
+/*
+ * input: total size in bytes
+ * return: a heap pointer if OK, NULL if error
+ */
+memHeap_t *via_mmInit(int ofs, int size);
+
+PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
+			 int startSearch);
+
+/*
+ * Free block starts at offset
+ * input: pointer to a block
+ * return: 0 if OK, -1 if error
+ */
+int via_mmFreeMem(PMemBlock b);
+
+#endif
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
new file mode 100644
index 0000000..e8027f3
--- /dev/null
+++ b/drivers/char/drm/via_irq.c
@@ -0,0 +1,339 @@
+/* via_irq.c
+ *
+ * Copyright 2004 BEAM Ltd.
+ * Copyright 2002 Tungsten Graphics, Inc.
+ * Copyright 2005 Thomas Hellstrom.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BEAM LTD, TUNGSTEN GRAPHICS  AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Terry Barnaby <terry1@beam.ltd.uk>
+ *    Keith Whitwell <keith@tungstengraphics.com>
+ *    Thomas Hellstrom <unichrome@shipmail.org>
+ *
+ * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
+ * interrupt, as well as an infrastructure to handle other interrupts of the chip.
+ * The refresh rate is also calculated for video playback sync purposes.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+#define VIA_REG_INTERRUPT       0x200
+
+/* VIA_REG_INTERRUPT */
+#define VIA_IRQ_GLOBAL          (1 << 31)
+#define VIA_IRQ_VBLANK_ENABLE   (1 << 19)
+#define VIA_IRQ_VBLANK_PENDING  (1 << 3)
+#define VIA_IRQ_HQV0_ENABLE     (1 << 11)
+#define VIA_IRQ_HQV1_ENABLE     (1 << 25)
+#define VIA_IRQ_HQV0_PENDING    (1 << 9)
+#define VIA_IRQ_HQV1_PENDING    (1 << 10)
+
+/*
+ * Device-specific IRQs go here. This type might need to be extended with
+ * the register if there are multiple IRQ control registers.
+ * Currently we activate the HQV interrupts of  Unichrome Pro group A. 
+ */
+
+static maskarray_t via_pro_group_a_irqs[] = {
+	{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000 },
+	{VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 0x00000000 }};
+static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs)/sizeof(maskarray_t);
+
+static maskarray_t via_unichrome_irqs[] = {};
+static int via_num_unichrome = sizeof(via_unichrome_irqs)/sizeof(maskarray_t);
+
+
+static unsigned time_diff(struct timeval *now,struct timeval *then) 
+{
+    return (now->tv_usec >= then->tv_usec) ?
+        now->tv_usec - then->tv_usec :
+        1000000 - (then->tv_usec - now->tv_usec);
+}
+
+irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
+{
+	drm_device_t *dev = (drm_device_t *) arg;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	u32 status;
+	int handled = 0;
+	struct timeval cur_vblank;
+	drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+	int i;
+
+	status = VIA_READ(VIA_REG_INTERRUPT);
+	if (status & VIA_IRQ_VBLANK_PENDING) {
+		atomic_inc(&dev->vbl_received);
+                if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
+			do_gettimeofday(&cur_vblank);
+                        if (dev_priv->last_vblank_valid) {
+				dev_priv->usec_per_vblank = 
+					time_diff( &cur_vblank,&dev_priv->last_vblank) >> 4;
+			}
+			dev_priv->last_vblank = cur_vblank;
+			dev_priv->last_vblank_valid = 1;
+                }
+                if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+			DRM_DEBUG("US per vblank is: %u\n",
+				dev_priv->usec_per_vblank);
+		}
+		DRM_WAKEUP(&dev->vbl_queue);
+		drm_vbl_send_signals(dev);
+		handled = 1;
+	}
+	
+
+	for (i=0; i<dev_priv->num_irqs; ++i) {
+		if (status & cur_irq->pending_mask) {
+			atomic_inc( &cur_irq->irq_received );
+			DRM_WAKEUP( &cur_irq->irq_queue );
+			handled = 1;
+		}
+		cur_irq++;
+	}
+	
+	/* Acknowlege interrupts */
+	VIA_WRITE(VIA_REG_INTERRUPT, status);
+
+
+	if (handled)
+		return IRQ_HANDLED;
+	else
+		return IRQ_NONE;
+}
+
+static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
+{
+	u32 status;
+
+	if (dev_priv) {
+		/* Acknowlege interrupts */
+		status = VIA_READ(VIA_REG_INTERRUPT);
+		VIA_WRITE(VIA_REG_INTERRUPT, status | 
+			  dev_priv->irq_pending_mask);
+	}
+}
+
+int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+{
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	unsigned int cur_vblank;
+	int ret = 0;
+
+	DRM_DEBUG("viadrv_vblank_wait\n");
+	if (!dev_priv) {
+		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	viadrv_acknowledge_irqs(dev_priv);
+
+	/* Assume that the user has missed the current sequence number
+	 * by about a day rather than she wants to wait for years
+	 * using vertical blanks...
+	 */
+
+	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+		    (((cur_vblank = atomic_read(&dev->vbl_received)) -
+		      *sequence) <= (1 << 23)));
+	
+	*sequence = cur_vblank;
+	return ret;
+}
+
+static int 
+via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
+		    unsigned int *sequence)
+{
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	unsigned int cur_irq_sequence;
+	drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+	int ret = 0;
+	maskarray_t *masks = dev_priv->irq_masks;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (!dev_priv) {
+		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+		return DRM_ERR(EINVAL);
+	}
+
+	if (irq >= dev_priv->num_irqs ) {
+		DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq);
+		return DRM_ERR(EINVAL);
+	}
+		
+	cur_irq += irq;
+
+	if (masks[irq][2] && !force_sequence) {
+		DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+			    ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4]));
+		cur_irq_sequence = atomic_read(&cur_irq->irq_received);
+	} else {
+		DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+			    (((cur_irq_sequence = atomic_read(&cur_irq->irq_received)) -
+			      *sequence) <= (1 << 23)));		
+	}
+	*sequence = cur_irq_sequence;
+	return ret;
+}
+
+
+/*
+ * drm_dma.h hooks
+ */
+
+void via_driver_irq_preinstall(drm_device_t * dev)
+{
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	u32 status;
+	drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+	int i;
+
+	DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
+	if (dev_priv) {
+
+		dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
+		dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
+
+		dev_priv->irq_masks = (dev_priv->pro_group_a) ?
+			via_pro_group_a_irqs : via_unichrome_irqs;
+		dev_priv->num_irqs = (dev_priv->pro_group_a) ?
+			via_num_pro_group_a : via_num_unichrome;
+		
+		for(i=0; i < dev_priv->num_irqs; ++i) {
+			atomic_set(&cur_irq->irq_received, 0);
+			cur_irq->enable_mask = dev_priv->irq_masks[i][0]; 
+			cur_irq->pending_mask = dev_priv->irq_masks[i][1];
+			DRM_INIT_WAITQUEUE( &cur_irq->irq_queue );
+			dev_priv->irq_enable_mask |= cur_irq->enable_mask;
+			dev_priv->irq_pending_mask |= cur_irq->pending_mask;
+			cur_irq++;
+			
+			DRM_DEBUG("Initializing IRQ %d\n", i);
+		}
+			
+	        dev_priv->last_vblank_valid = 0;
+
+		// Clear VSync interrupt regs
+		status = VIA_READ(VIA_REG_INTERRUPT);
+		VIA_WRITE(VIA_REG_INTERRUPT, status & 
+			  ~(dev_priv->irq_enable_mask));
+		
+		/* Clear bits if they're already high */
+		viadrv_acknowledge_irqs(dev_priv);
+	}
+}
+
+void via_driver_irq_postinstall(drm_device_t * dev)
+{
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	u32 status;
+
+	DRM_DEBUG("via_driver_irq_postinstall\n");
+	if (dev_priv) {
+		status = VIA_READ(VIA_REG_INTERRUPT);
+		VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
+			  | dev_priv->irq_enable_mask);
+
+		/* Some magic, oh for some data sheets ! */
+
+		VIA_WRITE8(0x83d4, 0x11);
+		VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
+		
+	}
+}
+
+void via_driver_irq_uninstall(drm_device_t * dev)
+{
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	u32 status;
+
+	DRM_DEBUG("driver_irq_uninstall)\n");
+	if (dev_priv) {
+
+		/* Some more magic, oh for some data sheets ! */
+
+		VIA_WRITE8(0x83d4, 0x11);
+		VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
+
+		status = VIA_READ(VIA_REG_INTERRUPT);
+		VIA_WRITE(VIA_REG_INTERRUPT, status & 
+			  ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
+	}
+}
+
+int via_wait_irq(DRM_IOCTL_ARGS)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->head->dev;
+	drm_via_irqwait_t __user *argp = (void __user *)data;
+	drm_via_irqwait_t irqwait;
+	struct timeval now;
+	int ret = 0;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+	int force_sequence;
+
+	if (!dev->irq)
+		return DRM_ERR(EINVAL);
+
+	DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
+	if (irqwait.request.irq >= dev_priv->num_irqs) {
+		DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, 
+			  irqwait.request.irq);
+		return DRM_ERR(EINVAL);
+	}
+
+	cur_irq += irqwait.request.irq;
+
+	switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
+	case VIA_IRQ_RELATIVE:
+		irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
+		irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+	case VIA_IRQ_ABSOLUTE:
+		break;
+	default:
+		return DRM_ERR(EINVAL);
+	}
+
+	if (irqwait.request.type & VIA_IRQ_SIGNAL) {
+		DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n", 
+			  __FUNCTION__);
+		return DRM_ERR(EINVAL);
+	}
+
+	force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
+
+	ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
+				  &irqwait.request.sequence);
+	do_gettimeofday(&now);
+	irqwait.reply.tval_sec = now.tv_sec;
+	irqwait.reply.tval_usec = now.tv_usec;
+
+	DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
+
+	return ret;
+}
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
new file mode 100644
index 0000000..0be829b
--- /dev/null
+++ b/drivers/char/drm/via_map.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
+{
+	drm_via_private_t *dev_priv;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	dev_priv = drm_alloc(sizeof(drm_via_private_t), DRM_MEM_DRIVER);
+	if (dev_priv == NULL)
+		return -ENOMEM;
+
+	memset(dev_priv, 0, sizeof(drm_via_private_t));
+
+	DRM_GETSAREA();
+	if (!dev_priv->sarea) {
+		DRM_ERROR("could not find sarea!\n");
+		dev->dev_private = (void *)dev_priv;
+		via_do_cleanup_map(dev);
+		return -EINVAL;
+	}
+
+	dev_priv->fb = drm_core_findmap(dev, init->fb_offset);
+	if (!dev_priv->fb) {
+		DRM_ERROR("could not find framebuffer!\n");
+		dev->dev_private = (void *)dev_priv;
+		via_do_cleanup_map(dev);
+		return -EINVAL;
+	}
+	dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
+	if (!dev_priv->mmio) {
+		DRM_ERROR("could not find mmio region!\n");
+		dev->dev_private = (void *)dev_priv;
+		via_do_cleanup_map(dev);
+		return -EINVAL;
+	}
+
+	dev_priv->sarea_priv =
+	    (drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle +
+				 init->sarea_priv_offset);
+
+	dev_priv->agpAddr = init->agpAddr;
+
+	via_init_futex( dev_priv );
+	dev_priv->pro_group_a = (dev->pdev->device == 0x3118);
+
+	dev->dev_private = (void *)dev_priv;
+	return 0;
+}
+
+int via_do_cleanup_map(drm_device_t * dev)
+{
+	if (dev->dev_private) {
+
+		drm_via_private_t *dev_priv = dev->dev_private;
+
+		via_dma_cleanup(dev);
+
+		drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
+		dev->dev_private = NULL;
+	}
+
+	return 0;
+}
+
+int via_map_init(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_via_init_t init;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t *) data, sizeof(init));
+
+	switch (init.func) {
+	case VIA_INIT_MAP:
+		return via_do_init_map(dev, &init);
+	case VIA_CLEANUP_MAP:
+		return via_do_cleanup_map(dev);
+	}
+
+	return -EINVAL;
+}
+
+
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
new file mode 100644
index 0000000..c22712f
--- /dev/null
+++ b/drivers/char/drm/via_mm.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+#include "via_ds.h"
+#include "via_mm.h"
+
+#define MAX_CONTEXT 100
+
+typedef struct {
+	int used;
+	int context;
+	set_t *sets[2];		/* 0 for frame buffer, 1 for AGP , 2 for System */
+} via_context_t;
+
+static via_context_t global_ppriv[MAX_CONTEXT];
+
+static int via_agp_alloc(drm_via_mem_t * mem);
+static int via_agp_free(drm_via_mem_t * mem);
+static int via_fb_alloc(drm_via_mem_t * mem);
+static int via_fb_free(drm_via_mem_t * mem);
+
+static int add_alloc_set(int context, int type, unsigned int val)
+{
+	int i, retval = 0;
+
+	for (i = 0; i < MAX_CONTEXT; i++) {
+		if (global_ppriv[i].used && global_ppriv[i].context == context) {
+			retval = via_setAdd(global_ppriv[i].sets[type], val);
+			break;
+		}
+	}
+
+	return retval;
+}
+
+static int del_alloc_set(int context, int type, unsigned int val)
+{
+	int i, retval = 0;
+
+	for (i = 0; i < MAX_CONTEXT; i++)
+		if (global_ppriv[i].used && global_ppriv[i].context == context) {
+			retval = via_setDel(global_ppriv[i].sets[type], val);
+			break;
+		}
+
+	return retval;
+}
+
+/* agp memory management */
+static memHeap_t *AgpHeap = NULL;
+
+int via_agp_init(DRM_IOCTL_ARGS)
+{
+	drm_via_agp_t agp;
+
+	DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t *) data, sizeof(agp));
+
+	AgpHeap = via_mmInit(agp.offset, agp.size);
+
+	DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset, (unsigned long)agp.size);
+
+	return 0;
+}
+
+/* fb memory management */
+static memHeap_t *FBHeap = NULL;
+
+int via_fb_init(DRM_IOCTL_ARGS)
+{
+	drm_via_fb_t fb;
+
+	DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t *) data, sizeof(fb));
+
+	FBHeap = via_mmInit(fb.offset, fb.size);
+
+	DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset, (unsigned long)fb.size);
+
+	return 0;
+}
+
+int via_init_context(struct drm_device *dev, int context)
+{
+	int i;
+
+	for (i = 0; i < MAX_CONTEXT; i++)
+		if (global_ppriv[i].used &&
+		    (global_ppriv[i].context == context))
+			break;
+
+	if (i >= MAX_CONTEXT) {
+		for (i = 0; i < MAX_CONTEXT; i++) {
+			if (!global_ppriv[i].used) {
+				global_ppriv[i].context = context;
+				global_ppriv[i].used = 1;
+				global_ppriv[i].sets[0] = via_setInit();
+				global_ppriv[i].sets[1] = via_setInit();
+				DRM_DEBUG("init allocation set, socket=%d,"
+					  " context = %d\n", i, context);
+				break;
+			}
+		}
+
+		if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
+		    (global_ppriv[i].sets[1] == NULL)) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+int via_final_context(struct drm_device *dev, int context)
+{	
+        int i;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+
+	for (i = 0; i < MAX_CONTEXT; i++)
+		if (global_ppriv[i].used &&
+		    (global_ppriv[i].context == context))
+			break;
+
+	if (i < MAX_CONTEXT) {
+		set_t *set;
+		ITEM_TYPE item;
+		int retval;
+
+		DRM_DEBUG("find socket %d, context = %d\n", i, context);
+
+		/* Video Memory */
+		set = global_ppriv[i].sets[0];
+		retval = via_setFirst(set, &item);
+		while (retval) {
+			DRM_DEBUG("free video memory 0x%lx\n", item);
+			via_mmFreeMem((PMemBlock) item);
+			retval = via_setNext(set, &item);
+		}
+		via_setDestroy(set);
+
+		/* AGP Memory */
+		set = global_ppriv[i].sets[1];
+		retval = via_setFirst(set, &item);
+		while (retval) {
+			DRM_DEBUG("free agp memory 0x%lx\n", item);
+			via_mmFreeMem((PMemBlock) item);
+			retval = via_setNext(set, &item);
+		}
+		via_setDestroy(set);
+		global_ppriv[i].used = 0;
+	}
+	via_release_futex(dev_priv, context); 
+	
+			
+#if defined(__linux__)
+	/* Linux specific until context tracking code gets ported to BSD */
+	/* Last context, perform cleanup */
+	if (dev->ctx_count == 1 && dev->dev_private) {
+	        DRM_DEBUG("Last Context\n");
+		if (dev->irq)
+			drm_irq_uninstall(dev);
+
+		via_cleanup_futex(dev_priv);
+		via_do_cleanup_map(dev);
+	}
+#endif
+
+	return 1;
+}
+
+int via_mem_alloc(DRM_IOCTL_ARGS)
+{
+	drm_via_mem_t mem;
+
+	DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem));
+
+	switch (mem.type) {
+	case VIDEO:
+		if (via_fb_alloc(&mem) < 0)
+			return -EFAULT;
+		DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem,
+				       sizeof(mem));
+		return 0;
+	case AGP:
+		if (via_agp_alloc(&mem) < 0)
+			return -EFAULT;
+		DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem,
+				       sizeof(mem));
+		return 0;
+	}
+
+	return -EFAULT;
+}
+
+static int via_fb_alloc(drm_via_mem_t * mem)
+{
+	drm_via_mm_t fb;
+	PMemBlock block;
+	int retval = 0;
+
+	if (!FBHeap)
+		return -1;
+
+	fb.size = mem->size;
+	fb.context = mem->context;
+
+	block = via_mmAllocMem(FBHeap, fb.size, 5, 0);
+	if (block) {
+		fb.offset = block->ofs;
+		fb.free = (unsigned long)block;
+		if (!add_alloc_set(fb.context, VIDEO, fb.free)) {
+			DRM_DEBUG("adding to allocation set fails\n");
+			via_mmFreeMem((PMemBlock) fb.free);
+			retval = -1;
+		}
+	} else {
+		fb.offset = 0;
+		fb.size = 0;
+		fb.free = 0;
+		retval = -1;
+	}
+
+	mem->offset = fb.offset;
+	mem->index = fb.free;
+
+	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size,
+		  (int)fb.offset);
+
+	return retval;
+}
+
+static int via_agp_alloc(drm_via_mem_t * mem)
+{
+	drm_via_mm_t agp;
+	PMemBlock block;
+	int retval = 0;
+
+	if (!AgpHeap)
+		return -1;
+
+	agp.size = mem->size;
+	agp.context = mem->context;
+
+	block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);
+	if (block) {
+		agp.offset = block->ofs;
+		agp.free = (unsigned long)block;
+		if (!add_alloc_set(agp.context, AGP, agp.free)) {
+			DRM_DEBUG("adding to allocation set fails\n");
+			via_mmFreeMem((PMemBlock) agp.free);
+			retval = -1;
+		}
+	} else {
+		agp.offset = 0;
+		agp.size = 0;
+		agp.free = 0;
+	}
+
+	mem->offset = agp.offset;
+	mem->index = agp.free;
+
+	DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size,
+		  (unsigned int)agp.offset);
+	return retval;
+}
+
+int via_mem_free(DRM_IOCTL_ARGS)
+{
+	drm_via_mem_t mem;
+
+	DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem));
+
+	switch (mem.type) {
+
+	case VIDEO:
+		if (via_fb_free(&mem) == 0)
+			return 0;
+		break;
+	case AGP:
+		if (via_agp_free(&mem) == 0)
+			return 0;
+		break;
+	}
+
+	return -EFAULT;
+}
+
+static int via_fb_free(drm_via_mem_t * mem)
+{
+	drm_via_mm_t fb;
+	int retval = 0;
+
+	if (!FBHeap) {
+		return -1;
+	}
+
+	fb.free = mem->index;
+	fb.context = mem->context;
+
+	if (!fb.free) {
+		return -1;
+
+	}
+
+	via_mmFreeMem((PMemBlock) fb.free);
+
+	if (!del_alloc_set(fb.context, VIDEO, fb.free)) {
+		retval = -1;
+	}
+
+	DRM_DEBUG("free fb, free = %ld\n", fb.free);
+
+	return retval;
+}
+
+static int via_agp_free(drm_via_mem_t * mem)
+{
+	drm_via_mm_t agp;
+
+	int retval = 0;
+
+	agp.free = mem->index;
+	agp.context = mem->context;
+
+	if (!agp.free)
+		return -1;
+
+	via_mmFreeMem((PMemBlock) agp.free);
+
+	if (!del_alloc_set(agp.context, AGP, agp.free)) {
+		retval = -1;
+	}
+
+	DRM_DEBUG("free agp, free = %ld\n", agp.free);
+
+	return retval;
+}
diff --git a/drivers/char/drm/via_mm.h b/drivers/char/drm/via_mm.h
new file mode 100644
index 0000000..d57efda
--- /dev/null
+++ b/drivers/char/drm/via_mm.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _via_drm_mm_h_
+#define _via_drm_mm_h_
+
+typedef struct {
+	unsigned int context;
+	unsigned int size;
+	unsigned long offset;
+	unsigned long free;
+} drm_via_mm_t;
+
+typedef struct {
+	unsigned int size;
+	unsigned long handle;
+	void *virtual;
+} drm_via_dma_t;
+
+#endif
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
new file mode 100644
index 0000000..07923b0
--- /dev/null
+++ b/drivers/char/drm/via_verifier.c
@@ -0,0 +1,1061 @@
+/*
+ * Copyright 2004 The Unichrome Project. All Rights Reserved.
+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Thomas Hellstrom 2004, 2005.
+ * This code was written using docs obtained under NDA from VIA Inc.
+ *
+ * Don't run this code directly on an AGP buffer. Due to cache problems it will
+ * be very slow.
+ */
+
+
+#include "via_3d_reg.h"
+#include "drmP.h"
+#include "drm.h"
+#include "via_drm.h"
+#include "via_verifier.h"
+#include "via_drv.h"
+
+typedef enum{
+	state_command,
+	state_header2,
+	state_header1,
+	state_vheader5,
+	state_vheader6,
+	state_error
+} verifier_state_t;
+
+
+typedef enum{
+	no_check = 0,
+	check_for_header2,
+	check_for_header1,
+	check_for_header2_err,
+	check_for_header1_err,
+	check_for_fire,
+	check_z_buffer_addr0,
+	check_z_buffer_addr1,
+	check_z_buffer_addr_mode,
+	check_destination_addr0,
+	check_destination_addr1,
+	check_destination_addr_mode,
+	check_for_dummy,
+	check_for_dd,
+	check_texture_addr0,
+	check_texture_addr1,
+	check_texture_addr2,
+	check_texture_addr3,
+	check_texture_addr4,
+	check_texture_addr5,
+	check_texture_addr6,
+	check_texture_addr7,
+	check_texture_addr8,
+	check_texture_addr_mode,
+	check_for_vertex_count,
+	check_number_texunits,
+	forbidden_command
+}hazard_t;
+
+/*
+ * Associates each hazard above with a possible multi-command
+ * sequence. For example an address that is split over multiple
+ * commands and that needs to be checked at the first command 
+ * that does not include any part of the address.
+ */
+
+static drm_via_sequence_t seqs[] = { 
+	no_sequence,
+	no_sequence,
+	no_sequence,
+	no_sequence,
+	no_sequence,
+	no_sequence,
+	z_address,
+	z_address,
+	z_address,
+	dest_address,
+	dest_address,
+	dest_address,
+	no_sequence,
+	no_sequence,
+	tex_address,
+	tex_address,
+	tex_address,
+	tex_address,
+	tex_address,
+	tex_address,
+	tex_address,
+	tex_address,
+	tex_address,
+	tex_address,
+	no_sequence
+};
+    
+typedef struct{
+	unsigned int code;
+	hazard_t hz;
+} hz_init_t;
+
+
+
+static hz_init_t init_table1[] = {
+	{0xf2, check_for_header2_err},
+	{0xf0, check_for_header1_err},
+	{0xee, check_for_fire},
+	{0xcc, check_for_dummy},
+	{0xdd, check_for_dd},
+	{0x00, no_check},
+	{0x10, check_z_buffer_addr0},
+	{0x11, check_z_buffer_addr1},
+	{0x12, check_z_buffer_addr_mode},
+	{0x13, no_check},
+	{0x14, no_check},
+	{0x15, no_check},
+	{0x23, no_check},
+	{0x24, no_check},
+	{0x33, no_check},
+	{0x34, no_check},
+	{0x35, no_check},
+	{0x36, no_check},
+	{0x37, no_check},
+	{0x38, no_check},
+	{0x39, no_check},
+	{0x3A, no_check},
+	{0x3B, no_check},
+	{0x3C, no_check},
+	{0x3D, no_check},
+	{0x3E, no_check},
+	{0x40, check_destination_addr0},
+	{0x41, check_destination_addr1},
+	{0x42, check_destination_addr_mode},
+	{0x43, no_check},
+	{0x44, no_check},
+	{0x50, no_check},
+	{0x51, no_check},
+	{0x52, no_check},
+	{0x53, no_check},
+	{0x54, no_check},
+	{0x55, no_check},
+	{0x56, no_check},
+	{0x57, no_check},
+	{0x58, no_check},
+	{0x70, no_check},
+	{0x71, no_check},
+	{0x78, no_check},
+	{0x79, no_check},
+	{0x7A, no_check},
+	{0x7B, no_check},
+	{0x7C, no_check},
+	{0x7D, check_for_vertex_count}
+};
+
+   
+		       
+static hz_init_t init_table2[] = {
+	{0xf2, check_for_header2_err},
+	{0xf0, check_for_header1_err},
+	{0xee, check_for_fire},
+	{0xcc, check_for_dummy},
+	{0x00, check_texture_addr0},
+	{0x01, check_texture_addr0},
+	{0x02, check_texture_addr0},
+	{0x03, check_texture_addr0},
+	{0x04, check_texture_addr0},
+	{0x05, check_texture_addr0},
+	{0x06, check_texture_addr0},
+	{0x07, check_texture_addr0},
+	{0x08, check_texture_addr0},
+	{0x09, check_texture_addr0},
+	{0x20, check_texture_addr1},
+	{0x21, check_texture_addr1},
+	{0x22, check_texture_addr1},
+	{0x23, check_texture_addr4},
+	{0x2B, check_texture_addr3},
+	{0x2C, check_texture_addr3},
+	{0x2D, check_texture_addr3},
+	{0x2E, check_texture_addr3},
+	{0x2F, check_texture_addr3},
+	{0x30, check_texture_addr3},
+	{0x31, check_texture_addr3},
+	{0x32, check_texture_addr3},
+	{0x33, check_texture_addr3},
+	{0x34, check_texture_addr3},
+	{0x4B, check_texture_addr5},
+	{0x4C, check_texture_addr6},
+	{0x51, check_texture_addr7},
+	{0x52, check_texture_addr8},
+	{0x77, check_texture_addr2},
+	{0x78, no_check},
+	{0x79, no_check},
+	{0x7A, no_check},
+	{0x7B, check_texture_addr_mode},
+	{0x7C, no_check},
+	{0x7D, no_check},
+	{0x7E, no_check},
+	{0x7F, no_check},
+	{0x80, no_check},
+	{0x81, no_check},
+	{0x82, no_check},
+	{0x83, no_check},
+	{0x85, no_check},
+	{0x86, no_check},
+	{0x87, no_check},
+	{0x88, no_check},
+	{0x89, no_check},
+	{0x8A, no_check},
+	{0x90, no_check},
+	{0x91, no_check},
+	{0x92, no_check},
+	{0x93, no_check}
+};
+
+static hz_init_t init_table3[] = {
+	{0xf2, check_for_header2_err},
+	{0xf0, check_for_header1_err},
+	{0xcc, check_for_dummy},
+	{0x00, check_number_texunits}
+};
+   
+		       
+static hazard_t table1[256]; 
+static hazard_t table2[256]; 
+static hazard_t table3[256]; 
+
+
+
+static __inline__ int
+eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)
+{
+	if ((*buf - buf_end) >= num_words) {
+		*buf += num_words;
+		return 0;
+	} 
+	DRM_ERROR("Illegal termination of DMA command buffer\n");
+	return 1;
+}
+
+
+/*
+ * Partially stolen from drm_memory.h
+ */
+
+static __inline__ drm_map_t *
+via_drm_lookup_agp_map (drm_via_state_t *seq, unsigned long offset, unsigned long size, 
+			drm_device_t *dev)
+{
+	struct list_head *list;
+	drm_map_list_t *r_list;
+	drm_map_t *map = seq->map_cache;
+
+	if (map && map->offset <= offset && (offset + size) <= (map->offset + map->size)) {
+		return map;
+	}
+		
+	list_for_each(list, &dev->maplist->head) {
+		r_list = (drm_map_list_t *) list;
+		map = r_list->map;
+		if (!map)
+			continue;
+		if (map->offset <= offset && (offset + size) <= (map->offset + map->size) && 
+		    !(map->flags & _DRM_RESTRICTED) && (map->type == _DRM_AGP)) {
+			seq->map_cache = map;
+			return map;
+		}
+	}
+	return NULL;
+}
+
+
+/*
+ * Require that all AGP texture levels reside in the same AGP map which should 
+ * be mappable by the client. This is not a big restriction.
+ * FIXME: To actually enforce this security policy strictly, drm_rmmap 
+ * would have to wait for dma quiescent before removing an AGP map. 
+ * The via_drm_lookup_agp_map call in reality seems to take
+ * very little CPU time.
+ */
+
+
+static __inline__ int
+finish_current_sequence(drm_via_state_t *cur_seq) 
+{
+	switch(cur_seq->unfinished) {
+	case z_address:
+		DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);
+		break;
+	case dest_address:
+		DRM_DEBUG("Destination start address is 0x%x\n", cur_seq->d_addr);
+		break;
+	case tex_address:
+		if (cur_seq->agp_texture) {			 
+			unsigned start = cur_seq->tex_level_lo[cur_seq->texture];
+			unsigned end = cur_seq->tex_level_hi[cur_seq->texture];
+			unsigned long lo=~0, hi=0, tmp;
+			uint32_t *addr, *pitch, *height, tex;
+			unsigned i;
+
+			if (end > 9) end = 9;
+			if (start > 9) start = 9;
+
+			addr =&(cur_seq->t_addr[tex = cur_seq->texture][start]);
+			pitch = &(cur_seq->pitch[tex][start]);
+			height = &(cur_seq->height[tex][start]);
+
+			for (i=start; i<= end; ++i) {
+				tmp = *addr++;
+				if (tmp < lo) lo = tmp;
+				tmp += (*height++ << *pitch++);
+				if (tmp > hi) hi = tmp;
+			}
+
+			if (! via_drm_lookup_agp_map (cur_seq, lo, hi - lo, cur_seq->dev)) {
+				DRM_ERROR("AGP texture is not in allowed map\n");
+				return 2;
+			}
+		}	
+		break;
+	default:
+		break;
+	}
+	cur_seq->unfinished = no_sequence;
+	return 0;
+}
+
+static __inline__ int 
+investigate_hazard( uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)
+{
+	register uint32_t tmp, *tmp_addr;
+
+	if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {
+		int ret;
+		if ((ret = finish_current_sequence(cur_seq))) return ret;
+	}
+
+	switch(hz) {
+	case check_for_header2:
+		if (cmd == HALCYON_HEADER2) return 1;
+		return 0;
+	case check_for_header1:
+		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1;
+		return 0;
+	case check_for_header2_err:
+		if (cmd == HALCYON_HEADER2) return 1;
+		DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
+		break;
+	case check_for_header1_err:
+		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1;
+		DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
+		break;
+	case check_for_fire:
+		if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) return 1; 
+		DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
+		break;
+	case check_for_dummy:
+		if (HC_DUMMY == cmd) return 0;
+		DRM_ERROR("Illegal DMA HC_DUMMY command\n");
+		break;
+	case check_for_dd:
+		if (0xdddddddd == cmd) return 0;
+		DRM_ERROR("Illegal DMA 0xdddddddd command\n");
+		break;
+	case check_z_buffer_addr0:
+		cur_seq->unfinished = z_address;
+		cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |
+			(cmd & 0x00FFFFFF);
+		return 0;
+	case check_z_buffer_addr1:
+		cur_seq->unfinished = z_address;
+		cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |
+			((cmd & 0xFF) << 24);
+		return 0;
+	case check_z_buffer_addr_mode:
+		cur_seq->unfinished = z_address;
+		if ((cmd & 0x0000C000) == 0) return 0;
+		DRM_ERROR("Attempt to place Z buffer in system memory\n");
+		return 2;
+	case check_destination_addr0:
+		cur_seq->unfinished = dest_address;
+		cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |
+			(cmd & 0x00FFFFFF);
+		return 0;
+	case check_destination_addr1:
+		cur_seq->unfinished = dest_address;
+		cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |
+			((cmd & 0xFF) << 24);
+		return 0;
+	case check_destination_addr_mode:
+		cur_seq->unfinished = dest_address;
+		if ((cmd & 0x0000C000) == 0) return 0;
+		DRM_ERROR("Attempt to place 3D drawing buffer in system memory\n");
+		return 2;	    
+	case check_texture_addr0:
+		cur_seq->unfinished = tex_address;
+		tmp = (cmd >> 24);
+		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
+		*tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);
+		return 0;
+	case check_texture_addr1:
+		cur_seq->unfinished = tex_address;
+		tmp = ((cmd >> 24) - 0x20);
+		tmp += tmp << 1;
+		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
+		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
+		tmp_addr++;
+		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);
+		tmp_addr++;
+		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);
+		return 0;
+	case check_texture_addr2:
+		cur_seq->unfinished = tex_address;
+		cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;
+		cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;
+		return 0;
+	case check_texture_addr3:
+		cur_seq->unfinished = tex_address;
+		tmp = ((cmd >> 24) - 0x2B);
+		cur_seq->pitch[cur_seq->texture][tmp] = (cmd & 0x00F00000) >> 20;
+		if (!tmp && (cmd & 0x000FFFFF)) {
+			DRM_ERROR("Unimplemented texture level 0 pitch mode.\n");
+			return 2;
+		}
+		return 0;
+	case check_texture_addr4:
+		cur_seq->unfinished = tex_address;
+		tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];
+		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
+		return 0;
+	case check_texture_addr5:
+	case check_texture_addr6:
+		cur_seq->unfinished = tex_address;
+		/*
+		 * Texture width. We don't care since we have the pitch.
+		 */  
+		return 0;
+	case check_texture_addr7:
+		cur_seq->unfinished = tex_address;
+		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
+		tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);
+		tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);
+		tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);
+		tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);
+		tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);
+		tmp_addr[0] = 1 << (cmd & 0x0000000F);
+		return 0;
+	case check_texture_addr8:
+		cur_seq->unfinished = tex_address;
+		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
+		tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);
+	        tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);
+		tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);
+		tmp_addr[6] = 1 << (cmd & 0x0000000F);
+		return 0;
+	case check_texture_addr_mode:
+		cur_seq->unfinished = tex_address;
+		if ( 2 == (tmp = cmd & 0x00000003)) {
+			DRM_ERROR("Attempt to fetch texture from system memory.\n"); 
+			return 2;
+		}
+		cur_seq->agp_texture = (tmp == 3);
+		cur_seq->tex_palette_size[cur_seq->texture] = 
+			(cmd >> 16) & 0x000000007;
+		return 0;
+	case check_for_vertex_count:
+		cur_seq->vertex_count = cmd & 0x0000FFFF;
+		return 0;
+	case check_number_texunits:
+	        cur_seq->multitex = (cmd >> 3) & 1;
+		return 0;
+	default:
+		DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
+		return 2;
+	}
+	return 2;
+}
+
+
+static __inline__ int
+via_check_prim_list(uint32_t const **buffer, const uint32_t *buf_end,
+		    drm_via_state_t *cur_seq)
+{
+	drm_via_private_t *dev_priv = (drm_via_private_t *) cur_seq->dev->dev_private;
+	uint32_t a_fire, bcmd , dw_count;
+	int ret = 0;
+	int have_fire;
+	const uint32_t *buf = *buffer;
+
+	while(buf < buf_end) {
+	        have_fire = 0;
+		if ((buf_end - buf) < 2) {
+			DRM_ERROR("Unexpected termination of primitive list.\n");
+			ret = 1;
+			break;
+		}
+		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) break;
+		bcmd = *buf++;
+		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
+			DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
+				  *buf);
+			ret = 1;
+			break;
+		}
+		a_fire = *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;	
+	
+		/*
+		 * How many dwords per vertex ?
+		 */ 
+		
+		if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {
+			DRM_ERROR("Illegal B command vertex data for AGP.\n");
+			ret = 1;
+			break;
+		} 
+
+		dw_count = 0;
+		if (bcmd & (1 << 7)) dw_count += (cur_seq->multitex) ? 2:1;
+		if (bcmd & (1 << 8)) dw_count += (cur_seq->multitex) ? 2:1;
+		if (bcmd & (1 << 9)) dw_count++;
+		if (bcmd & (1 << 10)) dw_count++;
+		if (bcmd & (1 << 11)) dw_count++;
+		if (bcmd & (1 << 12)) dw_count++;
+		if (bcmd & (1 << 13)) dw_count++;
+		if (bcmd & (1 << 14)) dw_count++;
+
+		while(buf < buf_end) {
+			if (*buf == a_fire) {
+				if (dev_priv->num_fire_offsets >= VIA_FIRE_BUF_SIZE) {
+					DRM_ERROR("Fire offset buffer full.\n");
+					ret = 1;
+					break;
+				}
+				dev_priv->fire_offsets[dev_priv->num_fire_offsets++] = buf;
+			        have_fire = 1;
+				buf++;
+				if (buf < buf_end && *buf == a_fire) 
+					buf++;
+				break;
+			}
+			if ((*buf == HALCYON_HEADER2) || 
+			    ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {
+				DRM_ERROR("Missing Vertex Fire command, "
+					  "Stray Vertex Fire command  or verifier "
+					  "lost sync.\n");
+				ret = 1;
+				break;
+			}
+			if ((ret = eat_words(&buf, buf_end, dw_count)))
+				break;
+		}
+		if (buf >= buf_end && !have_fire) {
+			DRM_ERROR("Missing Vertex Fire command or verifier "
+				  "lost sync.\n");
+			ret = 1;
+			break;
+		}
+		if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {
+			DRM_ERROR("AGP Primitive list end misaligned.\n");
+			ret = 1;
+			break;
+		}
+	} 
+	*buffer = buf;
+	return ret;
+}
+
+
+		       
+
+
+static __inline__ verifier_state_t
+via_check_header2( uint32_t const **buffer, const uint32_t *buf_end, 
+		   drm_via_state_t *hc_state)
+{
+	uint32_t cmd;
+	int hz_mode;
+	hazard_t hz;
+	const uint32_t *buf = *buffer;
+	const hazard_t *hz_table;
+
+
+	if ((buf_end - buf) < 2) {
+		DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
+		return state_error;
+	}
+	buf++;
+	cmd = (*buf++ & 0xFFFF0000) >> 16;
+
+	switch(cmd) {
+	case HC_ParaType_CmdVdata:
+		if (via_check_prim_list(&buf, buf_end, hc_state )) 
+			return state_error;
+		*buffer = buf;
+		return state_command;
+	case HC_ParaType_NotTex:
+		hz_table = table1;
+		break;
+	case HC_ParaType_Tex:
+		hc_state->texture = 0;
+		hz_table = table2;
+		break;
+	case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):
+		hc_state->texture = 1;
+		hz_table = table2;
+		break;
+	case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):
+		hz_table = table3;
+		break;
+	case HC_ParaType_Auto:
+		if (eat_words(&buf, buf_end, 2))
+			return state_error;
+		*buffer = buf;
+		return state_command;
+	case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):
+		if (eat_words(&buf, buf_end, 32))
+			return state_error;
+		*buffer = buf;
+		return state_command;
+	case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):
+	case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):
+		DRM_ERROR("Texture palettes are rejected because of "
+			  "lack of info how to determine their size.\n");
+		return state_error;
+	case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):
+		DRM_ERROR("Fog factor palettes are rejected because of "
+			  "lack of info how to determine their size.\n");
+		return state_error;
+	default:
+
+		/*
+		 * There are some unimplemented HC_ParaTypes here, that
+		 * need to be implemented if the Mesa driver is extended.
+		 */
+
+		DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
+			  "DMA subcommand: 0x%x. Previous dword: 0x%x\n", 
+			  cmd, *(buf -2));
+		*buffer = buf;
+		return state_error;
+	}
+
+	while(buf < buf_end) {
+		cmd = *buf++;
+		if ((hz = hz_table[cmd >> 24])) {
+			if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {
+				if (hz_mode == 1) {
+					buf--;
+					break;
+				}
+				return state_error;
+			}
+		} else if (hc_state->unfinished && 
+			   finish_current_sequence(hc_state)) {
+			return state_error;
+		}
+	}
+	if (hc_state->unfinished && finish_current_sequence(hc_state)) {
+		return state_error;
+	}
+	*buffer = buf;
+	return state_command;
+}
+
+static __inline__ verifier_state_t
+via_parse_header2( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end,
+		   int *fire_count)
+{
+	uint32_t cmd;
+	const uint32_t *buf = *buffer;
+	const uint32_t *next_fire; 
+	int burst = 0;
+
+	next_fire = dev_priv->fire_offsets[*fire_count];
+	buf++;
+	cmd = (*buf & 0xFFFF0000) >> 16;
+	VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
+	switch(cmd) {
+	case HC_ParaType_CmdVdata:
+		while ((buf < buf_end) &&
+		       (*fire_count < dev_priv->num_fire_offsets) && 
+		       (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB ) {
+			while(buf <= next_fire) {
+				VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+				burst += 4;
+			}
+			if ( ( buf < buf_end ) && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
+				buf++;
+
+			if (++(*fire_count) < dev_priv->num_fire_offsets) 
+				next_fire = dev_priv->fire_offsets[*fire_count];
+		}
+		break;
+	default:
+		while(buf < buf_end) {
+			
+			if ( *buf == HC_HEADER2 ||
+			     (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1  ||
+			     (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
+			     (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6 ) break;
+			
+			VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+			burst +=4;
+		}
+	}
+	*buffer = buf;
+	return state_command;
+}
+
+
+
+static __inline__ int
+verify_mmio_address( uint32_t address)
+{
+	if ((address > 0x3FF) && (address < 0xC00 )) {
+		DRM_ERROR("Invalid VIDEO DMA command. "
+			  "Attempt to access 3D- or command burst area.\n");
+		return 1;
+	} else if ((address > 0xCFF) && (address < 0x1300)) {
+		DRM_ERROR("Invalid VIDEO DMA command. "
+			  "Attempt to access PCI DMA area.\n");
+		return 1;		
+	} else if (address > 0x13FF ) {
+		DRM_ERROR("Invalid VIDEO DMA command. "
+			  "Attempt to access VGA registers.\n");
+		return 1;
+	}
+	return 0;
+}
+
+static __inline__ int
+verify_video_tail( uint32_t const **buffer, const uint32_t *buf_end, uint32_t dwords) 
+{
+	const uint32_t *buf = *buffer;
+
+	if (buf_end - buf < dwords) {
+		DRM_ERROR("Illegal termination of video command.\n");
+		return 1;
+	}
+	while (dwords--) {
+		if (*buf++) {
+			DRM_ERROR("Illegal video command tail.\n");
+			return 1;
+		}
+	}
+	*buffer = buf;
+	return 0;
+}
+		
+
+static __inline__ verifier_state_t
+via_check_header1( uint32_t const **buffer, const uint32_t *buf_end )
+{
+	uint32_t cmd;
+	const uint32_t *buf = *buffer;
+	verifier_state_t ret = state_command;
+
+	while (buf < buf_end) {
+		cmd = *buf;
+		if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&
+		    (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) {			
+			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 
+				break;
+			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+				  "Attempt to access 3D- or command burst area.\n");
+			ret = state_error;
+			break;
+		} else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {
+			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 
+				break;
+			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+				  "Attempt to access VGA registers.\n");
+			ret = state_error;
+			break;			
+		} else {			
+			buf += 2;
+		}
+	}
+	*buffer = buf;
+	return ret;
+}
+
+static __inline__ verifier_state_t
+via_parse_header1( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+	register uint32_t cmd;
+	const uint32_t *buf = *buffer;
+
+	while (buf < buf_end) {
+		cmd = *buf;
+		if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) break;
+		VIA_WRITE( (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); 
+		buf++;
+	}
+	*buffer = buf;
+	return state_command;
+}
+
+static __inline__ verifier_state_t
+via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
+{
+	uint32_t data;
+	const uint32_t *buf = *buffer;
+
+	if (buf_end - buf < 4) {
+		DRM_ERROR("Illegal termination of video header5 command\n");
+		return state_error;
+	}
+
+	data = *buf++ & ~VIA_VIDEOMASK;
+	if (verify_mmio_address(data))
+		return state_error;
+
+	data = *buf++;
+	if (*buf++ != 0x00F50000) {
+		DRM_ERROR("Illegal header5 header data\n");
+		return state_error;
+	}
+	if (*buf++ != 0x00000000) {
+		DRM_ERROR("Illegal header5 header data\n");
+		return state_error;
+	}
+	if (eat_words(&buf, buf_end, data)) 
+		return state_error;
+	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) 
+		return state_error;
+	*buffer = buf;
+	return state_command;
+	       
+} 
+
+static __inline__ verifier_state_t
+via_parse_vheader5( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+  uint32_t addr, count, i;
+	const uint32_t *buf = *buffer;
+	
+	addr = *buf++ & ~VIA_VIDEOMASK;
+	i = count = *buf;
+	buf += 3;
+	while(i--) {
+		VIA_WRITE(addr, *buf++);
+	}
+	if (count & 3) buf += 4 - (count & 3);
+	*buffer = buf;
+	return state_command;	       
+} 
+
+
+static __inline__ verifier_state_t
+via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )
+{
+	uint32_t data;
+	const uint32_t *buf = *buffer;
+	uint32_t i;
+
+
+	if (buf_end - buf < 4) {
+		DRM_ERROR("Illegal termination of video header6 command\n");
+		return state_error;
+	}
+	buf++;
+	data = *buf++;
+	if (*buf++ != 0x00F60000) {
+		DRM_ERROR("Illegal header6 header data\n");
+		return state_error;
+	}
+	if (*buf++ != 0x00000000) {
+		DRM_ERROR("Illegal header6 header data\n");
+		return state_error;
+	}
+	if ((buf_end - buf) < (data << 1)) {
+		DRM_ERROR("Illegal termination of video header6 command\n");
+		return state_error;
+	}
+	for (i=0; i<data; ++i) {
+		if (verify_mmio_address(*buf++))
+			return state_error;
+		buf++;
+	}
+	data <<= 1;
+	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
+		return state_error;
+	*buffer = buf;
+	return state_command;
+} 
+
+static __inline__ verifier_state_t
+via_parse_vheader6( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+
+  uint32_t addr, count, i;
+	const uint32_t *buf = *buffer;
+
+	i = count = *++buf;
+	buf += 3;
+	while(i--) {
+		addr = *buf++;
+		VIA_WRITE(addr, *buf++);
+	}
+	count <<= 1;
+	if (count & 3) buf += 4 - (count & 3);
+	*buffer = buf;
+	return state_command;
+} 
+
+
+
+int 
+via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t *dev,
+			  int agp)
+{
+
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	drm_via_state_t *hc_state = &dev_priv->hc_state;
+	drm_via_state_t saved_state = *hc_state;
+	uint32_t cmd;
+	const uint32_t *buf_end = buf + ( size >> 2 );
+	verifier_state_t state = state_command;
+	int pro_group_a = dev_priv->pro_group_a;
+	
+	hc_state->dev = dev;
+	hc_state->unfinished = no_sequence;
+	hc_state->map_cache = NULL;
+	hc_state->agp = agp;
+	hc_state->buf_start = buf;
+	dev_priv->num_fire_offsets = 0;
+
+	while (buf < buf_end) {
+
+		switch (state) {
+		case state_header2:
+		  state = via_check_header2( &buf, buf_end, hc_state );
+			break;
+		case state_header1:
+			state = via_check_header1( &buf, buf_end );
+			break;
+		case state_vheader5:
+			state = via_check_vheader5( &buf, buf_end );
+			break;
+		case state_vheader6:
+			state = via_check_vheader6( &buf, buf_end );
+			break;
+		case state_command:
+			if (HALCYON_HEADER2 == (cmd = *buf)) 
+				state = state_header2;
+			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 
+				state = state_header1;
+			else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+				state = state_vheader5;
+			else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+				state = state_vheader6;
+			else {
+				DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
+					  cmd);
+				state = state_error;
+			}
+			break;
+		case state_error:
+		default:
+			*hc_state = saved_state;
+			return DRM_ERR(EINVAL);			
+		}
+	}	
+	if (state == state_error) {
+		*hc_state = saved_state;
+		return DRM_ERR(EINVAL);
+	}
+	return 0;
+}
+
+int 
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size)
+{
+
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	uint32_t cmd;
+	const uint32_t *buf_end = buf + ( size >> 2 );
+	verifier_state_t state = state_command;
+	int fire_count = 0;
+	
+	while (buf < buf_end) {
+
+		switch (state) {
+		case state_header2:
+		  state = via_parse_header2( dev_priv, &buf, buf_end, &fire_count );
+			break;
+		case state_header1:
+			state = via_parse_header1( dev_priv, &buf, buf_end );
+			break;
+		case state_vheader5:
+			state = via_parse_vheader5( dev_priv, &buf, buf_end );
+			break;
+		case state_vheader6:
+			state = via_parse_vheader6( dev_priv, &buf, buf_end );
+			break;
+		case state_command:
+			if (HALCYON_HEADER2 == (cmd = *buf)) 
+				state = state_header2;
+			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 
+				state = state_header1;
+			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+				state = state_vheader5;
+			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+				state = state_vheader6;
+			else {
+				DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
+					  cmd);
+				state = state_error;
+			}
+			break;
+		case state_error:
+		default:
+			return DRM_ERR(EINVAL);			
+		}
+	}	
+	if (state == state_error) {
+		return DRM_ERR(EINVAL);
+	}
+	return 0;
+}
+
+
+
+static void 
+setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
+{
+	int i;
+
+	for(i=0; i<256; ++i) {
+		table[i] = forbidden_command;
+	}
+
+	for(i=0; i<size; ++i) {
+		table[init_table[i].code] = init_table[i].hz;
+	}
+}
+
+void 
+via_init_command_verifier( void )
+{
+	setup_hazard_table(init_table1, table1, sizeof(init_table1) / sizeof(hz_init_t));
+	setup_hazard_table(init_table2, table2, sizeof(init_table2) / sizeof(hz_init_t));
+	setup_hazard_table(init_table3, table3, sizeof(init_table3) / sizeof(hz_init_t));
+}
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
new file mode 100644
index 0000000..a8e1359
--- /dev/null
+++ b/drivers/char/drm/via_verifier.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2004 The Unichrome Project. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE UNICHROME PROJECT, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Thomas Hellström 2004.
+ */
+
+#ifndef _VIA_VERIFIER_H_
+#define _VIA_VERIFIER_H_
+
+typedef enum{
+	no_sequence = 0, 
+	z_address,
+	dest_address,
+	tex_address
+}drm_via_sequence_t;
+
+
+
+typedef struct{
+	unsigned texture;
+	uint32_t z_addr; 
+	uint32_t d_addr; 
+        uint32_t t_addr[2][10];
+	uint32_t pitch[2][10];
+	uint32_t height[2][10];
+	uint32_t tex_level_lo[2]; 
+	uint32_t tex_level_hi[2];
+	uint32_t tex_palette_size[2];
+	drm_via_sequence_t unfinished;
+	int agp_texture;
+	int multitex;
+	drm_device_t *dev;
+	drm_map_t *map_cache;
+	uint32_t vertex_count;
+	int agp;
+	const uint32_t *buf_start;
+} drm_via_state_t;
+
+extern int via_verify_command_stream(const uint32_t * buf, unsigned int size, 
+				     drm_device_t *dev, int agp);
+
+#endif
diff --git a/drivers/char/drm/via_video.c b/drivers/char/drm/via_video.c
new file mode 100644
index 0000000..37a61c6
--- /dev/null
+++ b/drivers/char/drm/via_video.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Thomas Hellstrom 2005.
+ *
+ * Video and XvMC related functions.
+ */
+
+#include "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+void
+via_init_futex(drm_via_private_t *dev_priv)
+{
+	unsigned int i;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
+		DRM_INIT_WAITQUEUE(&(dev_priv->decoder_queue[i]));
+		XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0;
+	}
+}
+
+void
+via_cleanup_futex(drm_via_private_t *dev_priv)
+{
+}	
+
+void
+via_release_futex(drm_via_private_t *dev_priv, int context)
+{
+	unsigned int i;
+	volatile int *lock;
+
+	for (i=0; i < VIA_NR_XVMC_LOCKS; ++i) {
+	        lock = (int *) XVMCLOCKPTR(dev_priv->sarea_priv, i);
+		if ( (_DRM_LOCKING_CONTEXT( *lock ) == context)) {
+			if (_DRM_LOCK_IS_HELD( *lock ) && (*lock & _DRM_LOCK_CONT)) {
+				DRM_WAKEUP( &(dev_priv->decoder_queue[i]));
+			}
+			*lock = 0;
+		}
+	}	
+}	
+
+int 
+via_decoder_futex(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_via_futex_t fx;
+	volatile int *lock;
+	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+	drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
+	int ret = 0;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t *) data, sizeof(fx));
+
+	if (fx.lock > VIA_NR_XVMC_LOCKS)
+		return -EFAULT;
+
+	lock = (int *)XVMCLOCKPTR(sAPriv, fx.lock);
+
+	switch (fx.func) {
+	case VIA_FUTEX_WAIT:
+		DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],
+			    (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);
+		return ret;
+	case VIA_FUTEX_WAKE:
+		DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));
+		return 0;
+	}
+	return 0;
+}
+
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 88cd858..cddb789 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -22,6 +22,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/config.h>
 #include <linux/console.h>
 #include <linux/cpumask.h>
 #include <linux/init.h>
@@ -40,7 +41,6 @@
 #include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/hvconsole.h>
-#include <asm/vio.h>
 
 #define HVC_MAJOR	229
 #define HVC_MINOR	0
@@ -61,16 +61,21 @@
  */
 #define HVC_ALLOC_TTY_ADAPTERS	8
 
-static struct tty_driver *hvc_driver;
-#ifdef CONFIG_MAGIC_SYSRQ
-static int sysrq_pressed;
-#endif
-
 #define N_OUTBUF	16
 #define N_INBUF		16
 
 #define __ALIGNED__	__attribute__((__aligned__(8)))
 
+static struct tty_driver *hvc_driver;
+static struct task_struct *hvc_task;
+
+/* Picks up late kicks after list walk but before schedule() */
+static int hvc_kicked;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static int sysrq_pressed;
+#endif
+
 struct hvc_struct {
 	spinlock_t lock;
 	int index;
@@ -80,11 +85,11 @@
 	char outbuf[N_OUTBUF] __ALIGNED__;
 	int n_outbuf;
 	uint32_t vtermno;
+	struct hv_ops *ops;
 	int irq_requested;
 	int irq;
 	struct list_head next;
 	struct kobject kobj; /* ref count & hvc_struct lifetime */
-	struct vio_dev *vdev;
 };
 
 /* dynamic list of hvc_struct instances */
@@ -97,48 +102,11 @@
 static DEFINE_SPINLOCK(hvc_structs_lock);
 
 /*
- * Initial console vtermnos for console API usage prior to full console
- * initialization.  Any vty adapter outside this range will not have usable
- * console interfaces but can still be used as a tty device.  This has to be
- * static because kmalloc will not work during early console init.
+ * This value is used to assign a tty->index value to a hvc_struct based
+ * upon order of exposure via hvc_probe(), when we can not match it to
+ * a console canidate registered with hvc_instantiate().
  */
-static uint32_t vtermnos[MAX_NR_HVC_CONSOLES];
-
-/* Used for accounting purposes */
-static int num_vterms = 0;
-
-static struct task_struct *hvc_task;
-
-/*
- * This value is used to associate a tty->index value to a hvc_struct based
- * upon order of exposure via hvc_probe().
- */
-static int hvc_count = -1;
-
-/* Picks up late kicks after list walk but before schedule() */
-static int hvc_kicked;
-
-/* Wake the sleeping khvcd */
-static void hvc_kick(void)
-{
-	hvc_kicked = 1;
-	wake_up_process(hvc_task);
-}
-
-/*
- * NOTE: This API isn't used if the console adapter doesn't support interrupts.
- * In this case the console is poll driven.
- */
-static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
-	hvc_kick();
-	return IRQ_HANDLED;
-}
-
-static void hvc_unthrottle(struct tty_struct *tty)
-{
-	hvc_kick();
-}
+static int last_hvc = -1;
 
 /*
  * Do not call this function with either the hvc_strucst_lock or the hvc_struct
@@ -168,6 +136,178 @@
 	return hp;
 }
 
+
+/*
+ * Initial console vtermnos for console API usage prior to full console
+ * initialization.  Any vty adapter outside this range will not have usable
+ * console interfaces but can still be used as a tty device.  This has to be
+ * static because kmalloc will not work during early console init.
+ */
+static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
+static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
+	{[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
+
+/*
+ * Console APIs, NOT TTY.  These APIs are available immediately when
+ * hvc_console_setup() finds adapters.
+ */
+
+void hvc_console_print(struct console *co, const char *b, unsigned count)
+{
+	char c[16] __ALIGNED__;
+	unsigned i = 0, n = 0;
+	int r, donecr = 0, index = co->index;
+
+	/* Console access attempt outside of acceptable console range. */
+	if (index >= MAX_NR_HVC_CONSOLES)
+		return;
+
+	/* This console adapter was removed so it is not useable. */
+	if (vtermnos[index] < 0)
+		return;
+
+	while (count > 0 || i > 0) {
+		if (count > 0 && i < sizeof(c)) {
+			if (b[n] == '\n' && !donecr) {
+				c[i++] = '\r';
+				donecr = 1;
+			} else {
+				c[i++] = b[n++];
+				donecr = 0;
+				--count;
+			}
+		} else {
+			r = cons_ops[index]->put_chars(vtermnos[index], c, i);
+			if (r < 0) {
+				/* throw away chars on error */
+				i = 0;
+			} else if (r > 0) {
+				i -= r;
+				if (i > 0)
+					memmove(c, c+r, i);
+			}
+		}
+	}
+}
+
+static struct tty_driver *hvc_console_device(struct console *c, int *index)
+{
+	if (vtermnos[c->index] == -1)
+		return NULL;
+
+	*index = c->index;
+	return hvc_driver;
+}
+
+static int __init hvc_console_setup(struct console *co, char *options)
+{
+	if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
+		return -ENODEV;
+
+	if (vtermnos[co->index] == -1)
+		return -ENODEV;
+
+	return 0;
+}
+
+struct console hvc_con_driver = {
+	.name		= "hvc",
+	.write		= hvc_console_print,
+	.device		= hvc_console_device,
+	.setup		= hvc_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+/*
+ * Early console initialization.  Preceeds driver initialization.
+ *
+ * (1) we are first, and the user specified another driver
+ * -- index will remain -1
+ * (2) we are first and the user specified no driver
+ * -- index will be set to 0, then we will fail setup.
+ * (3)  we are first and the user specified our driver
+ * -- index will be set to user specified driver, and we will fail
+ * (4) we are after driver, and this initcall will register us
+ * -- if the user didn't specify a driver then the console will match
+ *
+ * Note that for cases 2 and 3, we will match later when the io driver
+ * calls hvc_instantiate() and call register again.
+ */
+static int __init hvc_console_init(void)
+{
+	register_console(&hvc_con_driver);
+	return 0;
+}
+console_initcall(hvc_console_init);
+
+/*
+ * hvc_instantiate() is an early console discovery method which locates
+ * consoles * prior to the vio subsystem discovering them.  Hotplugged
+ * vty adapters do NOT get an hvc_instantiate() callback since they
+ * appear after early console init.
+ */
+int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
+{
+	struct hvc_struct *hp;
+
+	if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
+		return -1;
+
+	if (vtermnos[index] != -1)
+		return -1;
+
+	/* make sure no no tty has been registerd in this index */
+	hp = hvc_get_by_index(index);
+	if (hp) {
+		kobject_put(&hp->kobj);
+		return -1;
+	}
+
+	vtermnos[index] = vtermno;
+	cons_ops[index] = ops;
+
+	/* reserve all indices upto and including this index */
+	if (last_hvc < index)
+		last_hvc = index;
+
+	/* if this index is what the user requested, then register
+	 * now (setup won't fail at this point).  It's ok to just
+	 * call register again if previously .setup failed.
+	 */
+	if (index == hvc_con_driver.index)
+		register_console(&hvc_con_driver);
+
+	return 0;
+}
+EXPORT_SYMBOL(hvc_instantiate);
+
+/* Wake the sleeping khvcd */
+static void hvc_kick(void)
+{
+	hvc_kicked = 1;
+	wake_up_process(hvc_task);
+}
+
+static int hvc_poll(struct hvc_struct *hp);
+
+/*
+ * NOTE: This API isn't used if the console adapter doesn't support interrupts.
+ * In this case the console is poll driven.
+ */
+static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	/* if hvc_poll request a repoll, then kick the hvcd thread */
+	if (hvc_poll(dev_instance))
+		hvc_kick();
+	return IRQ_HANDLED;
+}
+
+static void hvc_unthrottle(struct tty_struct *tty)
+{
+	hvc_kick();
+}
+
 /*
  * The TTY interface won't be used until after the vio layer has exposed the vty
  * adapter to the kernel.
@@ -329,7 +469,7 @@
 {
 	int n;
 
-	n = hvc_put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
+	n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
 	if (n <= 0) {
 		if (n == 0)
 			return;
@@ -467,7 +607,7 @@
 			break;
 		}
 
-		n = hvc_get_chars(hp->vtermno, buf, count);
+		n = hp->ops->get_chars(hp->vtermno, buf, count);
 		if (n <= 0) {
 			/* Hangup the tty when disconnected from host */
 			if (n == -EPIPE) {
@@ -479,14 +619,17 @@
 		}
 		for (i = 0; i < n; ++i) {
 #ifdef CONFIG_MAGIC_SYSRQ
-			/* Handle the SysRq Hack */
-			if (buf[i] == '\x0f') {	/* ^O -- should support a sequence */
-				sysrq_pressed = 1;
-				continue;
-			} else if (sysrq_pressed) {
-				handle_sysrq(buf[i], NULL, tty);
-				sysrq_pressed = 0;
-				continue;
+			if (hp->index == hvc_con_driver.index) {
+				/* Handle the SysRq Hack */
+				/* XXX should support a sequence */
+				if (buf[i] == '\x0f') {	/* ^O */
+					sysrq_pressed = 1;
+					continue;
+				} else if (sysrq_pressed) {
+					handle_sysrq(buf[i], NULL, tty);
+					sysrq_pressed = 0;
+					continue;
+				}
 			}
 #endif /* CONFIG_MAGIC_SYSRQ */
 			tty_insert_flip_char(tty, buf[i], 0);
@@ -497,8 +640,8 @@
 
 		/*
 		 * Account for the total amount read in one loop, and if above
-		 * 64 bytes, we do a quick schedule loop to let the tty grok the
-		 * data and eventually throttle us.
+		 * 64 bytes, we do a quick schedule loop to let the tty grok
+		 * the data and eventually throttle us.
 		 */
 		read_total += n;
 		if (read_total >= 64) {
@@ -542,7 +685,6 @@
 		if (cpus_empty(cpus_in_xmon)) {
 			spin_lock(&hvc_structs_lock);
 			list_for_each_entry(hp, &hvc_structs, next) {
-				/*hp = list_entry(node, struct hvc_struct, * next); */
 				poll_mask |= hvc_poll(hp);
 			}
 			spin_unlock(&hvc_structs_lock);
@@ -577,14 +719,6 @@
 	.chars_in_buffer = hvc_chars_in_buffer,
 };
 
-char hvc_driver_name[] = "hvc_console";
-
-static struct vio_device_id hvc_driver_table[] __devinitdata= {
-	{"serial", "hvterm1"},
-	{ NULL, }
-};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
-
 /* callback when the kboject ref count reaches zero. */
 static void destroy_hvc_struct(struct kobject *kobj)
 {
@@ -606,41 +740,51 @@
 	.release = destroy_hvc_struct,
 };
 
-static int __devinit hvc_probe(
-		struct vio_dev *dev,
-		const struct vio_device_id *id)
+struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
+					struct hv_ops *ops)
 {
 	struct hvc_struct *hp;
-
-	/* probed with invalid parameters. */
-	if (!dev || !id)
-		return -EPERM;
+	int i;
 
 	hp = kmalloc(sizeof(*hp), GFP_KERNEL);
 	if (!hp)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	memset(hp, 0x00, sizeof(*hp));
-	hp->vtermno = dev->unit_address;
-	hp->vdev = dev;
-	hp->vdev->dev.driver_data = hp;
-	hp->irq = dev->irq;
+
+	hp->vtermno = vtermno;
+	hp->irq = irq;
+	hp->ops = ops;
 
 	kobject_init(&hp->kobj);
 	hp->kobj.ktype = &hvc_kobj_type;
 
 	spin_lock_init(&hp->lock);
 	spin_lock(&hvc_structs_lock);
-	hp->index = ++hvc_count;
+
+	/*
+	 * find index to use:
+	 * see if this vterm id matches one registered for console.
+	 */
+	for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
+		if (vtermnos[i] == hp->vtermno)
+			break;
+
+	/* no matching slot, just use a counter */
+	if (i >= MAX_NR_HVC_CONSOLES)
+		i = ++last_hvc;
+
+	hp->index = i;
+
 	list_add_tail(&(hp->next), &hvc_structs);
 	spin_unlock(&hvc_structs_lock);
 
-	return 0;
+	return hp;
 }
+EXPORT_SYMBOL(hvc_alloc);
 
-static int __devexit hvc_remove(struct vio_dev *dev)
+int __devexit hvc_remove(struct hvc_struct *hp)
 {
-	struct hvc_struct *hp = dev->dev.driver_data;
 	unsigned long flags;
 	struct kobject *kobjp;
 	struct tty_struct *tty;
@@ -673,23 +817,14 @@
 		tty_hangup(tty);
 	return 0;
 }
-
-static struct vio_driver hvc_vio_driver = {
-	.name		= hvc_driver_name,
-	.id_table	= hvc_driver_table,
-	.probe		= hvc_probe,
-	.remove		= hvc_remove,
-};
+EXPORT_SYMBOL(hvc_remove);
 
 /* Driver initialization.  Follow console initialization.  This is where the TTY
  * interfaces start to become available. */
 int __init hvc_init(void)
 {
-	int rc;
-
-	/* We need more than num_vterms adapters due to hotplug additions. */
+	/* We need more than hvc_count adapters due to hotplug additions. */
 	hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
-	/* hvc_driver = alloc_tty_driver(num_vterms); */
 	if (!hvc_driver)
 		return -ENOMEM;
 
@@ -716,116 +851,20 @@
 		return -EIO;
 	}
 
-	/* Register as a vio device to receive callbacks */
-	rc = vio_register_driver(&hvc_vio_driver);
-
-	return rc;
+	return 0;
 }
+module_init(hvc_init);
 
-/* This isn't particularily necessary due to this being a console driver but it
- * is nice to be thorough */
+/* This isn't particularily necessary due to this being a console driver
+ * but it is nice to be thorough.
+ */
 static void __exit hvc_exit(void)
 {
 	kthread_stop(hvc_task);
 
-	vio_unregister_driver(&hvc_vio_driver);
 	tty_unregister_driver(hvc_driver);
 	/* return tty_struct instances allocated in hvc_init(). */
 	put_tty_driver(hvc_driver);
+	unregister_console(&hvc_con_driver);
 }
-
-/*
- * Console APIs, NOT TTY.  These APIs are available immediately when
- * hvc_console_setup() finds adapters.
- */
-
-/*
- * hvc_instantiate() is an early console discovery method which locates consoles
- * prior to the vio subsystem discovering them.  Hotplugged vty adapters do NOT
- * get an hvc_instantiate() callback since the appear after early console init.
- */
-int hvc_instantiate(uint32_t vtermno, int index)
-{
-	if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
-		return -1;
-
-	if (vtermnos[index] != -1)
-		return -1;
-
-	vtermnos[index] = vtermno;
-	return 0;
-}
-
-void hvc_console_print(struct console *co, const char *b, unsigned count)
-{
-	char c[16] __ALIGNED__;
-	unsigned i = 0, n = 0;
-	int r, donecr = 0;
-
-	/* Console access attempt outside of acceptable console range. */
-	if (co->index >= MAX_NR_HVC_CONSOLES)
-		return;
-
-	/* This console adapter was removed so it is not useable. */
-	if (vtermnos[co->index] < 0)
-		return;
-
-	while (count > 0 || i > 0) {
-		if (count > 0 && i < sizeof(c)) {
-			if (b[n] == '\n' && !donecr) {
-				c[i++] = '\r';
-				donecr = 1;
-			} else {
-				c[i++] = b[n++];
-				donecr = 0;
-				--count;
-			}
-		} else {
-			r = hvc_put_chars(vtermnos[co->index], c, i);
-			if (r < 0) {
-				/* throw away chars on error */
-				i = 0;
-			} else if (r > 0) {
-				i -= r;
-				if (i > 0)
-					memmove(c, c+r, i);
-			}
-		}
-	}
-}
-
-static struct tty_driver *hvc_console_device(struct console *c, int *index)
-{
-	*index = c->index;
-	return hvc_driver;
-}
-
-static int __init hvc_console_setup(struct console *co, char *options)
-{
-	return 0;
-}
-
-struct console hvc_con_driver = {
-	.name		= "hvc",
-	.write		= hvc_console_print,
-	.device		= hvc_console_device,
-	.setup		= hvc_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-};
-
-/* Early console initialization.  Preceeds driver initialization. */
-static int __init hvc_console_init(void)
-{
-	int i;
-
-	for (i=0; i<MAX_NR_HVC_CONSOLES; i++)
-		vtermnos[i] = -1;
-	num_vterms = hvc_find_vtys();
-	register_console(&hvc_con_driver);
-	return 0;
-}
-console_initcall(hvc_console_init);
-
-module_init(hvc_init);
 module_exit(hvc_exit);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
new file mode 100644
index 0000000..60bb915
--- /dev/null
+++ b/drivers/char/hvc_vio.c
@@ -0,0 +1,152 @@
+/*
+ * vio driver interface to hvc_console.c
+ *
+ * This code was moved here to allow the remaing code to be reused as a
+ * generic polling mode with semi-reliable transport driver core to the
+ * console and tty subsystems.
+ *
+ *
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Additional Author(s):
+ *  Ryan S. Arnold <rsa@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <asm/hvconsole.h>
+#include <asm/vio.h>
+#include <asm/prom.h>
+
+char hvc_driver_name[] = "hvc_console";
+
+static struct vio_device_id hvc_driver_table[] __devinitdata = {
+	{"serial", "hvterm1"},
+	{ NULL, }
+};
+MODULE_DEVICE_TABLE(vio, hvc_driver_table);
+
+static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
+{
+	unsigned long got;
+	int i;
+
+	got = hvc_get_chars(vtermno, buf, count);
+
+	/*
+	 * Work around a HV bug where it gives us a null
+	 * after every \r.  -- paulus
+	 */
+	for (i = 1; i < got; ++i) {
+		if (buf[i] == 0 && buf[i-1] == '\r') {
+			--got;
+			if (i < got)
+				memmove(&buf[i], &buf[i+1],
+					got - i);
+		}
+	}
+	return got;
+}
+
+static struct hv_ops hvc_get_put_ops = {
+	.get_chars = filtered_get_chars,
+	.put_chars = hvc_put_chars,
+};
+
+static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+				const struct vio_device_id *id)
+{
+	struct hvc_struct *hp;
+
+	/* probed with invalid parameters. */
+	if (!vdev || !id)
+		return -EPERM;
+
+	hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops);
+	if (IS_ERR(hp))
+		return PTR_ERR(hp);
+	dev_set_drvdata(&vdev->dev, hp);
+
+	return 0;
+}
+
+static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+{
+	struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
+
+	return hvc_remove(hp);
+}
+
+static struct vio_driver hvc_vio_driver = {
+	.name		= hvc_driver_name,
+	.id_table	= hvc_driver_table,
+	.probe		= hvc_vio_probe,
+	.remove		= hvc_vio_remove,
+	.driver		= {
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int hvc_vio_init(void)
+{
+	int rc;
+
+	/* Register as a vio device to receive callbacks */
+	rc = vio_register_driver(&hvc_vio_driver);
+
+	return rc;
+}
+module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
+
+static void hvc_vio_exit(void)
+{
+	vio_unregister_driver(&hvc_vio_driver);
+}
+module_exit(hvc_vio_exit);
+
+/* the device tree order defines our numbering */
+static int hvc_find_vtys(void)
+{
+	struct device_node *vty;
+	int num_found = 0;
+
+	for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
+			vty = of_find_node_by_name(vty, "vty")) {
+		uint32_t *vtermno;
+
+		/* We have statically defined space for only a certain number
+		 * of console adapters.
+		 */
+		if (num_found >= MAX_NR_HVC_CONSOLES)
+			break;
+
+		vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+		if (!vtermno)
+			continue;
+
+		if (device_is_compatible(vty, "hvterm1")) {
+			hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
+			++num_found;
+		}
+	}
+
+	return num_found;
+}
+console_initcall(hvc_find_vtys);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index f1f1192..a22aa94 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -291,15 +291,13 @@
 	dump_hex(packet, header->len);
 }
 
-/* can't use hvc_get_chars because that strips CRs */
 static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
 {
 	unsigned long got;
 
-	if (plpar_hcall(H_GET_TERM_CHAR, hp->vtermno, 0, 0, 0, &got,
-			(unsigned long *)buf, (unsigned long *)buf+1) == H_Success)
-		return got;
-	return 0;
+	got = hvc_get_chars(hp->vtermno, buf, count);
+
+	return got;
 }
 
 static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index edba5a3..09103b3 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -770,10 +770,8 @@
 		}
 		if (c == '\n') {
 			if (L_ECHO(tty) || L_ECHONL(tty)) {
-				if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
+				if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
 					put_char('\a', tty);
-					return;
-				}
 				opost('\n', tty);
 			}
 			goto handle_newline;
@@ -790,10 +788,8 @@
 			 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
 			 */
 			if (L_ECHO(tty)) {
-				if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
+				if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
 					put_char('\a', tty);
-					return;
-				}
 				/* Record the column of first canon char. */
 				if (tty->canon_head == tty->read_head)
 					tty->canon_column = tty->column;
@@ -862,12 +858,9 @@
 	 * that erase characters will be handled.  Other excess
 	 * characters will be beeped.
 	 */
-	if (tty->icanon && !tty->canon_data)
-		return N_TTY_BUF_SIZE;
-
-	if (left > 0)
-		return left;
-	return 0;
+	if (left <= 0)
+		left = tty->icanon && !tty->canon_data;
+	return left;
 }
 
 /**
@@ -1473,13 +1466,17 @@
 			if (tty->driver->flush_chars)
 				tty->driver->flush_chars(tty);
 		} else {
-			c = tty->driver->write(tty, b, nr);
-			if (c < 0) {
-				retval = c;
-				goto break_out;
+			while (nr > 0) {
+				c = tty->driver->write(tty, b, nr);
+				if (c < 0) {
+					retval = c;
+					goto break_out;
+				}
+				if (!c)
+					break;
+				b += c;
+				nr -= c;
 			}
-			b += c;
-			nr -= c;
 		}
 		if (!nr)
 			break;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 8f36b17..7a0c7464 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -71,7 +71,6 @@
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -593,11 +592,6 @@
     dev_list = link;
 
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &mgslpc_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
 
@@ -3093,6 +3087,7 @@
 		.name	= "synclink_cs",
 	},
 	.attach		= mgslpc_attach,
+	.event		= mgslpc_event,
 	.detach		= mgslpc_detach,
 	.id_table	= mgslpc_ids,
 };
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 460b5d4..6b11d6b 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -271,7 +271,7 @@
  * samples to avoid wasting CPU time and reduce lock contention.
  */
 
-static int trickle_thresh = INPUT_POOL_WORDS * 28;
+static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28;
 
 static DEFINE_PER_CPU(int, trickle_count) = 0;
 
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index af79805..12d563c 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -228,7 +228,7 @@
 
 static void moom_callback(void *ignored)
 {
-	out_of_memory(GFP_KERNEL);
+	out_of_memory(GFP_KERNEL, 0);
 }
 
 static DECLARE_WORK(moom_work, moom_callback, NULL);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index bf62dfe..7a7859d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -869,7 +869,7 @@
  *	cpufreq_suspend - let the low level driver prepare for suspend
  */
 
-static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
+static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
 {
 	int cpu = sysdev->id;
 	unsigned int ret = 0;
@@ -897,7 +897,7 @@
 	}
 
 	if (cpufreq_driver->suspend) {
-		ret = cpufreq_driver->suspend(cpu_policy, state);
+		ret = cpufreq_driver->suspend(cpu_policy, pmsg);
 		if (ret) {
 			printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
 					"step on CPU %u\n", cpu_policy->cpu);
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index ed708b4..71407c5 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -49,6 +49,7 @@
 #include <linux/errno.h>
 #include <linux/crypto.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <asm/byteorder.h>
 #include "padlock.h"
 
@@ -59,8 +60,12 @@
 #define AES_EXTENDED_KEY_SIZE_B	(AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
 
 struct aes_ctx {
-	uint32_t e_data[AES_EXTENDED_KEY_SIZE+4];
-	uint32_t d_data[AES_EXTENDED_KEY_SIZE+4];
+	uint32_t e_data[AES_EXTENDED_KEY_SIZE];
+	uint32_t d_data[AES_EXTENDED_KEY_SIZE];
+	struct {
+		struct cword encrypt;
+		struct cword decrypt;
+	} cword;
 	uint32_t *E;
 	uint32_t *D;
 	int key_length;
@@ -280,10 +285,15 @@
 	return 0;
 }
 
+static inline struct aes_ctx *aes_ctx(void *ctx)
+{
+	return (struct aes_ctx *)ALIGN((unsigned long)ctx, PADLOCK_ALIGNMENT);
+}
+
 static int
 aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags)
 {
-	struct aes_ctx *ctx = ctx_arg;
+	struct aes_ctx *ctx = aes_ctx(ctx_arg);
 	uint32_t i, t, u, v, w;
 	uint32_t P[AES_EXTENDED_KEY_SIZE];
 	uint32_t rounds;
@@ -295,25 +305,36 @@
 
 	ctx->key_length = key_len;
 
+	/*
+	 * If the hardware is capable of generating the extended key
+	 * itself we must supply the plain key for both encryption
+	 * and decryption.
+	 */
 	ctx->E = ctx->e_data;
-	ctx->D = ctx->d_data;
-
-	/* Ensure 16-Bytes alignmentation of keys for VIA PadLock. */
-	if ((int)(ctx->e_data) & 0x0F)
-		ctx->E += 4 - (((int)(ctx->e_data) & 0x0F) / sizeof (ctx->e_data[0]));
-
-	if ((int)(ctx->d_data) & 0x0F)
-		ctx->D += 4 - (((int)(ctx->d_data) & 0x0F) / sizeof (ctx->d_data[0]));
+	ctx->D = ctx->e_data;
 
 	E_KEY[0] = uint32_t_in (in_key);
 	E_KEY[1] = uint32_t_in (in_key + 4);
 	E_KEY[2] = uint32_t_in (in_key + 8);
 	E_KEY[3] = uint32_t_in (in_key + 12);
 
+	/* Prepare control words. */
+	memset(&ctx->cword, 0, sizeof(ctx->cword));
+
+	ctx->cword.decrypt.encdec = 1;
+	ctx->cword.encrypt.rounds = 10 + (key_len - 16) / 4;
+	ctx->cword.decrypt.rounds = ctx->cword.encrypt.rounds;
+	ctx->cword.encrypt.ksize = (key_len - 16) / 8;
+	ctx->cword.decrypt.ksize = ctx->cword.encrypt.ksize;
+
 	/* Don't generate extended keys if the hardware can do it. */
 	if (aes_hw_extkey_available(key_len))
 		return 0;
 
+	ctx->D = ctx->d_data;
+	ctx->cword.encrypt.keygen = 1;
+	ctx->cword.decrypt.keygen = 1;
+
 	switch (key_len) {
 	case 16:
 		t = E_KEY[3];
@@ -369,10 +390,9 @@
 
 /* ====== Encryption/decryption routines ====== */
 
-/* This is the real call to PadLock. */
-static inline void
-padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key,
-		   void *control_word, uint32_t count)
+/* These are the real call to PadLock. */
+static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
+				      void *control_word, u32 count)
 {
 	asm volatile ("pushfl; popfl");		/* enforce key reload. */
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
@@ -380,60 +400,70 @@
 		      : "d"(control_word), "b"(key), "c"(count));
 }
 
-static void
-aes_padlock(void *ctx_arg, uint8_t *out_arg, const uint8_t *in_arg, int encdec)
+static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
+				     u8 *iv, void *control_word, u32 count)
 {
-	/* Don't blindly modify this structure - the items must 
-	   fit on 16-Bytes boundaries! */
-	struct padlock_xcrypt_data {
-		uint8_t buf[AES_BLOCK_SIZE];
-		union cword cword;
-	};
-
-	struct aes_ctx *ctx = ctx_arg;
-	char bigbuf[sizeof(struct padlock_xcrypt_data) + 16];
-	struct padlock_xcrypt_data *data;
-	void *key;
-
-	/* Place 'data' at the first 16-Bytes aligned address in 'bigbuf'. */
-	if (((long)bigbuf) & 0x0F)
-		data = (void*)(bigbuf + 16 - ((long)bigbuf & 0x0F));
-	else
-		data = (void*)bigbuf;
-
-	/* Prepare Control word. */
-	memset (data, 0, sizeof(struct padlock_xcrypt_data));
-	data->cword.b.encdec = !encdec;	/* in the rest of cryptoapi ENC=1/DEC=0 */
-	data->cword.b.rounds = 10 + (ctx->key_length - 16) / 4;
-	data->cword.b.ksize = (ctx->key_length - 16) / 8;
-
-	/* Is the hardware capable to generate the extended key? */
-	if (!aes_hw_extkey_available(ctx->key_length))
-		data->cword.b.keygen = 1;
-
-	/* ctx->E starts with a plain key - if the hardware is capable
-	   to generate the extended key itself we must supply
-	   the plain key for both Encryption and Decryption. */
-	if (encdec == CRYPTO_DIR_ENCRYPT || data->cword.b.keygen == 0)
-		key = ctx->E;
-	else
-		key = ctx->D;
-	
-	memcpy(data->buf, in_arg, AES_BLOCK_SIZE);
-	padlock_xcrypt_ecb(data->buf, data->buf, key, &data->cword, 1);
-	memcpy(out_arg, data->buf, AES_BLOCK_SIZE);
+	/* Enforce key reload. */
+	asm volatile ("pushfl; popfl");
+	/* rep xcryptcbc */
+	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
+		      : "+S" (input), "+D" (output), "+a" (iv)
+		      : "d" (control_word), "b" (key), "c" (count));
+	return iv;
 }
 
 static void
 aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
 {
-	aes_padlock(ctx_arg, out, in, CRYPTO_DIR_ENCRYPT);
+	struct aes_ctx *ctx = aes_ctx(ctx_arg);
+	padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1);
 }
 
 static void
 aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
 {
-	aes_padlock(ctx_arg, out, in, CRYPTO_DIR_DECRYPT);
+	struct aes_ctx *ctx = aes_ctx(ctx_arg);
+	padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1);
+}
+
+static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt,
+			   nbytes / AES_BLOCK_SIZE);
+	return nbytes & ~(AES_BLOCK_SIZE - 1);
+}
+
+static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt,
+			   nbytes / AES_BLOCK_SIZE);
+	return nbytes & ~(AES_BLOCK_SIZE - 1);
+}
+
+static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	u8 *iv;
+
+	iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info,
+				&ctx->cword.encrypt, nbytes / AES_BLOCK_SIZE);
+	memcpy(desc->info, iv, AES_BLOCK_SIZE);
+
+	return nbytes & ~(AES_BLOCK_SIZE - 1);
+}
+
+static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt,
+			   nbytes / AES_BLOCK_SIZE);
+	return nbytes & ~(AES_BLOCK_SIZE - 1);
 }
 
 static struct crypto_alg aes_alg = {
@@ -441,6 +471,7 @@
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	AES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct aes_ctx),
+	.cra_alignmask		=	PADLOCK_ALIGNMENT - 1,
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
 	.cra_u			=	{
@@ -449,7 +480,11 @@
 			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
 			.cia_setkey	   	= 	aes_set_key,
 			.cia_encrypt	 	=	aes_encrypt,
-			.cia_decrypt	  	=	aes_decrypt
+			.cia_decrypt	  	=	aes_decrypt,
+			.cia_encrypt_ecb 	=	aes_encrypt_ecb,
+			.cia_decrypt_ecb  	=	aes_decrypt_ecb,
+			.cia_encrypt_cbc 	=	aes_encrypt_cbc,
+			.cia_decrypt_cbc  	=	aes_decrypt_cbc,
 		}
 	}
 };
diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h
index 7a50060..3cf2b7a 100644
--- a/drivers/crypto/padlock.h
+++ b/drivers/crypto/padlock.h
@@ -13,18 +13,18 @@
 #ifndef _CRYPTO_PADLOCK_H
 #define _CRYPTO_PADLOCK_H
 
+#define PADLOCK_ALIGNMENT 16
+
 /* Control word. */
-union cword {
-	uint32_t cword[4];
-	struct {
-		int rounds:4;
-		int algo:3;
-		int keygen:1;
-		int interm:1;
-		int encdec:1;
-		int ksize:2;
-	} b;
-};
+struct cword {
+	int __attribute__ ((__packed__))
+		rounds:4,
+		algo:3,
+		keygen:1,
+		interm:1,
+		encdec:1,
+		ksize:2;
+} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
 
 #define PFX	"padlock: "
 
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
index 363e545..94ae808 100644
--- a/drivers/i2c/busses/i2c-keywest.c
+++ b/drivers/i2c/busses/i2c-keywest.c
@@ -698,7 +698,7 @@
 }
 
 static int
-create_iface_macio(struct macio_dev* dev, const struct of_match *match)
+create_iface_macio(struct macio_dev* dev, const struct of_device_id *match)
 {
 	return create_iface(dev->ofdev.node, &dev->ofdev.dev);
 }
@@ -710,7 +710,7 @@
 }
 
 static int
-create_iface_of_platform(struct of_device* dev, const struct of_match *match)
+create_iface_of_platform(struct of_device* dev, const struct of_device_id *match)
 {
 	return create_iface(dev->node, &dev->dev);
 }
@@ -721,10 +721,9 @@
 	return dispose_iface(&dev->dev);
 }
 
-static struct of_match i2c_keywest_match[] = 
+static struct of_device_id i2c_keywest_match[] = 
 {
 	{
-	.name 		= OF_ANY_MATCH,
 	.type		= "i2c",
 	.compatible	= "keywest"
 	},
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 978d27d..aac5975 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -46,7 +46,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -134,11 +133,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ide_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -497,6 +491,7 @@
 		.name	= "ide-cs",
 	},
 	.attach		= ide_attach,
+	.event		= ide_event,
 	.detach		= ide_detach,
 	.id_table       = ide_ids,
 };
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 818380b..be0fcc8 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1419,7 +1419,7 @@
  * Attach to a macio probed interface
  */
 static int __devinit
-pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match)
+pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	void __iomem *base;
 	unsigned long regbase;
@@ -1637,27 +1637,19 @@
 	return rc;
 }
 
-static struct of_match pmac_ide_macio_match[] = 
+static struct of_device_id pmac_ide_macio_match[] = 
 {
 	{
 	.name 		= "IDE",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{
 	.name 		= "ATA",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{
-	.name 		= OF_ANY_MATCH,
 	.type		= "ide",
-	.compatible	= OF_ANY_MATCH
 	},
 	{
-	.name 		= OF_ANY_MATCH,
 	.type		= "ata",
-	.compatible	= OF_ANY_MATCH
 	},
 	{},
 };
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 7d58af1..25103a0 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -66,6 +66,18 @@
 	  with MacOSX and WinXP IP-over-1394), enable this option and the
 	  eth1394 option below.
 
+config IEEE1394_EXPORT_FULL_API
+	bool "Export all symbols of ieee1394's API"
+	depends on IEEE1394
+	default n
+	help
+	  Export all symbols of ieee1394's driver programming interface, even
+	  those that are not currently used by the standard IEEE 1394 drivers.
+
+	  This option does not affect the interface to userspace applications.
+	  Say Y here if you want to compile externally developed drivers that
+	  make extended use of ieee1394's API. It is otherwise safe to say N.
+
 comment "Device Drivers"
 	depends on IEEE1394
 
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index 1b98684..149573d 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -28,6 +28,7 @@
 #include "hosts.h"
 #include "ieee1394.h"
 #include "highlevel.h"
+#include "ieee1394_core.h"
 
 /* Module Parameters */
 /* this module parameter can be used to disable mapping of the FCP registers */
@@ -232,7 +233,7 @@
 	host->csr.generation = 2;
 
 	bus_info[1] = __constant_cpu_to_be32(0x31333934);
-	bus_info[2] = cpu_to_be32((1 << CSR_IRMC_SHIFT) |
+	bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
 				  (1 << CSR_CMC_SHIFT) |
 				  (1 << CSR_ISC_SHIFT) |
 				  (0 << CSR_BMC_SHIFT) |
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index 7c4330e..61ddd5d 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -209,7 +209,15 @@
 {
 	static const int mr_map[] = { 4, 64, 1024, 0 };
 
+#ifdef __KERNEL__
+	BUG_ON(max_rom & ~0x3);
 	csr->max_rom = mr_map[max_rom];
+#else
+	if (max_rom & ~0x3) /* caller supplied invalid argument */
+		csr->max_rom = 0;
+	else
+		csr->max_rom = mr_map[max_rom];
+#endif
 	memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
 }
 
@@ -533,12 +541,15 @@
 	static const int pd[4] = { 0, 4, 16, 256 };
 	static const int cs[16] = { 4, 2 };
 	struct csr1212_keyval *kv;
-	int palette_size = pd[palette_depth] * cs[color_space];
+	int palette_size;
 	int pixel_size = (hscan * vscan + 3) & ~0x3;
 
-	if ((palette_depth && !palette) || !pixels)
+	if (!pixels || (!palette && palette_depth) ||
+	    (palette_depth & ~0x3) || (color_space & ~0xf))
 		return NULL;
 
+	palette_size = pd[palette_depth] * cs[color_space];
+
 	kv = csr1212_new_descriptor_leaf(1, 0, NULL,
 					 palette_size + pixel_size +
 					 CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD);
@@ -760,9 +771,9 @@
 	struct csr1212_csr_rom_cache *cache;
 	u_int64_t csr_addr;
 
-	if (!csr || !csr->ops->allocate_addr_range ||
-	    !csr->ops->release_addr)
-		return CSR1212_ENOMEM;
+	if (!csr || !csr->ops || !csr->ops->allocate_addr_range ||
+	    !csr->ops->release_addr || csr->max_rom < 1)
+		return CSR1212_EINVAL;
 
 	/* ROM size must be a multiple of csr->max_rom */
 	romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
@@ -1145,6 +1156,8 @@
 
 			/* Make sure the Extended ROM leaf is a multiple of
 			 * max_rom in size. */
+			if (csr->max_rom < 1)
+				return CSR1212_EINVAL;
 			leaf_size = (cache->len + (csr->max_rom - 1)) &
 				~(csr->max_rom - 1);
 
@@ -1409,7 +1422,7 @@
 	u_int32_t *cache_ptr;
 	u_int16_t kv_len = 0;
 
-	if (!csr || !kv)
+	if (!csr || !kv || csr->max_rom < 1)
 		return CSR1212_EINVAL;
 
 	/* First find which cache the data should be in (or go in if not read
@@ -1572,7 +1585,7 @@
 	struct csr1212_dentry *dentry;
 	int ret;
 
-	if (!csr || !csr->ops->bus_read)
+	if (!csr || !csr->ops || !csr->ops->bus_read)
 		return CSR1212_EINVAL;
 
 	ret = csr1212_parse_bus_info_block(csr);
@@ -1581,9 +1594,13 @@
 
 	if (!csr->ops->get_max_rom)
 		csr->max_rom = mr_map[0];	/* default value */
-	else
-		csr->max_rom = mr_map[csr->ops->get_max_rom(csr->bus_info_data,
-							    csr->private)];
+	else {
+		int i = csr->ops->get_max_rom(csr->bus_info_data,
+					      csr->private);
+		if (i & ~0x3)
+			return CSR1212_EINVAL;
+		csr->max_rom = mr_map[i];
+	}
 
 	csr->cache_head->layout_head = csr->root_kv;
 	csr->cache_head->layout_tail = csr->root_kv;
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
index 758819d..b79ddb4 100644
--- a/drivers/ieee1394/dma.c
+++ b/drivers/ieee1394/dma.c
@@ -158,7 +158,7 @@
 
 dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset)
 {
-	unsigned long rem;
+	unsigned long rem = 0;
 
 	struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)];
 	return sg_dma_address(sg) + rem;
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 654da76..cd53c17 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -89,7 +89,7 @@
 #define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
 
 static char version[] __devinitdata =
-	"$Rev: 1247 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1264 $ Ben Collins <bcollins@debian.org>";
 
 struct fragment_info {
 	struct list_head list;
@@ -706,7 +706,7 @@
 		return;
 
 	dev = hi->dev;
-	priv = netdev_priv(dev);
+	priv = (struct eth1394_priv *)netdev_priv(dev);
 
 	/* Reset our private host data, but not our mtu */
 	netif_stop_queue (dev);
@@ -1770,7 +1770,7 @@
 static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	strcpy (info->driver, driver_name);
-	strcpy (info->version, "$Rev: 1247 $");
+	strcpy (info->version, "$Rev: 1264 $");
 	/* FIXME XXX provide sane businfo */
 	strcpy (info->bus_info, "ieee1394");
 }
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 629070b..b248d89 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -52,7 +52,7 @@
 /*
  * Disable the nodemgr detection and config rom reading functionality.
  */
-static int disable_nodemgr = 0;
+static int disable_nodemgr;
 module_param(disable_nodemgr, int, 0444);
 MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
 
@@ -520,6 +520,9 @@
 
 	if (!packet->no_waiter || packet->expect_response) {
 		atomic_inc(&packet->refcnt);
+		/* Set the initial "sendtime" to 10 seconds from now, to
+		   prevent premature expiry.  If a packet takes more than
+		   10 seconds to hit the wire, we have bigger problems :) */
 		packet->sendtime = jiffies + 10 * HZ;
 		skb_queue_tail(&host->pending_packet_queue, packet->skb);
 	}
@@ -1223,9 +1226,7 @@
 EXPORT_SYMBOL(hpsb_set_packet_complete_task);
 EXPORT_SYMBOL(hpsb_alloc_packet);
 EXPORT_SYMBOL(hpsb_free_packet);
-EXPORT_SYMBOL(hpsb_send_phy_config);
 EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_send_packet_and_wait);
 EXPORT_SYMBOL(hpsb_reset_bus);
 EXPORT_SYMBOL(hpsb_bus_reset);
 EXPORT_SYMBOL(hpsb_selfid_received);
@@ -1233,6 +1234,10 @@
 EXPORT_SYMBOL(hpsb_packet_sent);
 EXPORT_SYMBOL(hpsb_packet_received);
 EXPORT_SYMBOL_GPL(hpsb_disable_irm);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
+EXPORT_SYMBOL(hpsb_send_phy_config);
+EXPORT_SYMBOL(hpsb_send_packet_and_wait);
+#endif
 
 /** ieee1394_transactions.c **/
 EXPORT_SYMBOL(hpsb_get_tlabel);
@@ -1262,9 +1267,11 @@
 EXPORT_SYMBOL(hpsb_set_hostinfo_key);
 EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
 EXPORT_SYMBOL(hpsb_set_hostinfo);
+EXPORT_SYMBOL(highlevel_host_reset);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
 EXPORT_SYMBOL(highlevel_add_host);
 EXPORT_SYMBOL(highlevel_remove_host);
-EXPORT_SYMBOL(highlevel_host_reset);
+#endif
 
 /** nodemgr.c **/
 EXPORT_SYMBOL(hpsb_node_fill_packet);
@@ -1272,7 +1279,9 @@
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(ieee1394_bus_type);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
 EXPORT_SYMBOL(nodemgr_for_each_host);
+#endif
 
 /** csr.c **/
 EXPORT_SYMBOL(hpsb_update_config_rom);
@@ -1309,19 +1318,21 @@
 EXPORT_SYMBOL(hpsb_iso_recv_flush);
 
 /** csr1212.c **/
+EXPORT_SYMBOL(csr1212_new_directory);
+EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
+EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
+EXPORT_SYMBOL(csr1212_release_keyval);
+EXPORT_SYMBOL(csr1212_read);
+EXPORT_SYMBOL(csr1212_parse_keyval);
+EXPORT_SYMBOL(_csr1212_read_keyval);
+EXPORT_SYMBOL(_csr1212_destroy_keyval);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
 EXPORT_SYMBOL(csr1212_create_csr);
 EXPORT_SYMBOL(csr1212_init_local_csr);
 EXPORT_SYMBOL(csr1212_new_immediate);
-EXPORT_SYMBOL(csr1212_new_directory);
 EXPORT_SYMBOL(csr1212_associate_keyval);
-EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
 EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_release_keyval);
 EXPORT_SYMBOL(csr1212_destroy_csr);
-EXPORT_SYMBOL(csr1212_read);
 EXPORT_SYMBOL(csr1212_generate_csr_image);
-EXPORT_SYMBOL(csr1212_parse_keyval);
 EXPORT_SYMBOL(csr1212_parse_csr);
-EXPORT_SYMBOL(_csr1212_read_keyval);
-EXPORT_SYMBOL(_csr1212_destroy_keyval);
+#endif
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index 73bd8ef..0b31429 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -38,8 +38,8 @@
 
         /* These are core internal. */
         signed char tlabel;
-        char ack_code;
-        char tcode;
+	signed char ack_code;
+	unsigned char tcode;
 
         unsigned expect_response:1;
         unsigned no_waiter:1;
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
index f057591..615541b 100644
--- a/drivers/ieee1394/iso.c
+++ b/drivers/ieee1394/iso.c
@@ -62,10 +62,10 @@
 	if ((dma_mode < HPSB_ISO_DMA_DEFAULT) || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
 		dma_mode=HPSB_ISO_DMA_DEFAULT;
 
+	if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
+ 		irq_interval = buf_packets / 4;
 	if (irq_interval == 0)     /* really interrupt for each packet*/
 		irq_interval = 1;
-	else if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
- 		irq_interval = buf_packets / 4;
 
 	if (channel < -1 || channel >= 64)
 		return NULL;
@@ -106,6 +106,7 @@
 	}
 
 	atomic_set(&iso->overflows, 0);
+	iso->bytes_discarded = 0;
 	iso->flags = 0;
 	iso->prebuffer = 0;
 
@@ -241,12 +242,12 @@
 	iso->xmit_cycle = cycle;
 
 	if (prebuffer < 0)
-		prebuffer = iso->buf_packets;
+		prebuffer = iso->buf_packets - 1;
 	else if (prebuffer == 0)
 		prebuffer = 1;
 
-	if (prebuffer > iso->buf_packets)
-		prebuffer = iso->buf_packets;
+	if (prebuffer >= iso->buf_packets)
+		prebuffer = iso->buf_packets - 1;
 
 	iso->prebuffer = prebuffer;
 
@@ -395,7 +396,7 @@
 }
 
 void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
-			      u16 cycle, u8 channel, u8 tag, u8 sy)
+			      u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy)
 {
 	unsigned long flags;
 	spin_lock_irqsave(&iso->lock, flags);
@@ -403,10 +404,13 @@
 	if (iso->n_ready_packets == iso->buf_packets) {
 		/* overflow! */
 		atomic_inc(&iso->overflows);
+		/* Record size of this discarded packet */
+		iso->bytes_discarded += total_len;
 	} else {
 		struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
 		info->offset = offset;
 		info->len = len;
+		info->total_len = total_len;
 		info->cycle = cycle;
 		info->channel = channel;
 		info->tag = tag;
@@ -437,6 +441,17 @@
 
 		iso->first_packet = (iso->first_packet+1) % iso->buf_packets;
 		iso->n_ready_packets--;
+
+		/* release memory from packets discarded when queue was full  */
+		if (iso->n_ready_packets == 0) { /* Release only after all prior packets handled */
+			if (iso->bytes_discarded != 0) {
+				struct hpsb_iso_packet_info inf;
+				inf.total_len = iso->bytes_discarded;
+				iso->host->driver->isoctl(iso, RECV_RELEASE,
+							(unsigned long) &inf);
+				iso->bytes_discarded = 0;
+			}
+		}
 	}
 	spin_unlock_irqrestore(&iso->lock, flags);
 	return rv;
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
index fb654d9..3efc60b 100644
--- a/drivers/ieee1394/iso.h
+++ b/drivers/ieee1394/iso.h
@@ -47,6 +47,14 @@
 	/* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
 	__u8 tag;
 	__u8 sy;
+
+	/*
+	 * length in bytes of the packet including header/trailer.
+	 * MUST be at structure end, since the first part of this structure is also 
+	 * defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is copied to 
+	 * userspace and is accessed there through libraw1394. 
+	 */
+	__u16 total_len;
 };
 
 enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
@@ -111,6 +119,9 @@
 	/* how many times the buffer has overflowed or underflowed */
 	atomic_t overflows;
 
+	/* Current number of bytes lost in discarded packets */
+	int bytes_discarded;
+
 	/* private flags to track initialization progress */
 #define HPSB_ISO_DRIVER_INIT     (1<<0)
 #define HPSB_ISO_DRIVER_STARTED  (1<<1)
@@ -193,7 +204,7 @@
 
 /* call after a packet has been received (interrupt context OK) */
 void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
-			      u16 cycle, u8 channel, u8 tag, u8 sy);
+			      u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy);
 
 /* call to wake waiting processes after buffer space has opened up. */
 void hpsb_iso_wake(struct hpsb_iso *iso);
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 9a46c3b..bebcc47 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -30,7 +30,7 @@
 #include "csr.h"
 #include "nodemgr.h"
 
-static int ignore_drivers = 0;
+static int ignore_drivers;
 module_param(ignore_drivers, int, 0444);
 MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
 
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index b3d3d22..a485f47 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -162,7 +162,7 @@
 printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 1250 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1299 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 static int phys_dma = 1;
@@ -483,7 +483,9 @@
 	/* Put some defaults to these undefined bus options */
 	buf = reg_read(ohci, OHCI1394_BusOptions);
 	buf |=  0x60000000; /* Enable CMC and ISC */
-	if (!hpsb_disable_irm)
+	if (hpsb_disable_irm)
+		buf &= ~0x80000000;
+	else
 		buf |=  0x80000000; /* Enable IRMC */
 	buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
 	buf &= ~0x18000000; /* Disable PMC and BMC */
@@ -503,8 +505,12 @@
 	reg_write(ohci, OHCI1394_LinkControlSet,
 		  OHCI1394_LinkControl_CycleTimerEnable |
 		  OHCI1394_LinkControl_CycleMaster);
-	set_phy_reg_mask(ohci, 4, PHY_04_LCTRL |
-			 (hpsb_disable_irm ? 0 : PHY_04_CONTENDER));
+	i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
+	if (hpsb_disable_irm)
+		i &= ~PHY_04_CONTENDER;
+	else
+		i |= PHY_04_CONTENDER;
+	set_phy_reg(ohci, 4, i);
 
 	/* Set up self-id dma buffer */
 	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
@@ -1566,6 +1572,10 @@
 
 	struct dma_cmd *next = &recv->block[next_i];
 	struct dma_cmd *prev = &recv->block[prev_i];
+	
+	/* ignore out-of-range requests */
+	if ((block < 0) || (block > recv->nblocks))
+		return;
 
 	/* 'next' becomes the new end of the DMA chain,
 	   so disable branch and enable interrupt */
@@ -1593,19 +1603,8 @@
 static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
 					     struct hpsb_iso_packet_info *info)
 {
-	int len;
-
 	/* release the memory where the packet was */
-	len = info->len;
-
-	/* add the wasted space for padding to 4 bytes */
-	if (len % 4)
-		len += 4 - (len % 4);
-
-	/* add 8 bytes for the OHCI DMA data format overhead */
-	len += 8;
-
-	recv->released_bytes += len;
+	recv->released_bytes += info->total_len;
 
 	/* have we released enough memory for one block? */
 	while (recv->released_bytes > recv->buf_stride) {
@@ -1637,7 +1636,7 @@
 		/* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
 
 		unsigned int offset;
-		unsigned short len, cycle;
+		unsigned short len, cycle, total_len;
 		unsigned char channel, tag, sy;
 
 		unsigned char *p = iso->data_buf.kvirt;
@@ -1688,9 +1687,11 @@
 		/* advance to xferStatus/timeStamp */
 		recv->dma_offset += len;
 
+		total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */
 		/* payload is padded to 4 bytes */
 		if (len % 4) {
 			recv->dma_offset += 4 - (len%4);
+			total_len += 4 - (len%4);
 		}
 
 		/* check for wrap-around */
@@ -1724,7 +1725,7 @@
 			recv->dma_offset -= recv->buf_stride*recv->nblocks;
 		}
 
-		hpsb_iso_packet_received(iso, offset, len, cycle, channel, tag, sy);
+		hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy);
 	}
 
 	if (wake)
@@ -1850,7 +1851,8 @@
 			tag = hdr[5] >> 6;
 			sy = hdr[4] & 0xF;
 
-			hpsb_iso_packet_received(iso, offset, packet_len, cycle, channel, tag, sy);
+			hpsb_iso_packet_received(iso, offset, packet_len,
+					recv->buf_stride, cycle, channel, tag, sy);
 		}
 
 		/* reset the DMA descriptor */
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index bdb3a85..36074e6 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -76,7 +76,7 @@
 
 
 /* Module Parameters */
-static int skip_eeprom = 0;
+static int skip_eeprom;
 module_param(skip_eeprom, int, 0444);
 MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0).");
 
@@ -1422,7 +1422,7 @@
 		i = get_phy_reg(lynx, 4);
 		i |= PHY_04_LCTRL;
 		if (hpsb_disable_irm)
-			i &= !PHY_04_CONTENDER;
+			i &= ~PHY_04_CONTENDER;
 		else
 			i |= PHY_04_CONTENDER;
 		if (i != -1) set_phy_reg(lynx, 4, i);
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 7419af4..b4fa147 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -98,7 +98,7 @@
 
 static void queue_complete_cb(struct pending_request *req);
 
-static struct pending_request *__alloc_pending_request(int flags)
+static struct pending_request *__alloc_pending_request(unsigned int __nocast flags)
 {
 	struct pending_request *req;
 
@@ -2506,9 +2506,12 @@
 	if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
 		return -EFAULT;
 
-	if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
+	if (upackets.n_packets >= fi->iso_handle->buf_packets)
 		return -EINVAL;
 
+	if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle))
+		return -EAGAIN;
+
 	/* ensure user-supplied buffer is accessible and big enough */
 	if (!access_ok(VERIFY_READ, upackets.infos,
 			upackets.n_packets *
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 32368f3..fe3e170 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -81,7 +81,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 1219 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1306 $ Ben Collins <bcollins@debian.org>";
 
 /*
  * Module load parameter definitions
@@ -104,7 +104,7 @@
  * down to us at a time (debugging). This might be necessary for very
  * badly behaved sbp2 devices.
  */
-static int serialize_io = 0;
+static int serialize_io;
 module_param(serialize_io, int, 0444);
 MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
 
@@ -145,7 +145,7 @@
  * please submit the logged sbp2_firmware_revision value of this device to
  * the linux1394-devel mailing list.
  */
-static int force_inquiry_hack = 0;
+static int force_inquiry_hack;
 module_param(force_inquiry_hack, int, 0444);
 MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");
 
@@ -2112,6 +2112,102 @@
  */
 static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd)
 {
+	unchar new_cmd[16];
+	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
+
+	SBP2_DEBUG("sbp2_check_sbp2_command");
+
+	switch (*cmd) {
+
+		case READ_6:
+
+			if (sbp2_command_conversion_device_type(device_type)) {
+
+				SBP2_DEBUG("Convert READ_6 to READ_10");
+
+				/*
+				 * Need to turn read_6 into read_10
+				 */
+				new_cmd[0] = 0x28;
+				new_cmd[1] = (cmd[1] & 0xe0);
+				new_cmd[2] = 0x0;
+				new_cmd[3] = (cmd[1] & 0x1f);
+				new_cmd[4] = cmd[2];
+				new_cmd[5] = cmd[3];
+				new_cmd[6] = 0x0;
+				new_cmd[7] = 0x0;
+				new_cmd[8] = cmd[4];
+				new_cmd[9] = cmd[5];
+
+				memcpy(cmd, new_cmd, 10);
+
+			}
+
+			break;
+
+		case WRITE_6:
+
+			if (sbp2_command_conversion_device_type(device_type)) {
+
+				SBP2_DEBUG("Convert WRITE_6 to WRITE_10");
+
+				/*
+				 * Need to turn write_6 into write_10
+				 */
+				new_cmd[0] = 0x2a;
+				new_cmd[1] = (cmd[1] & 0xe0);
+				new_cmd[2] = 0x0;
+				new_cmd[3] = (cmd[1] & 0x1f);
+				new_cmd[4] = cmd[2];
+				new_cmd[5] = cmd[3];
+				new_cmd[6] = 0x0;
+				new_cmd[7] = 0x0;
+				new_cmd[8] = cmd[4];
+				new_cmd[9] = cmd[5];
+
+				memcpy(cmd, new_cmd, 10);
+
+			}
+
+			break;
+
+		case MODE_SENSE:
+
+			if (sbp2_command_conversion_device_type(device_type)) {
+
+				SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10");
+
+				/*
+				 * Need to turn mode_sense_6 into mode_sense_10
+				 */
+				new_cmd[0] = 0x5a;
+				new_cmd[1] = cmd[1];
+				new_cmd[2] = cmd[2];
+				new_cmd[3] = 0x0;
+				new_cmd[4] = 0x0;
+				new_cmd[5] = 0x0;
+				new_cmd[6] = 0x0;
+				new_cmd[7] = 0x0;
+				new_cmd[8] = cmd[4];
+				new_cmd[9] = cmd[5];
+
+				memcpy(cmd, new_cmd, 10);
+
+			}
+
+			break;
+
+		case MODE_SELECT:
+
+			/*
+			 * TODO. Probably need to change mode select to 10 byte version
+			 */
+
+		default:
+			break;
+	}
+
+	return;
 }
 
 /*
@@ -2152,6 +2248,7 @@
 				     struct scsi_cmnd *SCpnt)
 {
 	u8 *scsi_buf = SCpnt->request_buffer;
+	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
 
 	SBP2_DEBUG("sbp2_check_sbp2_response");
 
@@ -2176,6 +2273,14 @@
 			}
 
 			/*
+			 * Check for Simple Direct Access Device and change it to TYPE_DISK
+			 */
+			if ((scsi_buf[0] & 0x1f) == TYPE_RBC) {
+				SBP2_DEBUG("Changing TYPE_RBC to TYPE_DISK");
+				scsi_buf[0] &= 0xe0;
+			}
+
+			/*
 			 * Fix ansi revision and response data format
 			 */
 			scsi_buf[2] |= 2;
@@ -2183,6 +2288,27 @@
 
 			break;
 
+		case MODE_SENSE:
+
+			if (sbp2_command_conversion_device_type(device_type)) {
+
+				SBP2_DEBUG("Modify mode sense response (10 byte version)");
+
+				scsi_buf[0] = scsi_buf[1];	/* Mode data length */
+				scsi_buf[1] = scsi_buf[2];	/* Medium type */
+				scsi_buf[2] = scsi_buf[3];	/* Device specific parameter */
+				scsi_buf[3] = scsi_buf[7];	/* Block descriptor length */
+				memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]);
+			}
+
+			break;
+
+		case MODE_SELECT:
+
+			/*
+			 * TODO. Probably need to change mode select to 10 byte version
+			 */
+
 		default:
 			break;
 	}
@@ -2559,8 +2685,7 @@
 static int sbp2scsi_slave_configure (struct scsi_device *sdev)
 {
 	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
-	sdev->use_10_for_rw = 1;
-	sdev->use_10_for_ms = 1;
+
 	return 0;
 }
 
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 3cc3ff0..79c8e2d 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -7,6 +7,16 @@
 	  any protocols you wish to use as well as drivers for your
 	  InfiniBand hardware.
 
+config INFINIBAND_USER_VERBS
+	tristate "InfiniBand userspace verbs support"
+	depends on INFINIBAND
+	---help---
+	  Userspace InfiniBand verbs support.  This is the kernel side
+	  of userspace verbs, which allows userspace processes to
+	  directly access InfiniBand hardware for fast-path
+	  operations.  You will also need libibverbs and a hardware
+	  driver library from <http://www.openib.org>.
+
 source "drivers/infiniband/hw/mthca/Kconfig"
 
 source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index d2dbfb5..e1a7cf3 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -1,6 +1,7 @@
 EXTRA_CFLAGS += -Idrivers/infiniband/include
 
-obj-$(CONFIG_INFINIBAND) +=	ib_core.o ib_mad.o ib_sa.o ib_umad.o
+obj-$(CONFIG_INFINIBAND) +=		ib_core.o ib_mad.o ib_sa.o ib_umad.o
+obj-$(CONFIG_INFINIBAND_USER_VERBS) +=	ib_uverbs.o
 
 ib_core-y :=			packer.o ud_header.o verbs.o sysfs.o \
 				device.o fmr_pool.o cache.o
@@ -10,3 +11,5 @@
 ib_sa-y :=			sa_query.o
 
 ib_umad-y :=			user_mad.o
+
+ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_mem.o
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
new file mode 100644
index 0000000..57347f1
--- /dev/null
+++ b/drivers/infiniband/core/uverbs.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: uverbs.h 2559 2005-06-06 19:43:16Z roland $
+ */
+
+#ifndef UVERBS_H
+#define UVERBS_H
+
+/* Include device.h and fs.h until cdev.h is self-sufficient */
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/kref.h>
+#include <linux/idr.h>
+
+#include <ib_verbs.h>
+#include <ib_user_verbs.h>
+
+struct ib_uverbs_device {
+	int					devnum;
+	struct cdev				dev;
+	struct class_device			class_dev;
+	struct ib_device		       *ib_dev;
+	int					num_comp;
+};
+
+struct ib_uverbs_event_file {
+	struct kref				ref;
+	struct ib_uverbs_file		       *uverbs_file;
+	spinlock_t				lock;
+	int					fd;
+	int					is_async;
+	wait_queue_head_t			poll_wait;
+	struct list_head			event_list;
+};
+
+struct ib_uverbs_file {
+	struct kref				ref;
+	struct ib_uverbs_device		       *device;
+	struct ib_ucontext		       *ucontext;
+	struct ib_event_handler			event_handler;
+	struct ib_uverbs_event_file	        async_file;
+	struct ib_uverbs_event_file	        comp_file[1];
+};
+
+struct ib_uverbs_async_event {
+	struct ib_uverbs_async_event_desc	desc;
+	struct list_head			list;
+};
+
+struct ib_uverbs_comp_event {
+	struct ib_uverbs_comp_event_desc	desc;
+	struct list_head			list;
+};
+
+struct ib_uobject_mr {
+	struct ib_uobject			uobj;
+	struct page			       *page_list;
+	struct scatterlist		       *sg_list;
+};
+
+extern struct semaphore ib_uverbs_idr_mutex;
+extern struct idr ib_uverbs_pd_idr;
+extern struct idr ib_uverbs_mr_idr;
+extern struct idr ib_uverbs_mw_idr;
+extern struct idr ib_uverbs_ah_idr;
+extern struct idr ib_uverbs_cq_idr;
+extern struct idr ib_uverbs_qp_idr;
+
+void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context);
+void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr);
+void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
+
+int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
+		void *addr, size_t size, int write);
+void ib_umem_release(struct ib_device *dev, struct ib_umem *umem);
+void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem);
+
+#define IB_UVERBS_DECLARE_CMD(name)					\
+	ssize_t ib_uverbs_##name(struct ib_uverbs_file *file,		\
+				 const char __user *buf, int in_len,	\
+				 int out_len)
+
+IB_UVERBS_DECLARE_CMD(query_params);
+IB_UVERBS_DECLARE_CMD(get_context);
+IB_UVERBS_DECLARE_CMD(query_device);
+IB_UVERBS_DECLARE_CMD(query_port);
+IB_UVERBS_DECLARE_CMD(query_gid);
+IB_UVERBS_DECLARE_CMD(query_pkey);
+IB_UVERBS_DECLARE_CMD(alloc_pd);
+IB_UVERBS_DECLARE_CMD(dealloc_pd);
+IB_UVERBS_DECLARE_CMD(reg_mr);
+IB_UVERBS_DECLARE_CMD(dereg_mr);
+IB_UVERBS_DECLARE_CMD(create_cq);
+IB_UVERBS_DECLARE_CMD(destroy_cq);
+IB_UVERBS_DECLARE_CMD(create_qp);
+IB_UVERBS_DECLARE_CMD(modify_qp);
+IB_UVERBS_DECLARE_CMD(destroy_qp);
+IB_UVERBS_DECLARE_CMD(attach_mcast);
+IB_UVERBS_DECLARE_CMD(detach_mcast);
+
+#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
new file mode 100644
index 0000000..5f2bbcd
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $
+ */
+
+#include <asm/uaccess.h>
+
+#include "uverbs.h"
+
+#define INIT_UDATA(udata, ibuf, obuf, ilen, olen)			\
+	do {								\
+		(udata)->inbuf  = (void __user *) (ibuf);		\
+		(udata)->outbuf = (void __user *) (obuf);		\
+		(udata)->inlen  = (ilen);				\
+		(udata)->outlen = (olen);				\
+	} while (0)
+
+ssize_t ib_uverbs_query_params(struct ib_uverbs_file *file,
+			       const char __user *buf,
+			       int in_len, int out_len)
+{
+	struct ib_uverbs_query_params      cmd;
+	struct ib_uverbs_query_params_resp resp;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	memset(&resp, 0, sizeof resp);
+
+	resp.num_cq_events = file->device->num_comp;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp))
+	    return -EFAULT;
+
+	return in_len;
+}
+
+ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
+			      const char __user *buf,
+			      int in_len, int out_len)
+{
+	struct ib_uverbs_get_context      cmd;
+	struct ib_uverbs_get_context_resp resp;
+	struct ib_udata                   udata;
+	struct ib_device                 *ibdev = file->device->ib_dev;
+	int i;
+	int ret = in_len;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	INIT_UDATA(&udata, buf + sizeof cmd,
+		   (unsigned long) cmd.response + sizeof resp,
+		   in_len - sizeof cmd, out_len - sizeof resp);
+
+	file->ucontext = ibdev->alloc_ucontext(ibdev, &udata);
+	if (IS_ERR(file->ucontext)) {
+		ret = PTR_ERR(file->ucontext);
+		file->ucontext = NULL;
+		return ret;
+	}
+
+	file->ucontext->device = ibdev;
+	INIT_LIST_HEAD(&file->ucontext->pd_list);
+	INIT_LIST_HEAD(&file->ucontext->mr_list);
+	INIT_LIST_HEAD(&file->ucontext->mw_list);
+	INIT_LIST_HEAD(&file->ucontext->cq_list);
+	INIT_LIST_HEAD(&file->ucontext->qp_list);
+	INIT_LIST_HEAD(&file->ucontext->srq_list);
+	INIT_LIST_HEAD(&file->ucontext->ah_list);
+	spin_lock_init(&file->ucontext->lock);
+
+	resp.async_fd = file->async_file.fd;
+	for (i = 0; i < file->device->num_comp; ++i)
+		if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab +
+				 i * sizeof (__u32),
+				 &file->comp_file[i].fd, sizeof (__u32)))
+			goto err;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		goto err;
+
+	return in_len;
+
+err:
+	ibdev->dealloc_ucontext(file->ucontext);
+	file->ucontext = NULL;
+
+	return -EFAULT;
+}
+
+ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
+			       const char __user *buf,
+			       int in_len, int out_len)
+{
+	struct ib_uverbs_query_device      cmd;
+	struct ib_uverbs_query_device_resp resp;
+	struct ib_device_attr              attr;
+	int                                ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	ret = ib_query_device(file->device->ib_dev, &attr);
+	if (ret)
+		return ret;
+
+	memset(&resp, 0, sizeof resp);
+
+	resp.fw_ver 		       = attr.fw_ver;
+	resp.node_guid 		       = attr.node_guid;
+	resp.sys_image_guid 	       = attr.sys_image_guid;
+	resp.max_mr_size 	       = attr.max_mr_size;
+	resp.page_size_cap 	       = attr.page_size_cap;
+	resp.vendor_id 		       = attr.vendor_id;
+	resp.vendor_part_id 	       = attr.vendor_part_id;
+	resp.hw_ver 		       = attr.hw_ver;
+	resp.max_qp 		       = attr.max_qp;
+	resp.max_qp_wr 		       = attr.max_qp_wr;
+	resp.device_cap_flags 	       = attr.device_cap_flags;
+	resp.max_sge 		       = attr.max_sge;
+	resp.max_sge_rd 	       = attr.max_sge_rd;
+	resp.max_cq 		       = attr.max_cq;
+	resp.max_cqe 		       = attr.max_cqe;
+	resp.max_mr 		       = attr.max_mr;
+	resp.max_pd 		       = attr.max_pd;
+	resp.max_qp_rd_atom 	       = attr.max_qp_rd_atom;
+	resp.max_ee_rd_atom 	       = attr.max_ee_rd_atom;
+	resp.max_res_rd_atom 	       = attr.max_res_rd_atom;
+	resp.max_qp_init_rd_atom       = attr.max_qp_init_rd_atom;
+	resp.max_ee_init_rd_atom       = attr.max_ee_init_rd_atom;
+	resp.atomic_cap 	       = attr.atomic_cap;
+	resp.max_ee 		       = attr.max_ee;
+	resp.max_rdd 		       = attr.max_rdd;
+	resp.max_mw 		       = attr.max_mw;
+	resp.max_raw_ipv6_qp 	       = attr.max_raw_ipv6_qp;
+	resp.max_raw_ethy_qp 	       = attr.max_raw_ethy_qp;
+	resp.max_mcast_grp 	       = attr.max_mcast_grp;
+	resp.max_mcast_qp_attach       = attr.max_mcast_qp_attach;
+	resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach;
+	resp.max_ah 		       = attr.max_ah;
+	resp.max_fmr 		       = attr.max_fmr;
+	resp.max_map_per_fmr 	       = attr.max_map_per_fmr;
+	resp.max_srq 		       = attr.max_srq;
+	resp.max_srq_wr 	       = attr.max_srq_wr;
+	resp.max_srq_sge 	       = attr.max_srq_sge;
+	resp.max_pkeys 		       = attr.max_pkeys;
+	resp.local_ca_ack_delay        = attr.local_ca_ack_delay;
+	resp.phys_port_cnt	       = file->device->ib_dev->phys_port_cnt;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		return -EFAULT;
+
+	return in_len;
+}
+
+ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
+			     const char __user *buf,
+			     int in_len, int out_len)
+{
+	struct ib_uverbs_query_port      cmd;
+	struct ib_uverbs_query_port_resp resp;
+	struct ib_port_attr              attr;
+	int                              ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr);
+	if (ret)
+		return ret;
+
+	memset(&resp, 0, sizeof resp);
+
+	resp.state 	     = attr.state;
+	resp.max_mtu 	     = attr.max_mtu;
+	resp.active_mtu      = attr.active_mtu;
+	resp.gid_tbl_len     = attr.gid_tbl_len;
+	resp.port_cap_flags  = attr.port_cap_flags;
+	resp.max_msg_sz      = attr.max_msg_sz;
+	resp.bad_pkey_cntr   = attr.bad_pkey_cntr;
+	resp.qkey_viol_cntr  = attr.qkey_viol_cntr;
+	resp.pkey_tbl_len    = attr.pkey_tbl_len;
+	resp.lid 	     = attr.lid;
+	resp.sm_lid 	     = attr.sm_lid;
+	resp.lmc 	     = attr.lmc;
+	resp.max_vl_num      = attr.max_vl_num;
+	resp.sm_sl 	     = attr.sm_sl;
+	resp.subnet_timeout  = attr.subnet_timeout;
+	resp.init_type_reply = attr.init_type_reply;
+	resp.active_width    = attr.active_width;
+	resp.active_speed    = attr.active_speed;
+	resp.phys_state      = attr.phys_state;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		return -EFAULT;
+
+	return in_len;
+}
+
+ssize_t ib_uverbs_query_gid(struct ib_uverbs_file *file,
+			    const char __user *buf,
+			    int in_len, int out_len)
+{
+	struct ib_uverbs_query_gid      cmd;
+	struct ib_uverbs_query_gid_resp resp;
+	int                             ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	memset(&resp, 0, sizeof resp);
+
+	ret = ib_query_gid(file->device->ib_dev, cmd.port_num, cmd.index,
+			   (union ib_gid *) resp.gid);
+	if (ret)
+		return ret;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		return -EFAULT;
+
+	return in_len;
+}
+
+ssize_t ib_uverbs_query_pkey(struct ib_uverbs_file *file,
+			     const char __user *buf,
+			     int in_len, int out_len)
+{
+	struct ib_uverbs_query_pkey      cmd;
+	struct ib_uverbs_query_pkey_resp resp;
+	int                              ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	memset(&resp, 0, sizeof resp);
+
+	ret = ib_query_pkey(file->device->ib_dev, cmd.port_num, cmd.index,
+			    &resp.pkey);
+	if (ret)
+		return ret;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		return -EFAULT;
+
+	return in_len;
+}
+
+ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
+			   const char __user *buf,
+			   int in_len, int out_len)
+{
+	struct ib_uverbs_alloc_pd      cmd;
+	struct ib_uverbs_alloc_pd_resp resp;
+	struct ib_udata                udata;
+	struct ib_uobject             *uobj;
+	struct ib_pd                  *pd;
+	int                            ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	INIT_UDATA(&udata, buf + sizeof cmd,
+		   (unsigned long) cmd.response + sizeof resp,
+		   in_len - sizeof cmd, out_len - sizeof resp);
+
+	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+	if (!uobj)
+		return -ENOMEM;
+
+	uobj->context = file->ucontext;
+
+	pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
+					    file->ucontext, &udata);
+	if (IS_ERR(pd)) {
+		ret = PTR_ERR(pd);
+		goto err;
+	}
+
+	pd->device  = file->device->ib_dev;
+	pd->uobject = uobj;
+	atomic_set(&pd->usecnt, 0);
+
+retry:
+	if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto err_pd;
+	}
+
+	down(&ib_uverbs_idr_mutex);
+	ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id);
+	up(&ib_uverbs_idr_mutex);
+
+	if (ret == -EAGAIN)
+		goto retry;
+	if (ret)
+		goto err_pd;
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_add_tail(&uobj->list, &file->ucontext->pd_list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	memset(&resp, 0, sizeof resp);
+	resp.pd_handle = uobj->id;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp)) {
+		ret = -EFAULT;
+		goto err_list;
+	}
+
+	return in_len;
+
+err_list:
+ 	spin_lock_irq(&file->ucontext->lock);
+	list_del(&uobj->list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	down(&ib_uverbs_idr_mutex);
+	idr_remove(&ib_uverbs_pd_idr, uobj->id);
+	up(&ib_uverbs_idr_mutex);
+
+err_pd:
+	ib_dealloc_pd(pd);
+
+err:
+	kfree(uobj);
+	return ret;
+}
+
+ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
+			     const char __user *buf,
+			     int in_len, int out_len)
+{
+	struct ib_uverbs_dealloc_pd cmd;
+	struct ib_pd               *pd;
+	struct ib_uobject          *uobj;
+	int                         ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	down(&ib_uverbs_idr_mutex);
+
+	pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+	if (!pd || pd->uobject->context != file->ucontext)
+		goto out;
+
+	uobj = pd->uobject;
+
+	ret = ib_dealloc_pd(pd);
+	if (ret)
+		goto out;
+
+	idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_del(&uobj->list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	kfree(uobj);
+
+out:
+	up(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
+			 const char __user *buf, int in_len,
+			 int out_len)
+{
+	struct ib_uverbs_reg_mr      cmd;
+	struct ib_uverbs_reg_mr_resp resp;
+	struct ib_udata              udata;
+	struct ib_umem_object       *obj;
+	struct ib_pd                *pd;
+	struct ib_mr                *mr;
+	int                          ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	INIT_UDATA(&udata, buf + sizeof cmd,
+		   (unsigned long) cmd.response + sizeof resp,
+		   in_len - sizeof cmd, out_len - sizeof resp);
+
+	if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
+		return -EINVAL;
+
+	obj = kmalloc(sizeof *obj, GFP_KERNEL);
+	if (!obj)
+		return -ENOMEM;
+
+	obj->uobject.context = file->ucontext;
+
+	/*
+	 * We ask for writable memory if any access flags other than
+	 * "remote read" are set.  "Local write" and "remote write"
+	 * obviously require write access.  "Remote atomic" can do
+	 * things like fetch and add, which will modify memory, and
+	 * "MW bind" can change permissions by binding a window.
+	 */
+	ret = ib_umem_get(file->device->ib_dev, &obj->umem,
+			  (void *) (unsigned long) cmd.start, cmd.length,
+			  !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ));
+	if (ret)
+		goto err_free;
+
+	obj->umem.virt_base = cmd.hca_va;
+
+	down(&ib_uverbs_idr_mutex);
+
+	pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+	if (!pd || pd->uobject->context != file->ucontext) {
+		ret = -EINVAL;
+		goto err_up;
+	}
+
+	if (!pd->device->reg_user_mr) {
+		ret = -ENOSYS;
+		goto err_up;
+	}
+
+	mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
+	if (IS_ERR(mr)) {
+		ret = PTR_ERR(mr);
+		goto err_up;
+	}
+
+	mr->device  = pd->device;
+	mr->pd      = pd;
+	mr->uobject = &obj->uobject;
+	atomic_inc(&pd->usecnt);
+	atomic_set(&mr->usecnt, 0);
+
+	memset(&resp, 0, sizeof resp);
+	resp.lkey = mr->lkey;
+	resp.rkey = mr->rkey;
+
+retry:
+	if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto err_unreg;
+	}
+
+	ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id);
+
+	if (ret == -EAGAIN)
+		goto retry;
+	if (ret)
+		goto err_unreg;
+
+	resp.mr_handle = obj->uobject.id;
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp)) {
+		ret = -EFAULT;
+		goto err_list;
+	}
+
+	up(&ib_uverbs_idr_mutex);
+
+	return in_len;
+
+err_list:
+	spin_lock_irq(&file->ucontext->lock);
+	list_del(&obj->uobject.list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+err_unreg:
+	ib_dereg_mr(mr);
+
+err_up:
+	up(&ib_uverbs_idr_mutex);
+
+	ib_umem_release(file->device->ib_dev, &obj->umem);
+
+err_free:
+	kfree(obj);
+	return ret;
+}
+
+ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
+			   const char __user *buf, int in_len,
+			   int out_len)
+{
+	struct ib_uverbs_dereg_mr cmd;
+	struct ib_mr             *mr;
+	struct ib_umem_object    *memobj;
+	int                       ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	down(&ib_uverbs_idr_mutex);
+
+	mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
+	if (!mr || mr->uobject->context != file->ucontext)
+		goto out;
+
+	memobj = container_of(mr->uobject, struct ib_umem_object, uobject);
+
+	ret = ib_dereg_mr(mr);
+	if (ret)
+		goto out;
+
+	idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_del(&memobj->uobject.list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	ib_umem_release(file->device->ib_dev, &memobj->umem);
+	kfree(memobj);
+
+out:
+	up(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
+			    const char __user *buf, int in_len,
+			    int out_len)
+{
+	struct ib_uverbs_create_cq      cmd;
+	struct ib_uverbs_create_cq_resp resp;
+	struct ib_udata                 udata;
+	struct ib_uobject              *uobj;
+	struct ib_cq                   *cq;
+	int                             ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	INIT_UDATA(&udata, buf + sizeof cmd,
+		   (unsigned long) cmd.response + sizeof resp,
+		   in_len - sizeof cmd, out_len - sizeof resp);
+
+	if (cmd.event_handler >= file->device->num_comp)
+		return -EINVAL;
+
+	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+	if (!uobj)
+		return -ENOMEM;
+
+	uobj->user_handle = cmd.user_handle;
+	uobj->context     = file->ucontext;
+
+	cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
+					     file->ucontext, &udata);
+	if (IS_ERR(cq)) {
+		ret = PTR_ERR(cq);
+		goto err;
+	}
+
+	cq->device        = file->device->ib_dev;
+	cq->uobject       = uobj;
+	cq->comp_handler  = ib_uverbs_comp_handler;
+	cq->event_handler = ib_uverbs_cq_event_handler;
+	cq->cq_context    = file;
+	atomic_set(&cq->usecnt, 0);
+
+retry:
+	if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto err_cq;
+	}
+
+	down(&ib_uverbs_idr_mutex);
+	ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->id);
+	up(&ib_uverbs_idr_mutex);
+
+	if (ret == -EAGAIN)
+		goto retry;
+	if (ret)
+		goto err_cq;
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_add_tail(&uobj->list, &file->ucontext->cq_list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	memset(&resp, 0, sizeof resp);
+	resp.cq_handle = uobj->id;
+	resp.cqe       = cq->cqe;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp)) {
+		ret = -EFAULT;
+		goto err_list;
+	}
+
+	return in_len;
+
+err_list:
+ 	spin_lock_irq(&file->ucontext->lock);
+	list_del(&uobj->list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	down(&ib_uverbs_idr_mutex);
+	idr_remove(&ib_uverbs_cq_idr, uobj->id);
+	up(&ib_uverbs_idr_mutex);
+
+err_cq:
+	ib_destroy_cq(cq);
+
+err:
+	kfree(uobj);
+	return ret;
+}
+
+ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
+			     const char __user *buf, int in_len,
+			     int out_len)
+{
+	struct ib_uverbs_destroy_cq cmd;
+	struct ib_cq               *cq;
+	struct ib_uobject          *uobj;
+	int                         ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	down(&ib_uverbs_idr_mutex);
+
+	cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+	if (!cq || cq->uobject->context != file->ucontext)
+		goto out;
+
+	uobj = cq->uobject;
+
+	ret = ib_destroy_cq(cq);
+	if (ret)
+		goto out;
+
+	idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_del(&uobj->list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	kfree(uobj);
+
+out:
+	up(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
+			    const char __user *buf, int in_len,
+			    int out_len)
+{
+	struct ib_uverbs_create_qp      cmd;
+	struct ib_uverbs_create_qp_resp resp;
+	struct ib_udata                 udata;
+	struct ib_uobject              *uobj;
+	struct ib_pd                   *pd;
+	struct ib_cq                   *scq, *rcq;
+	struct ib_qp                   *qp;
+	struct ib_qp_init_attr          attr;
+	int ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	INIT_UDATA(&udata, buf + sizeof cmd,
+		   (unsigned long) cmd.response + sizeof resp,
+		   in_len - sizeof cmd, out_len - sizeof resp);
+
+	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+	if (!uobj)
+		return -ENOMEM;
+
+	down(&ib_uverbs_idr_mutex);
+
+	pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+	scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
+	rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
+
+	if (!pd  || pd->uobject->context  != file->ucontext ||
+	    !scq || scq->uobject->context != file->ucontext ||
+	    !rcq || rcq->uobject->context != file->ucontext) {
+		ret = -EINVAL;
+		goto err_up;
+	}
+
+	attr.event_handler = ib_uverbs_qp_event_handler;
+	attr.qp_context    = file;
+	attr.send_cq       = scq;
+	attr.recv_cq       = rcq;
+	attr.srq           = NULL;
+	attr.sq_sig_type   = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
+	attr.qp_type       = cmd.qp_type;
+
+	attr.cap.max_send_wr     = cmd.max_send_wr;
+	attr.cap.max_recv_wr     = cmd.max_recv_wr;
+	attr.cap.max_send_sge    = cmd.max_send_sge;
+	attr.cap.max_recv_sge    = cmd.max_recv_sge;
+	attr.cap.max_inline_data = cmd.max_inline_data;
+
+	uobj->user_handle = cmd.user_handle;
+	uobj->context     = file->ucontext;
+
+	qp = pd->device->create_qp(pd, &attr, &udata);
+	if (IS_ERR(qp)) {
+		ret = PTR_ERR(qp);
+		goto err_up;
+	}
+
+	qp->device     	  = pd->device;
+	qp->pd         	  = pd;
+	qp->send_cq    	  = attr.send_cq;
+	qp->recv_cq    	  = attr.recv_cq;
+	qp->srq	       	  = attr.srq;
+	qp->uobject       = uobj;
+	qp->event_handler = attr.event_handler;
+	qp->qp_context    = attr.qp_context;
+	qp->qp_type	  = attr.qp_type;
+	atomic_inc(&pd->usecnt);
+	atomic_inc(&attr.send_cq->usecnt);
+	atomic_inc(&attr.recv_cq->usecnt);
+	if (attr.srq)
+		atomic_inc(&attr.srq->usecnt);
+
+	memset(&resp, 0, sizeof resp);
+	resp.qpn = qp->qp_num;
+
+retry:
+	if (!idr_pre_get(&ib_uverbs_qp_idr, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto err_destroy;
+	}
+
+	ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->id);
+
+	if (ret == -EAGAIN)
+		goto retry;
+	if (ret)
+		goto err_destroy;
+
+	resp.qp_handle = uobj->id;
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_add_tail(&uobj->list, &file->ucontext->qp_list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp)) {
+		ret = -EFAULT;
+		goto err_list;
+	}
+
+	up(&ib_uverbs_idr_mutex);
+
+	return in_len;
+
+err_list:
+	spin_lock_irq(&file->ucontext->lock);
+	list_del(&uobj->list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+err_destroy:
+	ib_destroy_qp(qp);
+
+err_up:
+	up(&ib_uverbs_idr_mutex);
+
+	kfree(uobj);
+	return ret;
+}
+
+ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
+			    const char __user *buf, int in_len,
+			    int out_len)
+{
+	struct ib_uverbs_modify_qp cmd;
+	struct ib_qp              *qp;
+	struct ib_qp_attr         *attr;
+	int                        ret;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	attr = kmalloc(sizeof *attr, GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	down(&ib_uverbs_idr_mutex);
+
+	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+	if (!qp || qp->uobject->context != file->ucontext) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	attr->qp_state 		  = cmd.qp_state;
+	attr->cur_qp_state 	  = cmd.cur_qp_state;
+	attr->path_mtu 		  = cmd.path_mtu;
+	attr->path_mig_state 	  = cmd.path_mig_state;
+	attr->qkey 		  = cmd.qkey;
+	attr->rq_psn 		  = cmd.rq_psn;
+	attr->sq_psn 		  = cmd.sq_psn;
+	attr->dest_qp_num 	  = cmd.dest_qp_num;
+	attr->qp_access_flags 	  = cmd.qp_access_flags;
+	attr->pkey_index 	  = cmd.pkey_index;
+	attr->alt_pkey_index 	  = cmd.pkey_index;
+	attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
+	attr->max_rd_atomic 	  = cmd.max_rd_atomic;
+	attr->max_dest_rd_atomic  = cmd.max_dest_rd_atomic;
+	attr->min_rnr_timer 	  = cmd.min_rnr_timer;
+	attr->port_num 		  = cmd.port_num;
+	attr->timeout 		  = cmd.timeout;
+	attr->retry_cnt 	  = cmd.retry_cnt;
+	attr->rnr_retry 	  = cmd.rnr_retry;
+	attr->alt_port_num 	  = cmd.alt_port_num;
+	attr->alt_timeout 	  = cmd.alt_timeout;
+
+	memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16);
+	attr->ah_attr.grh.flow_label        = cmd.dest.flow_label;
+	attr->ah_attr.grh.sgid_index        = cmd.dest.sgid_index;
+	attr->ah_attr.grh.hop_limit         = cmd.dest.hop_limit;
+	attr->ah_attr.grh.traffic_class     = cmd.dest.traffic_class;
+	attr->ah_attr.dlid 	    	    = cmd.dest.dlid;
+	attr->ah_attr.sl   	    	    = cmd.dest.sl;
+	attr->ah_attr.src_path_bits 	    = cmd.dest.src_path_bits;
+	attr->ah_attr.static_rate   	    = cmd.dest.static_rate;
+	attr->ah_attr.ah_flags 	    	    = cmd.dest.is_global ? IB_AH_GRH : 0;
+	attr->ah_attr.port_num 	    	    = cmd.dest.port_num;
+
+	memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16);
+	attr->alt_ah_attr.grh.flow_label    = cmd.alt_dest.flow_label;
+	attr->alt_ah_attr.grh.sgid_index    = cmd.alt_dest.sgid_index;
+	attr->alt_ah_attr.grh.hop_limit     = cmd.alt_dest.hop_limit;
+	attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class;
+	attr->alt_ah_attr.dlid 	    	    = cmd.alt_dest.dlid;
+	attr->alt_ah_attr.sl   	    	    = cmd.alt_dest.sl;
+	attr->alt_ah_attr.src_path_bits     = cmd.alt_dest.src_path_bits;
+	attr->alt_ah_attr.static_rate       = cmd.alt_dest.static_rate;
+	attr->alt_ah_attr.ah_flags 	    = cmd.alt_dest.is_global ? IB_AH_GRH : 0;
+	attr->alt_ah_attr.port_num 	    = cmd.alt_dest.port_num;
+
+	ret = ib_modify_qp(qp, attr, cmd.attr_mask);
+	if (ret)
+		goto out;
+
+	ret = in_len;
+
+out:
+	up(&ib_uverbs_idr_mutex);
+	kfree(attr);
+
+	return ret;
+}
+
+ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
+			     const char __user *buf, int in_len,
+			     int out_len)
+{
+	struct ib_uverbs_destroy_qp cmd;
+	struct ib_qp               *qp;
+	struct ib_uobject          *uobj;
+	int                         ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	down(&ib_uverbs_idr_mutex);
+
+	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+	if (!qp || qp->uobject->context != file->ucontext)
+		goto out;
+
+	uobj = qp->uobject;
+
+	ret = ib_destroy_qp(qp);
+	if (ret)
+		goto out;
+
+	idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
+
+	spin_lock_irq(&file->ucontext->lock);
+	list_del(&uobj->list);
+	spin_unlock_irq(&file->ucontext->lock);
+
+	kfree(uobj);
+
+out:
+	up(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
+			       const char __user *buf, int in_len,
+			       int out_len)
+{
+	struct ib_uverbs_attach_mcast cmd;
+	struct ib_qp                 *qp;
+	int                           ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	down(&ib_uverbs_idr_mutex);
+
+	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+	if (qp && qp->uobject->context == file->ucontext)
+		ret = ib_attach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
+
+	up(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
+			       const char __user *buf, int in_len,
+			       int out_len)
+{
+	struct ib_uverbs_detach_mcast cmd;
+	struct ib_qp                 *qp;
+	int                           ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	down(&ib_uverbs_idr_mutex);
+
+	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+	if (qp && qp->uobject->context == file->ucontext)
+		ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
+
+	up(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
new file mode 100644
index 0000000..fbbe03d
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: uverbs_main.c 2733 2005-06-28 19:14:34Z roland $
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+
+#include <asm/uaccess.h>
+
+#include "uverbs.h"
+
+MODULE_AUTHOR("Roland Dreier");
+MODULE_DESCRIPTION("InfiniBand userspace verbs access");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define INFINIBANDEVENTFS_MAGIC	0x49426576	/* "IBev" */
+
+enum {
+	IB_UVERBS_MAJOR       = 231,
+	IB_UVERBS_BASE_MINOR  = 192,
+	IB_UVERBS_MAX_DEVICES = 32
+};
+
+#define IB_UVERBS_BASE_DEV	MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR)
+
+DECLARE_MUTEX(ib_uverbs_idr_mutex);
+DEFINE_IDR(ib_uverbs_pd_idr);
+DEFINE_IDR(ib_uverbs_mr_idr);
+DEFINE_IDR(ib_uverbs_mw_idr);
+DEFINE_IDR(ib_uverbs_ah_idr);
+DEFINE_IDR(ib_uverbs_cq_idr);
+DEFINE_IDR(ib_uverbs_qp_idr);
+
+static spinlock_t map_lock;
+static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
+
+static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
+				     const char __user *buf, int in_len,
+				     int out_len) = {
+	[IB_USER_VERBS_CMD_QUERY_PARAMS]  = ib_uverbs_query_params,
+	[IB_USER_VERBS_CMD_GET_CONTEXT]   = ib_uverbs_get_context,
+	[IB_USER_VERBS_CMD_QUERY_DEVICE]  = ib_uverbs_query_device,
+	[IB_USER_VERBS_CMD_QUERY_PORT]    = ib_uverbs_query_port,
+	[IB_USER_VERBS_CMD_QUERY_GID]     = ib_uverbs_query_gid,
+	[IB_USER_VERBS_CMD_QUERY_PKEY]    = ib_uverbs_query_pkey,
+	[IB_USER_VERBS_CMD_ALLOC_PD]      = ib_uverbs_alloc_pd,
+	[IB_USER_VERBS_CMD_DEALLOC_PD]    = ib_uverbs_dealloc_pd,
+	[IB_USER_VERBS_CMD_REG_MR]        = ib_uverbs_reg_mr,
+	[IB_USER_VERBS_CMD_DEREG_MR]      = ib_uverbs_dereg_mr,
+	[IB_USER_VERBS_CMD_CREATE_CQ]     = ib_uverbs_create_cq,
+	[IB_USER_VERBS_CMD_DESTROY_CQ]    = ib_uverbs_destroy_cq,
+	[IB_USER_VERBS_CMD_CREATE_QP]     = ib_uverbs_create_qp,
+	[IB_USER_VERBS_CMD_MODIFY_QP]     = ib_uverbs_modify_qp,
+	[IB_USER_VERBS_CMD_DESTROY_QP]    = ib_uverbs_destroy_qp,
+	[IB_USER_VERBS_CMD_ATTACH_MCAST]  = ib_uverbs_attach_mcast,
+	[IB_USER_VERBS_CMD_DETACH_MCAST]  = ib_uverbs_detach_mcast,
+};
+
+static struct vfsmount *uverbs_event_mnt;
+
+static void ib_uverbs_add_one(struct ib_device *device);
+static void ib_uverbs_remove_one(struct ib_device *device);
+
+static int ib_dealloc_ucontext(struct ib_ucontext *context)
+{
+	struct ib_uobject *uobj, *tmp;
+
+	if (!context)
+		return 0;
+
+	down(&ib_uverbs_idr_mutex);
+
+	/* XXX Free AHs */
+
+	list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
+		struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id);
+		idr_remove(&ib_uverbs_qp_idr, uobj->id);
+		ib_destroy_qp(qp);
+		list_del(&uobj->list);
+		kfree(uobj);
+	}
+
+	list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
+		struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id);
+		idr_remove(&ib_uverbs_cq_idr, uobj->id);
+		ib_destroy_cq(cq);
+		list_del(&uobj->list);
+		kfree(uobj);
+	}
+
+	/* XXX Free SRQs */
+	/* XXX Free MWs */
+
+	list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
+		struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id);
+		struct ib_umem_object *memobj;
+
+		idr_remove(&ib_uverbs_mr_idr, uobj->id);
+		ib_dereg_mr(mr);
+
+		memobj = container_of(uobj, struct ib_umem_object, uobject);
+		ib_umem_release_on_close(mr->device, &memobj->umem);
+
+		list_del(&uobj->list);
+		kfree(memobj);
+	}
+
+	list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
+		struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id);
+		idr_remove(&ib_uverbs_pd_idr, uobj->id);
+		ib_dealloc_pd(pd);
+		list_del(&uobj->list);
+		kfree(uobj);
+	}
+
+	up(&ib_uverbs_idr_mutex);
+
+	return context->device->dealloc_ucontext(context);
+}
+
+static void ib_uverbs_release_file(struct kref *ref)
+{
+	struct ib_uverbs_file *file =
+		container_of(ref, struct ib_uverbs_file, ref);
+
+	module_put(file->device->ib_dev->owner);
+	kfree(file);
+}
+
+static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf,
+				    size_t count, loff_t *pos)
+{
+	struct ib_uverbs_event_file *file = filp->private_data;
+	void *event;
+	int eventsz;
+	int ret = 0;
+
+	spin_lock_irq(&file->lock);
+
+	while (list_empty(&file->event_list) && file->fd >= 0) {
+		spin_unlock_irq(&file->lock);
+
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		if (wait_event_interruptible(file->poll_wait,
+					     !list_empty(&file->event_list) ||
+					     file->fd < 0))
+			return -ERESTARTSYS;
+
+		spin_lock_irq(&file->lock);
+	}
+
+	if (file->fd < 0) {
+		spin_unlock_irq(&file->lock);
+		return -ENODEV;
+	}
+
+	if (file->is_async) {
+		event   = list_entry(file->event_list.next,
+				     struct ib_uverbs_async_event, list);
+		eventsz = sizeof (struct ib_uverbs_async_event_desc);
+	} else {
+		event   = list_entry(file->event_list.next,
+				     struct ib_uverbs_comp_event, list);
+		eventsz = sizeof (struct ib_uverbs_comp_event_desc);
+	}
+
+	if (eventsz > count) {
+		ret   = -EINVAL;
+		event = NULL;
+	} else
+		list_del(file->event_list.next);
+
+	spin_unlock_irq(&file->lock);
+
+	if (event) {
+		if (copy_to_user(buf, event, eventsz))
+			ret = -EFAULT;
+		else
+			ret = eventsz;
+	}
+
+	kfree(event);
+
+	return ret;
+}
+
+static unsigned int ib_uverbs_event_poll(struct file *filp,
+					 struct poll_table_struct *wait)
+{
+	unsigned int pollflags = 0;
+	struct ib_uverbs_event_file *file = filp->private_data;
+
+	poll_wait(filp, &file->poll_wait, wait);
+
+	spin_lock_irq(&file->lock);
+	if (file->fd < 0)
+		pollflags = POLLERR;
+	else if (!list_empty(&file->event_list))
+		pollflags = POLLIN | POLLRDNORM;
+	spin_unlock_irq(&file->lock);
+
+	return pollflags;
+}
+
+static void ib_uverbs_event_release(struct ib_uverbs_event_file *file)
+{
+	struct list_head *entry, *tmp;
+
+	spin_lock_irq(&file->lock);
+	if (file->fd != -1) {
+		file->fd = -1;
+		list_for_each_safe(entry, tmp, &file->event_list)
+			if (file->is_async)
+				kfree(list_entry(entry, struct ib_uverbs_async_event, list));
+			else
+				kfree(list_entry(entry, struct ib_uverbs_comp_event, list));
+	}
+	spin_unlock_irq(&file->lock);
+}
+
+static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
+{
+	struct ib_uverbs_event_file *file = filp->private_data;
+
+	ib_uverbs_event_release(file);
+	kref_put(&file->uverbs_file->ref, ib_uverbs_release_file);
+
+	return 0;
+}
+
+static struct file_operations uverbs_event_fops = {
+	/*
+	 * No .owner field since we artificially create event files,
+	 * so there is no increment to the module reference count in
+	 * the open path.  All event files come from a uverbs command
+	 * file, which already takes a module reference, so this is OK.
+	 */
+	.read 	 = ib_uverbs_event_read,
+	.poll    = ib_uverbs_event_poll,
+	.release = ib_uverbs_event_close
+};
+
+void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context)
+{
+	struct ib_uverbs_file       *file = cq_context;
+	struct ib_uverbs_comp_event *entry;
+	unsigned long                flags;
+
+	entry = kmalloc(sizeof *entry, GFP_ATOMIC);
+	if (!entry)
+		return;
+
+	entry->desc.cq_handle = cq->uobject->user_handle;
+
+	spin_lock_irqsave(&file->comp_file[0].lock, flags);
+	list_add_tail(&entry->list, &file->comp_file[0].event_list);
+	spin_unlock_irqrestore(&file->comp_file[0].lock, flags);
+
+	wake_up_interruptible(&file->comp_file[0].poll_wait);
+}
+
+static void ib_uverbs_async_handler(struct ib_uverbs_file *file,
+				    __u64 element, __u64 event)
+{
+	struct ib_uverbs_async_event *entry;
+	unsigned long flags;
+
+	entry = kmalloc(sizeof *entry, GFP_ATOMIC);
+	if (!entry)
+		return;
+
+	entry->desc.element    = element;
+	entry->desc.event_type = event;
+
+	spin_lock_irqsave(&file->async_file.lock, flags);
+	list_add_tail(&entry->list, &file->async_file.event_list);
+	spin_unlock_irqrestore(&file->async_file.lock, flags);
+
+	wake_up_interruptible(&file->async_file.poll_wait);
+}
+
+void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr)
+{
+	ib_uverbs_async_handler(context_ptr,
+				event->element.cq->uobject->user_handle,
+				event->event);
+}
+
+void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
+{
+	ib_uverbs_async_handler(context_ptr,
+				event->element.qp->uobject->user_handle,
+				event->event);
+}
+
+static void ib_uverbs_event_handler(struct ib_event_handler *handler,
+				    struct ib_event *event)
+{
+	struct ib_uverbs_file *file =
+		container_of(handler, struct ib_uverbs_file, event_handler);
+
+	ib_uverbs_async_handler(file, event->element.port_num, event->event);
+}
+
+static int ib_uverbs_event_init(struct ib_uverbs_event_file *file,
+				struct ib_uverbs_file *uverbs_file)
+{
+	struct file *filp;
+
+	spin_lock_init(&file->lock);
+	INIT_LIST_HEAD(&file->event_list);
+	init_waitqueue_head(&file->poll_wait);
+	file->uverbs_file = uverbs_file;
+
+	file->fd = get_unused_fd();
+	if (file->fd < 0)
+		return file->fd;
+
+	filp = get_empty_filp();
+	if (!filp) {
+		put_unused_fd(file->fd);
+		return -ENFILE;
+	}
+
+	filp->f_op 	   = &uverbs_event_fops;
+	filp->f_vfsmnt 	   = mntget(uverbs_event_mnt);
+	filp->f_dentry 	   = dget(uverbs_event_mnt->mnt_root);
+	filp->f_mapping    = filp->f_dentry->d_inode->i_mapping;
+	filp->f_flags      = O_RDONLY;
+	filp->f_mode       = FMODE_READ;
+	filp->private_data = file;
+
+	fd_install(file->fd, filp);
+
+	return 0;
+}
+
+static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
+			     size_t count, loff_t *pos)
+{
+	struct ib_uverbs_file *file = filp->private_data;
+	struct ib_uverbs_cmd_hdr hdr;
+
+	if (count < sizeof hdr)
+		return -EINVAL;
+
+	if (copy_from_user(&hdr, buf, sizeof hdr))
+		return -EFAULT;
+
+	if (hdr.in_words * 4 != count)
+		return -EINVAL;
+
+	if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table))
+		return -EINVAL;
+
+	if (!file->ucontext                               &&
+	    hdr.command != IB_USER_VERBS_CMD_QUERY_PARAMS &&
+	    hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT)
+		return -EINVAL;
+
+	return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr,
+					     hdr.in_words * 4, hdr.out_words * 4);
+}
+
+static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct ib_uverbs_file *file = filp->private_data;
+
+	if (!file->ucontext)
+		return -ENODEV;
+	else
+		return file->device->ib_dev->mmap(file->ucontext, vma);
+}
+
+static int ib_uverbs_open(struct inode *inode, struct file *filp)
+{
+	struct ib_uverbs_device *dev =
+		container_of(inode->i_cdev, struct ib_uverbs_device, dev);
+	struct ib_uverbs_file *file;
+	int i = 0;
+	int ret;
+
+	if (!try_module_get(dev->ib_dev->owner))
+		return -ENODEV;
+
+	file = kmalloc(sizeof *file +
+		       (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file),
+		       GFP_KERNEL);
+	if (!file)
+		return -ENOMEM;
+
+	file->device = dev;
+	kref_init(&file->ref);
+
+	file->ucontext = NULL;
+
+	ret = ib_uverbs_event_init(&file->async_file, file);
+	if (ret)
+		goto err;
+
+	file->async_file.is_async = 1;
+
+	kref_get(&file->ref);
+
+	for (i = 0; i < dev->num_comp; ++i) {
+		ret = ib_uverbs_event_init(&file->comp_file[i], file);
+		if (ret)
+			goto err_async;
+		kref_get(&file->ref);
+		file->comp_file[i].is_async = 0;
+	}
+
+
+	filp->private_data = file;
+
+	INIT_IB_EVENT_HANDLER(&file->event_handler, dev->ib_dev,
+			      ib_uverbs_event_handler);
+	if (ib_register_event_handler(&file->event_handler))
+		goto err_async;
+
+	return 0;
+
+err_async:
+	while (i--)
+		ib_uverbs_event_release(&file->comp_file[i]);
+
+	ib_uverbs_event_release(&file->async_file);
+
+err:
+	kref_put(&file->ref, ib_uverbs_release_file);
+
+	return ret;
+}
+
+static int ib_uverbs_close(struct inode *inode, struct file *filp)
+{
+	struct ib_uverbs_file *file = filp->private_data;
+	int i;
+
+	ib_unregister_event_handler(&file->event_handler);
+	ib_uverbs_event_release(&file->async_file);
+	ib_dealloc_ucontext(file->ucontext);
+
+	for (i = 0; i < file->device->num_comp; ++i)
+		ib_uverbs_event_release(&file->comp_file[i]);
+
+	kref_put(&file->ref, ib_uverbs_release_file);
+
+	return 0;
+}
+
+static struct file_operations uverbs_fops = {
+	.owner 	 = THIS_MODULE,
+	.write 	 = ib_uverbs_write,
+	.open 	 = ib_uverbs_open,
+	.release = ib_uverbs_close
+};
+
+static struct file_operations uverbs_mmap_fops = {
+	.owner 	 = THIS_MODULE,
+	.write 	 = ib_uverbs_write,
+	.mmap    = ib_uverbs_mmap,
+	.open 	 = ib_uverbs_open,
+	.release = ib_uverbs_close
+};
+
+static struct ib_client uverbs_client = {
+	.name   = "uverbs",
+	.add    = ib_uverbs_add_one,
+	.remove = ib_uverbs_remove_one
+};
+
+static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
+{
+	struct ib_uverbs_device *dev =
+		container_of(class_dev, struct ib_uverbs_device, class_dev);
+
+	return sprintf(buf, "%s\n", dev->ib_dev->name);
+}
+static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
+
+static void ib_uverbs_release_class_dev(struct class_device *class_dev)
+{
+	struct ib_uverbs_device *dev =
+		container_of(class_dev, struct ib_uverbs_device, class_dev);
+
+	cdev_del(&dev->dev);
+	clear_bit(dev->devnum, dev_map);
+	kfree(dev);
+}
+
+static struct class uverbs_class = {
+	.name    = "infiniband_verbs",
+	.release = ib_uverbs_release_class_dev
+};
+
+static ssize_t show_abi_version(struct class *class, char *buf)
+{
+	return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION);
+}
+static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+
+static void ib_uverbs_add_one(struct ib_device *device)
+{
+	struct ib_uverbs_device *uverbs_dev;
+
+	if (!device->alloc_ucontext)
+		return;
+
+	uverbs_dev = kmalloc(sizeof *uverbs_dev, GFP_KERNEL);
+	if (!uverbs_dev)
+		return;
+
+	memset(uverbs_dev, 0, sizeof *uverbs_dev);
+
+	spin_lock(&map_lock);
+	uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
+	if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) {
+		spin_unlock(&map_lock);
+		goto err;
+	}
+	set_bit(uverbs_dev->devnum, dev_map);
+	spin_unlock(&map_lock);
+
+	uverbs_dev->ib_dev   = device;
+	uverbs_dev->num_comp = 1;
+
+	if (device->mmap)
+		cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops);
+	else
+		cdev_init(&uverbs_dev->dev, &uverbs_fops);
+	uverbs_dev->dev.owner = THIS_MODULE;
+	kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum);
+	if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1))
+		goto err;
+
+	uverbs_dev->class_dev.class = &uverbs_class;
+	uverbs_dev->class_dev.dev   = device->dma_device;
+	uverbs_dev->class_dev.devt  = uverbs_dev->dev.dev;
+	snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum);
+	if (class_device_register(&uverbs_dev->class_dev))
+		goto err_cdev;
+
+	if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev))
+		goto err_class;
+
+	ib_set_client_data(device, &uverbs_client, uverbs_dev);
+
+	return;
+
+err_class:
+	class_device_unregister(&uverbs_dev->class_dev);
+
+err_cdev:
+	cdev_del(&uverbs_dev->dev);
+	clear_bit(uverbs_dev->devnum, dev_map);
+
+err:
+	kfree(uverbs_dev);
+	return;
+}
+
+static void ib_uverbs_remove_one(struct ib_device *device)
+{
+	struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client);
+
+	if (!uverbs_dev)
+		return;
+
+	class_device_unregister(&uverbs_dev->class_dev);
+}
+
+static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
+					       const char *dev_name, void *data)
+{
+	return get_sb_pseudo(fs_type, "infinibandevent:", NULL,
+			     INFINIBANDEVENTFS_MAGIC);
+}
+
+static struct file_system_type uverbs_event_fs = {
+	/* No owner field so module can be unloaded */
+	.name    = "infinibandeventfs",
+	.get_sb  = uverbs_event_get_sb,
+	.kill_sb = kill_litter_super
+};
+
+static int __init ib_uverbs_init(void)
+{
+	int ret;
+
+	spin_lock_init(&map_lock);
+
+	ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES,
+				     "infiniband_verbs");
+	if (ret) {
+		printk(KERN_ERR "user_verbs: couldn't register device number\n");
+		goto out;
+	}
+
+	ret = class_register(&uverbs_class);
+	if (ret) {
+		printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n");
+		goto out_chrdev;
+	}
+
+	ret = class_create_file(&uverbs_class, &class_attr_abi_version);
+	if (ret) {
+		printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n");
+		goto out_class;
+	}
+
+	ret = register_filesystem(&uverbs_event_fs);
+	if (ret) {
+		printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n");
+		goto out_class;
+	}
+
+	uverbs_event_mnt = kern_mount(&uverbs_event_fs);
+	if (IS_ERR(uverbs_event_mnt)) {
+		ret = PTR_ERR(uverbs_event_mnt);
+		printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n");
+		goto out_fs;
+	}
+
+	ret = ib_register_client(&uverbs_client);
+	if (ret) {
+		printk(KERN_ERR "user_verbs: couldn't register client\n");
+		goto out_mnt;
+	}
+
+	return 0;
+
+out_mnt:
+	mntput(uverbs_event_mnt);
+
+out_fs:
+	unregister_filesystem(&uverbs_event_fs);
+
+out_class:
+	class_unregister(&uverbs_class);
+
+out_chrdev:
+	unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+
+out:
+	return ret;
+}
+
+static void __exit ib_uverbs_cleanup(void)
+{
+	ib_unregister_client(&uverbs_client);
+	mntput(uverbs_event_mnt);
+	unregister_filesystem(&uverbs_event_fs);
+	class_unregister(&uverbs_class);
+	unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+}
+
+module_init(ib_uverbs_init);
+module_exit(ib_uverbs_cleanup);
diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c
new file mode 100644
index 0000000..ed550f6
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_mem.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: uverbs_mem.c 2743 2005-06-28 22:27:59Z roland $
+ */
+
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
+#include "uverbs.h"
+
+struct ib_umem_account_work {
+	struct work_struct work;
+	struct mm_struct  *mm;
+	unsigned long      diff;
+};
+
+
+static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
+{
+	struct ib_umem_chunk *chunk, *tmp;
+	int i;
+
+	list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) {
+		dma_unmap_sg(dev->dma_device, chunk->page_list,
+			     chunk->nents, DMA_BIDIRECTIONAL);
+		for (i = 0; i < chunk->nents; ++i) {
+			if (umem->writable && dirty)
+				set_page_dirty_lock(chunk->page_list[i].page);
+			put_page(chunk->page_list[i].page);
+		}
+
+		kfree(chunk);
+	}
+}
+
+int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
+		void *addr, size_t size, int write)
+{
+	struct page **page_list;
+	struct ib_umem_chunk *chunk;
+	unsigned long locked;
+	unsigned long lock_limit;
+	unsigned long cur_base;
+	unsigned long npages;
+	int ret = 0;
+	int off;
+	int i;
+
+	if (!can_do_mlock())
+		return -EPERM;
+
+	page_list = (struct page **) __get_free_page(GFP_KERNEL);
+	if (!page_list)
+		return -ENOMEM;
+
+	mem->user_base = (unsigned long) addr;
+	mem->length    = size;
+	mem->offset    = (unsigned long) addr & ~PAGE_MASK;
+	mem->page_size = PAGE_SIZE;
+	mem->writable  = write;
+
+	INIT_LIST_HEAD(&mem->chunk_list);
+
+	npages = PAGE_ALIGN(size + mem->offset) >> PAGE_SHIFT;
+
+	down_write(&current->mm->mmap_sem);
+
+	locked     = npages + current->mm->locked_vm;
+	lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+
+	if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cur_base = (unsigned long) addr & PAGE_MASK;
+
+	while (npages) {
+		ret = get_user_pages(current, current->mm, cur_base,
+				     min_t(int, npages,
+					   PAGE_SIZE / sizeof (struct page *)),
+				     1, !write, page_list, NULL);
+
+		if (ret < 0)
+			goto out;
+
+		cur_base += ret * PAGE_SIZE;
+		npages   -= ret;
+
+		off = 0;
+
+		while (ret) {
+			chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) *
+					min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK),
+					GFP_KERNEL);
+			if (!chunk) {
+				ret = -ENOMEM;
+				goto out;
+			}
+
+			chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
+			for (i = 0; i < chunk->nents; ++i) {
+				chunk->page_list[i].page   = page_list[i + off];
+				chunk->page_list[i].offset = 0;
+				chunk->page_list[i].length = PAGE_SIZE;
+			}
+
+			chunk->nmap = dma_map_sg(dev->dma_device,
+						 &chunk->page_list[0],
+						 chunk->nents,
+						 DMA_BIDIRECTIONAL);
+			if (chunk->nmap <= 0) {
+				for (i = 0; i < chunk->nents; ++i)
+					put_page(chunk->page_list[i].page);
+				kfree(chunk);
+
+				ret = -ENOMEM;
+				goto out;
+			}
+
+			ret -= chunk->nents;
+			off += chunk->nents;
+			list_add_tail(&chunk->list, &mem->chunk_list);
+		}
+
+		ret = 0;
+	}
+
+out:
+	if (ret < 0)
+		__ib_umem_release(dev, mem, 0);
+	else
+		current->mm->locked_vm = locked;
+
+	up_write(&current->mm->mmap_sem);
+	free_page((unsigned long) page_list);
+
+	return ret;
+}
+
+void ib_umem_release(struct ib_device *dev, struct ib_umem *umem)
+{
+	__ib_umem_release(dev, umem, 1);
+
+	down_write(&current->mm->mmap_sem);
+	current->mm->locked_vm -=
+		PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+	up_write(&current->mm->mmap_sem);
+}
+
+static void ib_umem_account(void *work_ptr)
+{
+	struct ib_umem_account_work *work = work_ptr;
+
+	down_write(&work->mm->mmap_sem);
+	work->mm->locked_vm -= work->diff;
+	up_write(&work->mm->mmap_sem);
+	mmput(work->mm);
+	kfree(work);
+}
+
+void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem)
+{
+	struct ib_umem_account_work *work;
+	struct mm_struct *mm;
+
+	__ib_umem_release(dev, umem, 1);
+
+	mm = get_task_mm(current);
+	if (!mm)
+		return;
+
+	/*
+	 * We may be called with the mm's mmap_sem already held.  This
+	 * can happen when a userspace munmap() is the call that drops
+	 * the last reference to our file and calls our release
+	 * method.  If there are memory regions to destroy, we'll end
+	 * up here and not be able to take the mmap_sem.  Therefore we
+	 * defer the vm_locked accounting to the system workqueue.
+	 */
+
+	work = kmalloc(sizeof *work, GFP_KERNEL);
+	if (!work)
+		return;
+
+	INIT_WORK(&work->work, ib_umem_account, work);
+	work->mm   = mm;
+	work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+
+	schedule_work(&work->work);
+}
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 7c08ed0..2516f96 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -47,10 +48,11 @@
 {
 	struct ib_pd *pd;
 
-	pd = device->alloc_pd(device);
+	pd = device->alloc_pd(device, NULL, NULL);
 
 	if (!IS_ERR(pd)) {
-		pd->device = device;
+		pd->device  = device;
+		pd->uobject = NULL;
 		atomic_set(&pd->usecnt, 0);
 	}
 
@@ -76,8 +78,9 @@
 	ah = pd->device->create_ah(pd, ah_attr);
 
 	if (!IS_ERR(ah)) {
-		ah->device = pd->device;
-		ah->pd     = pd;
+		ah->device  = pd->device;
+		ah->pd      = pd;
+		ah->uobject = NULL;
 		atomic_inc(&pd->usecnt);
 	}
 
@@ -122,7 +125,7 @@
 {
 	struct ib_qp *qp;
 
-	qp = pd->device->create_qp(pd, qp_init_attr);
+	qp = pd->device->create_qp(pd, qp_init_attr, NULL);
 
 	if (!IS_ERR(qp)) {
 		qp->device     	  = pd->device;
@@ -130,6 +133,7 @@
 		qp->send_cq    	  = qp_init_attr->send_cq;
 		qp->recv_cq    	  = qp_init_attr->recv_cq;
 		qp->srq	       	  = qp_init_attr->srq;
+		qp->uobject       = NULL;
 		qp->event_handler = qp_init_attr->event_handler;
 		qp->qp_context    = qp_init_attr->qp_context;
 		qp->qp_type	  = qp_init_attr->qp_type;
@@ -197,10 +201,11 @@
 {
 	struct ib_cq *cq;
 
-	cq = device->create_cq(device, cqe);
+	cq = device->create_cq(device, cqe, NULL, NULL);
 
 	if (!IS_ERR(cq)) {
 		cq->device        = device;
+		cq->uobject       = NULL;
 		cq->comp_handler  = comp_handler;
 		cq->event_handler = event_handler;
 		cq->cq_context    = cq_context;
@@ -245,8 +250,9 @@
 	mr = pd->device->get_dma_mr(pd, mr_access_flags);
 
 	if (!IS_ERR(mr)) {
-		mr->device = pd->device;
-		mr->pd     = pd;
+		mr->device  = pd->device;
+		mr->pd      = pd;
+		mr->uobject = NULL;
 		atomic_inc(&pd->usecnt);
 		atomic_set(&mr->usecnt, 0);
 	}
@@ -267,8 +273,9 @@
 				     mr_access_flags, iova_start);
 
 	if (!IS_ERR(mr)) {
-		mr->device = pd->device;
-		mr->pd     = pd;
+		mr->device  = pd->device;
+		mr->pd      = pd;
+		mr->uobject = NULL;
 		atomic_inc(&pd->usecnt);
 		atomic_set(&mr->usecnt, 0);
 	}
@@ -344,8 +351,9 @@
 
 	mw = pd->device->alloc_mw(pd);
 	if (!IS_ERR(mw)) {
-		mw->device = pd->device;
-		mw->pd     = pd;
+		mw->device  = pd->device;
+		mw->pd      = pd;
+		mw->uobject = NULL;
 		atomic_inc(&pd->usecnt);
 	}
 
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 766e9031..b5aea7b 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -742,6 +743,7 @@
 }
 
 int mthca_init_cq(struct mthca_dev *dev, int nent,
+		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq)
 {
 	int size = nent * MTHCA_CQ_ENTRY_SIZE;
@@ -753,30 +755,33 @@
 
 	might_sleep();
 
-	cq->ibcq.cqe = nent - 1;
+	cq->ibcq.cqe  = nent - 1;
+	cq->is_kernel = !ctx;
 
 	cq->cqn = mthca_alloc(&dev->cq_table.alloc);
 	if (cq->cqn == -1)
 		return -ENOMEM;
 
 	if (mthca_is_memfree(dev)) {
-		cq->arm_sn = 1;
-
 		err = mthca_table_get(dev, dev->cq_table.table, cq->cqn);
 		if (err)
 			goto err_out;
 
-		err = -ENOMEM;
+		if (cq->is_kernel) {
+			cq->arm_sn = 1;
 
-		cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
-						     cq->cqn, &cq->set_ci_db);
-		if (cq->set_ci_db_index < 0)
-			goto err_out_icm;
+			err = -ENOMEM;
 
-		cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
-						  cq->cqn, &cq->arm_db);
-		if (cq->arm_db_index < 0)
-			goto err_out_ci;
+			cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
+							     cq->cqn, &cq->set_ci_db);
+			if (cq->set_ci_db_index < 0)
+				goto err_out_icm;
+
+			cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
+							  cq->cqn, &cq->arm_db);
+			if (cq->arm_db_index < 0)
+				goto err_out_ci;
+		}
 	}
 
 	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
@@ -785,12 +790,14 @@
 
 	cq_context = mailbox->buf;
 
-	err = mthca_alloc_cq_buf(dev, size, cq);
-	if (err)
-		goto err_out_mailbox;
+	if (cq->is_kernel) {
+		err = mthca_alloc_cq_buf(dev, size, cq);
+		if (err)
+			goto err_out_mailbox;
 
-	for (i = 0; i < nent; ++i)
-		set_cqe_hw(get_cqe(cq, i));
+		for (i = 0; i < nent; ++i)
+			set_cqe_hw(get_cqe(cq, i));
+	}
 
 	spin_lock_init(&cq->lock);
 	atomic_set(&cq->refcount, 1);
@@ -801,11 +808,14 @@
 						  MTHCA_CQ_STATE_DISARMED |
 						  MTHCA_CQ_FLAG_TR);
 	cq_context->start           = cpu_to_be64(0);
-	cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24 |
-						  dev->driver_uar.index);
+	cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24);
+	if (ctx)
+		cq_context->logsize_usrpage |= cpu_to_be32(ctx->uar.index);
+	else
+		cq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index);
 	cq_context->error_eqn       = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
 	cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
-	cq_context->pd              = cpu_to_be32(dev->driver_pd.pd_num);
+	cq_context->pd              = cpu_to_be32(pdn);
 	cq_context->lkey            = cpu_to_be32(cq->mr.ibmr.lkey);
 	cq_context->cqn             = cpu_to_be32(cq->cqn);
 
@@ -843,18 +853,20 @@
 	return 0;
 
 err_out_free_mr:
-	mthca_free_mr(dev, &cq->mr);
-	mthca_free_cq_buf(dev, cq);
+	if (cq->is_kernel) {
+		mthca_free_mr(dev, &cq->mr);
+		mthca_free_cq_buf(dev, cq);
+	}
 
 err_out_mailbox:
 	mthca_free_mailbox(dev, mailbox);
 
 err_out_arm:
-	if (mthca_is_memfree(dev))
+	if (cq->is_kernel && mthca_is_memfree(dev))
 		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
 
 err_out_ci:
-	if (mthca_is_memfree(dev))
+	if (cq->is_kernel && mthca_is_memfree(dev))
 		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
 
 err_out_icm:
@@ -892,7 +904,8 @@
 		int j;
 
 		printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
-		       cq->cqn, cq->cons_index, !!next_cqe_sw(cq));
+		       cq->cqn, cq->cons_index,
+		       cq->is_kernel ? !!next_cqe_sw(cq) : 0);
 		for (j = 0; j < 16; ++j)
 			printk(KERN_ERR "[%2x] %08x\n", j * 4, be32_to_cpu(ctx[j]));
 	}
@@ -910,12 +923,13 @@
 	atomic_dec(&cq->refcount);
 	wait_event(cq->wait, !atomic_read(&cq->refcount));
 
-	mthca_free_mr(dev, &cq->mr);
-	mthca_free_cq_buf(dev, cq);
-
-	if (mthca_is_memfree(dev)) {
-		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
-		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
+	if (cq->is_kernel) {
+		mthca_free_mr(dev, &cq->mr);
+		mthca_free_cq_buf(dev, cq);
+		if (mthca_is_memfree(dev)) {
+			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
+			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
+		}
 	}
 
 	mthca_table_put(dev, dev->cq_table.table, cq->cqn);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 4127f09..5ecdd2e 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -378,7 +379,7 @@
 int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar);
 void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
 
-int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
+int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd);
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
 
 struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
@@ -413,6 +414,7 @@
 int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
 int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
 int mthca_init_cq(struct mthca_dev *dev, int nent,
+		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq);
 void mthca_free_cq(struct mthca_dev *dev,
 		   struct mthca_cq *cq);
@@ -438,12 +440,14 @@
 		   struct mthca_cq *recv_cq,
 		   enum ib_qp_type type,
 		   enum ib_sig_type send_policy,
+		   struct ib_qp_cap *cap,
 		   struct mthca_qp *qp);
 int mthca_alloc_sqp(struct mthca_dev *dev,
 		    struct mthca_pd *pd,
 		    struct mthca_cq *send_cq,
 		    struct mthca_cq *recv_cq,
 		    enum ib_sig_type send_policy,
+		    struct ib_qp_cap *cap,
 		    int qpn,
 		    int port,
 		    struct mthca_sqp *sqp);
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 09519b6..2ef9168 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -665,7 +665,7 @@
 		goto err_pd_table_free;
 	}
 
-	err = mthca_pd_alloc(dev, &dev->driver_pd);
+	err = mthca_pd_alloc(dev, 1, &dev->driver_pd);
 	if (err) {
 		mthca_err(dev, "Failed to create driver PD, "
 			  "aborting.\n");
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 6d3b05d..2a864615 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -47,6 +48,15 @@
 	MTHCA_TABLE_CHUNK_SIZE = 1 << 18
 };
 
+struct mthca_user_db_table {
+	struct semaphore mutex;
+	struct {
+		u64                uvirt;
+		struct scatterlist mem;
+		int                refcount;
+	}                page[0];
+};
+
 void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
 {
 	struct mthca_icm_chunk *chunk, *tmp;
@@ -344,13 +354,133 @@
 	kfree(table);
 }
 
-static u64 mthca_uarc_virt(struct mthca_dev *dev, int page)
+static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page)
 {
 	return dev->uar_table.uarc_base +
-		dev->driver_uar.index * dev->uar_table.uarc_size +
+		uar->index * dev->uar_table.uarc_size +
 		page * 4096;
 }
 
+int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+		      struct mthca_user_db_table *db_tab, int index, u64 uaddr)
+{
+	int ret = 0;
+	u8 status;
+	int i;
+
+	if (!mthca_is_memfree(dev))
+		return 0;
+
+	if (index < 0 || index > dev->uar_table.uarc_size / 8)
+		return -EINVAL;
+
+	down(&db_tab->mutex);
+
+	i = index / MTHCA_DB_REC_PER_PAGE;
+
+	if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE)       ||
+	    (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) ||
+	    (uaddr & 4095)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (db_tab->page[i].refcount) {
+		++db_tab->page[i].refcount;
+		goto out;
+	}
+
+	ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0,
+			     &db_tab->page[i].mem.page, NULL);
+	if (ret < 0)
+		goto out;
+
+	db_tab->page[i].mem.length = 4096;
+	db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
+
+	ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+	if (ret < 0) {
+		put_page(db_tab->page[i].mem.page);
+		goto out;
+	}
+
+	ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem),
+				 mthca_uarc_virt(dev, uar, i), &status);
+	if (!ret && status)
+		ret = -EINVAL;
+	if (ret) {
+		pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+		put_page(db_tab->page[i].mem.page);
+		goto out;
+	}
+
+	db_tab->page[i].uvirt    = uaddr;
+	db_tab->page[i].refcount = 1;
+
+out:
+	up(&db_tab->mutex);
+	return ret;
+}
+
+void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+			 struct mthca_user_db_table *db_tab, int index)
+{
+	if (!mthca_is_memfree(dev))
+		return;
+
+	/*
+	 * To make our bookkeeping simpler, we don't unmap DB
+	 * pages until we clean up the whole db table.
+	 */
+
+	down(&db_tab->mutex);
+
+	--db_tab->page[index / MTHCA_DB_REC_PER_PAGE].refcount;
+
+	up(&db_tab->mutex);
+}
+
+struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev)
+{
+	struct mthca_user_db_table *db_tab;
+	int npages;
+	int i;
+
+	if (!mthca_is_memfree(dev))
+		return NULL;
+
+	npages = dev->uar_table.uarc_size / 4096;
+	db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL);
+	if (!db_tab)
+		return ERR_PTR(-ENOMEM);
+
+	init_MUTEX(&db_tab->mutex);
+	for (i = 0; i < npages; ++i) {
+		db_tab->page[i].refcount = 0;
+		db_tab->page[i].uvirt    = 0;
+	}
+
+	return db_tab;
+}
+
+void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
+			       struct mthca_user_db_table *db_tab)
+{
+	int i;
+	u8 status;
+
+	if (!mthca_is_memfree(dev))
+		return;
+
+	for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) {
+		if (db_tab->page[i].uvirt) {
+			mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
+			pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+			put_page(db_tab->page[i].mem.page);
+		}
+	}
+}
+
 int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
 {
 	int group;
@@ -407,7 +537,8 @@
 	}
 	memset(page->db_rec, 0, 4096);
 
-	ret = mthca_MAP_ICM_page(dev, page->mapping, mthca_uarc_virt(dev, i), &status);
+	ret = mthca_MAP_ICM_page(dev, page->mapping,
+				 mthca_uarc_virt(dev, &dev->driver_uar, i), &status);
 	if (!ret && status)
 		ret = -EINVAL;
 	if (ret) {
@@ -461,7 +592,7 @@
 
 	if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) &&
 	    i >= dev->db_tab->max_group1 - 1) {
-		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
 
 		dma_free_coherent(&dev->pdev->dev, 4096,
 				  page->db_rec, page->mapping);
@@ -530,7 +661,7 @@
 		if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE))
 			mthca_warn(dev, "Kernel UARC page %d not empty\n", i);
 
-		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
 
 		dma_free_coherent(&dev->pdev->dev, 4096,
 				  dev->db_tab->page[i].db_rec,
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index fe7be2a..4761d84 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -148,7 +149,7 @@
 	struct semaphore      mutex;
 };
 
-enum {
+enum mthca_db_type {
 	MTHCA_DB_TYPE_INVALID   = 0x0,
 	MTHCA_DB_TYPE_CQ_SET_CI = 0x1,
 	MTHCA_DB_TYPE_CQ_ARM    = 0x2,
@@ -158,6 +159,17 @@
 	MTHCA_DB_TYPE_GROUP_SEP = 0x7
 };
 
+struct mthca_user_db_table;
+struct mthca_uar;
+
+int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+		      struct mthca_user_db_table *db_tab, int index, u64 uaddr);
+void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+			 struct mthca_user_db_table *db_tab, int index);
+struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev);
+void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
+			       struct mthca_user_db_table *db_tab);
+
 int mthca_init_db_tab(struct mthca_dev *dev);
 void mthca_cleanup_db_tab(struct mthca_dev *dev);
 int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db);
diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c
index ea66847..c2c8998 100644
--- a/drivers/infiniband/hw/mthca/mthca_pd.c
+++ b/drivers/infiniband/hw/mthca/mthca_pd.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -37,23 +38,27 @@
 
 #include "mthca_dev.h"
 
-int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd)
+int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd)
 {
-	int err;
+	int err = 0;
 
 	might_sleep();
 
+	pd->privileged = privileged;
+
 	atomic_set(&pd->sqp_count, 0);
 	pd->pd_num = mthca_alloc(&dev->pd_table.alloc);
 	if (pd->pd_num == -1)
 		return -ENOMEM;
 
-	err = mthca_mr_alloc_notrans(dev, pd->pd_num,
-				     MTHCA_MPT_FLAG_LOCAL_READ |
-				     MTHCA_MPT_FLAG_LOCAL_WRITE,
-				     &pd->ntmr);
-	if (err)
-		mthca_free(&dev->pd_table.alloc, pd->pd_num);
+	if (privileged) {
+		err = mthca_mr_alloc_notrans(dev, pd->pd_num,
+					     MTHCA_MPT_FLAG_LOCAL_READ |
+					     MTHCA_MPT_FLAG_LOCAL_WRITE,
+					     &pd->ntmr);
+		if (err)
+			mthca_free(&dev->pd_table.alloc, pd->pd_num);
+	}
 
 	return err;
 }
@@ -61,7 +66,8 @@
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd)
 {
 	might_sleep();
-	mthca_free_mr(dev, &pd->ntmr);
+	if (pd->privileged)
+		mthca_free_mr(dev, &pd->ntmr);
 	mthca_free(&dev->pd_table.alloc, pd->pd_num);
 }
 
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 0b5adfd..7a58ce9 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -34,9 +35,12 @@
  */
 
 #include <ib_smi.h>
+#include <linux/mm.h>
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
+#include "mthca_user.h"
+#include "mthca_memfree.h"
 
 static int mthca_query_device(struct ib_device *ibdev,
 			      struct ib_device_attr *props)
@@ -284,7 +288,78 @@
 	return err;
 }
 
-static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev)
+static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev,
+						struct ib_udata *udata)
+{
+	struct mthca_alloc_ucontext_resp uresp;
+	struct mthca_ucontext           *context;
+	int                              err;
+
+	memset(&uresp, 0, sizeof uresp);
+
+	uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps;
+	if (mthca_is_memfree(to_mdev(ibdev)))
+		uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size;
+	else
+		uresp.uarc_size = 0;
+
+	context = kmalloc(sizeof *context, GFP_KERNEL);
+	if (!context)
+		return ERR_PTR(-ENOMEM);
+
+	err = mthca_uar_alloc(to_mdev(ibdev), &context->uar);
+	if (err) {
+		kfree(context);
+		return ERR_PTR(err);
+	}
+
+	context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev));
+	if (IS_ERR(context->db_tab)) {
+		err = PTR_ERR(context->db_tab);
+		mthca_uar_free(to_mdev(ibdev), &context->uar);
+		kfree(context);
+		return ERR_PTR(err);
+	}
+
+	if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+		mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab);
+		mthca_uar_free(to_mdev(ibdev), &context->uar);
+		kfree(context);
+		return ERR_PTR(-EFAULT);
+	}
+
+	return &context->ibucontext;
+}
+
+static int mthca_dealloc_ucontext(struct ib_ucontext *context)
+{
+	mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar,
+				  to_mucontext(context)->db_tab);
+	mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar);
+	kfree(to_mucontext(context));
+
+	return 0;
+}
+
+static int mthca_mmap_uar(struct ib_ucontext *context,
+			  struct vm_area_struct *vma)
+{
+	if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	if (remap_pfn_range(vma, vma->vm_start,
+			    to_mucontext(context)->uar.pfn,
+			    PAGE_SIZE, vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev,
+				    struct ib_ucontext *context,
+				    struct ib_udata *udata)
 {
 	struct mthca_pd *pd;
 	int err;
@@ -293,12 +368,20 @@
 	if (!pd)
 		return ERR_PTR(-ENOMEM);
 
-	err = mthca_pd_alloc(to_mdev(ibdev), pd);
+	err = mthca_pd_alloc(to_mdev(ibdev), !context, pd);
 	if (err) {
 		kfree(pd);
 		return ERR_PTR(err);
 	}
 
+	if (context) {
+		if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) {
+			mthca_pd_free(to_mdev(ibdev), pd);
+			kfree(pd);
+			return ERR_PTR(-EFAULT);
+		}
+	}
+
 	return &pd->ibpd;
 }
 
@@ -338,8 +421,10 @@
 }
 
 static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
-				     struct ib_qp_init_attr *init_attr)
+				     struct ib_qp_init_attr *init_attr,
+				     struct ib_udata *udata)
 {
+	struct mthca_create_qp ucmd;
 	struct mthca_qp *qp;
 	int err;
 
@@ -348,41 +433,82 @@
 	case IB_QPT_UC:
 	case IB_QPT_UD:
 	{
+		struct mthca_ucontext *context;
+
 		qp = kmalloc(sizeof *qp, GFP_KERNEL);
 		if (!qp)
 			return ERR_PTR(-ENOMEM);
 
-		qp->sq.max    = init_attr->cap.max_send_wr;
-		qp->rq.max    = init_attr->cap.max_recv_wr;
-		qp->sq.max_gs = init_attr->cap.max_send_sge;
-		qp->rq.max_gs = init_attr->cap.max_recv_sge;
+		if (pd->uobject) {
+			context = to_mucontext(pd->uobject->context);
+
+			if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+				return ERR_PTR(-EFAULT);
+
+			err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
+						context->db_tab,
+						ucmd.sq_db_index, ucmd.sq_db_page);
+			if (err) {
+				kfree(qp);
+				return ERR_PTR(err);
+			}
+
+			err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
+						context->db_tab,
+						ucmd.rq_db_index, ucmd.rq_db_page);
+			if (err) {
+				mthca_unmap_user_db(to_mdev(pd->device),
+						    &context->uar,
+						    context->db_tab,
+						    ucmd.sq_db_index);
+				kfree(qp);
+				return ERR_PTR(err);
+			}
+
+			qp->mr.ibmr.lkey = ucmd.lkey;
+			qp->sq.db_index  = ucmd.sq_db_index;
+			qp->rq.db_index  = ucmd.rq_db_index;
+		}
 
 		err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd),
 				     to_mcq(init_attr->send_cq),
 				     to_mcq(init_attr->recv_cq),
 				     init_attr->qp_type, init_attr->sq_sig_type,
-				     qp);
+				     &init_attr->cap, qp);
+
+		if (err && pd->uobject) {
+			context = to_mucontext(pd->uobject->context);
+
+			mthca_unmap_user_db(to_mdev(pd->device),
+					    &context->uar,
+					    context->db_tab,
+					    ucmd.sq_db_index);
+			mthca_unmap_user_db(to_mdev(pd->device),
+					    &context->uar,
+					    context->db_tab,
+					    ucmd.rq_db_index);
+		}
+
 		qp->ibqp.qp_num = qp->qpn;
 		break;
 	}
 	case IB_QPT_SMI:
 	case IB_QPT_GSI:
 	{
+		/* Don't allow userspace to create special QPs */
+		if (pd->uobject)
+			return ERR_PTR(-EINVAL);
+
 		qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL);
 		if (!qp)
 			return ERR_PTR(-ENOMEM);
 
-		qp->sq.max    = init_attr->cap.max_send_wr;
-		qp->rq.max    = init_attr->cap.max_recv_wr;
-		qp->sq.max_gs = init_attr->cap.max_send_sge;
-		qp->rq.max_gs = init_attr->cap.max_recv_sge;
-
 		qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1;
 
 		err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd),
 				      to_mcq(init_attr->send_cq),
 				      to_mcq(init_attr->recv_cq),
-				      init_attr->sq_sig_type,
+				      init_attr->sq_sig_type, &init_attr->cap,
 				      qp->ibqp.qp_num, init_attr->port_num,
 				      to_msqp(qp));
 		break;
@@ -397,42 +523,115 @@
 		return ERR_PTR(err);
 	}
 
-        init_attr->cap.max_inline_data = 0;
+	init_attr->cap.max_inline_data = 0;
+	init_attr->cap.max_send_wr     = qp->sq.max;
+	init_attr->cap.max_recv_wr     = qp->rq.max;
+	init_attr->cap.max_send_sge    = qp->sq.max_gs;
+	init_attr->cap.max_recv_sge    = qp->rq.max_gs;
 
 	return &qp->ibqp;
 }
 
 static int mthca_destroy_qp(struct ib_qp *qp)
 {
+	if (qp->uobject) {
+		mthca_unmap_user_db(to_mdev(qp->device),
+				    &to_mucontext(qp->uobject->context)->uar,
+				    to_mucontext(qp->uobject->context)->db_tab,
+				    to_mqp(qp)->sq.db_index);
+		mthca_unmap_user_db(to_mdev(qp->device),
+				    &to_mucontext(qp->uobject->context)->uar,
+				    to_mucontext(qp->uobject->context)->db_tab,
+				    to_mqp(qp)->rq.db_index);
+	}
 	mthca_free_qp(to_mdev(qp->device), to_mqp(qp));
 	kfree(qp);
 	return 0;
 }
 
-static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries)
+static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
+				     struct ib_ucontext *context,
+				     struct ib_udata *udata)
 {
+	struct mthca_create_cq ucmd;
 	struct mthca_cq *cq;
 	int nent;
 	int err;
 
+	if (context) {
+		if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+			return ERR_PTR(-EFAULT);
+
+		err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+					to_mucontext(context)->db_tab,
+					ucmd.set_db_index, ucmd.set_db_page);
+		if (err)
+			return ERR_PTR(err);
+
+		err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+					to_mucontext(context)->db_tab,
+					ucmd.arm_db_index, ucmd.arm_db_page);
+		if (err)
+			goto err_unmap_set;
+	}
+
 	cq = kmalloc(sizeof *cq, GFP_KERNEL);
-	if (!cq)
-		return ERR_PTR(-ENOMEM);
+	if (!cq) {
+		err = -ENOMEM;
+		goto err_unmap_arm;
+	}
+
+	if (context) {
+		cq->mr.ibmr.lkey    = ucmd.lkey;
+		cq->set_ci_db_index = ucmd.set_db_index;
+		cq->arm_db_index    = ucmd.arm_db_index;
+	}
 
 	for (nent = 1; nent <= entries; nent <<= 1)
 		; /* nothing */
 
-	err = mthca_init_cq(to_mdev(ibdev), nent, cq);
-	if (err) {
-		kfree(cq);
-		cq = ERR_PTR(err);
+	err = mthca_init_cq(to_mdev(ibdev), nent,
+			    context ? to_mucontext(context) : NULL,
+			    context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,
+			    cq);
+	if (err)
+		goto err_free;
+
+	if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) {
+		mthca_free_cq(to_mdev(ibdev), cq);
+		goto err_free;
 	}
 
 	return &cq->ibcq;
+
+err_free:
+	kfree(cq);
+
+err_unmap_arm:
+	if (context)
+		mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+				    to_mucontext(context)->db_tab, ucmd.arm_db_index);
+
+err_unmap_set:
+	if (context)
+		mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+				    to_mucontext(context)->db_tab, ucmd.set_db_index);
+
+	return ERR_PTR(err);
 }
 
 static int mthca_destroy_cq(struct ib_cq *cq)
 {
+	if (cq->uobject) {
+		mthca_unmap_user_db(to_mdev(cq->device),
+				    &to_mucontext(cq->uobject->context)->uar,
+				    to_mucontext(cq->uobject->context)->db_tab,
+				    to_mcq(cq)->arm_db_index);
+		mthca_unmap_user_db(to_mdev(cq->device),
+				    &to_mucontext(cq->uobject->context)->uar,
+				    to_mucontext(cq->uobject->context)->db_tab,
+				    to_mcq(cq)->set_ci_db_index);
+	}
 	mthca_free_cq(to_mdev(cq->device), to_mcq(cq));
 	kfree(cq);
 
@@ -568,6 +767,87 @@
 	return &mr->ibmr;
 }
 
+static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
+				       int acc, struct ib_udata *udata)
+{
+	struct mthca_dev *dev = to_mdev(pd->device);
+	struct ib_umem_chunk *chunk;
+	struct mthca_mr *mr;
+	u64 *pages;
+	int shift, n, len;
+	int i, j, k;
+	int err = 0;
+
+	shift = ffs(region->page_size) - 1;
+
+	mr = kmalloc(sizeof *mr, GFP_KERNEL);
+	if (!mr)
+		return ERR_PTR(-ENOMEM);
+
+	n = 0;
+	list_for_each_entry(chunk, &region->chunk_list, list)
+		n += chunk->nents;
+
+	mr->mtt = mthca_alloc_mtt(dev, n);
+	if (IS_ERR(mr->mtt)) {
+		err = PTR_ERR(mr->mtt);
+		goto err;
+	}
+
+	pages = (u64 *) __get_free_page(GFP_KERNEL);
+	if (!pages) {
+		err = -ENOMEM;
+		goto err_mtt;
+	}
+
+	i = n = 0;
+
+	list_for_each_entry(chunk, &region->chunk_list, list)
+		for (j = 0; j < chunk->nmap; ++j) {
+			len = sg_dma_len(&chunk->page_list[j]) >> shift;
+			for (k = 0; k < len; ++k) {
+				pages[i++] = sg_dma_address(&chunk->page_list[j]) +
+					region->page_size * k;
+				/*
+				 * Be friendly to WRITE_MTT command
+				 * and leave two empty slots for the
+				 * index and reserved fields of the
+				 * mailbox.
+				 */
+				if (i == PAGE_SIZE / sizeof (u64) - 2) {
+					err = mthca_write_mtt(dev, mr->mtt,
+							      n, pages, i);
+					if (err)
+						goto mtt_done;
+					n += i;
+					i = 0;
+				}
+			}
+		}
+
+	if (i)
+		err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
+mtt_done:
+	free_page((unsigned long) pages);
+	if (err)
+		goto err_mtt;
+
+	err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base,
+			     region->length, convert_access(acc), mr);
+
+	if (err)
+		goto err_mtt;
+
+	return &mr->ibmr;
+
+err_mtt:
+	mthca_free_mtt(dev, mr->mtt);
+
+err:
+	kfree(mr);
+	return ERR_PTR(err);
+}
+
 static int mthca_dereg_mr(struct ib_mr *mr)
 {
 	struct mthca_mr *mmr = to_mmr(mr);
@@ -692,6 +972,8 @@
 	int i;
 
 	strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);
+	dev->ib_dev.owner                = THIS_MODULE;
+
 	dev->ib_dev.node_type            = IB_NODE_CA;
 	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
 	dev->ib_dev.dma_device           = &dev->pdev->dev;
@@ -701,6 +983,9 @@
 	dev->ib_dev.modify_port          = mthca_modify_port;
 	dev->ib_dev.query_pkey           = mthca_query_pkey;
 	dev->ib_dev.query_gid            = mthca_query_gid;
+	dev->ib_dev.alloc_ucontext       = mthca_alloc_ucontext;
+	dev->ib_dev.dealloc_ucontext     = mthca_dealloc_ucontext;
+	dev->ib_dev.mmap                 = mthca_mmap_uar;
 	dev->ib_dev.alloc_pd             = mthca_alloc_pd;
 	dev->ib_dev.dealloc_pd           = mthca_dealloc_pd;
 	dev->ib_dev.create_ah            = mthca_ah_create;
@@ -713,6 +998,7 @@
 	dev->ib_dev.poll_cq              = mthca_poll_cq;
 	dev->ib_dev.get_dma_mr           = mthca_get_dma_mr;
 	dev->ib_dev.reg_phys_mr          = mthca_reg_phys_mr;
+	dev->ib_dev.reg_user_mr          = mthca_reg_user_mr;
 	dev->ib_dev.dereg_mr             = mthca_dereg_mr;
 
 	if (dev->mthca_flags & MTHCA_FLAG_FMR) {
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 4d976cc..1d03279 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -54,6 +55,14 @@
 	int           index;
 };
 
+struct mthca_user_db_table;
+
+struct mthca_ucontext {
+	struct ib_ucontext          ibucontext;
+	struct mthca_uar            uar;
+	struct mthca_user_db_table *db_tab;
+};
+
 struct mthca_mtt;
 
 struct mthca_mr {
@@ -83,6 +92,7 @@
 	u32             pd_num;
 	atomic_t        sqp_count;
 	struct mthca_mr ntmr;
+	int             privileged;
 };
 
 struct mthca_eq {
@@ -167,6 +177,7 @@
 	int                    cqn;
 	u32                    cons_index;
 	int                    is_direct;
+	int                    is_kernel;
 
 	/* Next fields are Arbel only */
 	int                    set_ci_db_index;
@@ -236,6 +247,11 @@
 	dma_addr_t      header_dma;
 };
 
+static inline struct mthca_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
+{
+	return container_of(ibucontext, struct mthca_ucontext, ibucontext);
+}
+
 static inline struct mthca_fmr *to_mfmr(struct ib_fmr *ibmr)
 {
 	return container_of(ibmr, struct mthca_fmr, ibmr);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 163a8ef..f7126b1 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -46,7 +47,9 @@
 	MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE,
 	MTHCA_ACK_REQ_FREQ       = 10,
 	MTHCA_FLIGHT_LIMIT       = 9,
-	MTHCA_UD_HEADER_SIZE     = 72 /* largest UD header possible */
+	MTHCA_UD_HEADER_SIZE     = 72, /* largest UD header possible */
+	MTHCA_INLINE_HEADER_SIZE = 4,  /* data segment overhead for inline */
+	MTHCA_INLINE_CHUNK_SIZE  = 16  /* inline data segment chunk */
 };
 
 enum {
@@ -689,7 +692,11 @@
 
 	/* leave arbel_sched_queue as 0 */
 
-	qp_context->usr_page   = cpu_to_be32(dev->driver_uar.index);
+	if (qp->ibqp.uobject)
+		qp_context->usr_page =
+			cpu_to_be32(to_mucontext(qp->ibqp.uobject->context)->uar.index);
+	else
+		qp_context->usr_page = cpu_to_be32(dev->driver_uar.index);
 	qp_context->local_qpn  = cpu_to_be32(qp->qpn);
 	if (attr_mask & IB_QP_DEST_QPN) {
 		qp_context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
@@ -954,6 +961,15 @@
 
 	qp->send_wqe_offset = ALIGN(qp->rq.max << qp->rq.wqe_shift,
 				    1 << qp->sq.wqe_shift);
+
+	/*
+	 * If this is a userspace QP, we don't actually have to
+	 * allocate anything.  All we need is to calculate the WQE
+	 * sizes and the send_wqe_offset, so we're done now.
+	 */
+	if (pd->ibpd.uobject)
+		return 0;
+
 	size = PAGE_ALIGN(qp->send_wqe_offset +
 			  (qp->sq.max << qp->sq.wqe_shift));
 
@@ -1053,10 +1069,32 @@
 	return err;
 }
 
-static int mthca_alloc_memfree(struct mthca_dev *dev,
+static void mthca_free_wqe_buf(struct mthca_dev *dev,
 			       struct mthca_qp *qp)
 {
-	int ret = 0;
+	int i;
+	int size = PAGE_ALIGN(qp->send_wqe_offset +
+			      (qp->sq.max << qp->sq.wqe_shift));
+
+	if (qp->is_direct) {
+		dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
+				  pci_unmap_addr(&qp->queue.direct, mapping));
+	} else {
+		for (i = 0; i < size / PAGE_SIZE; ++i) {
+			dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+					  qp->queue.page_list[i].buf,
+					  pci_unmap_addr(&qp->queue.page_list[i],
+							 mapping));
+		}
+	}
+
+	kfree(qp->wrid);
+}
+
+static int mthca_map_memfree(struct mthca_dev *dev,
+			     struct mthca_qp *qp)
+{
+	int ret;
 
 	if (mthca_is_memfree(dev)) {
 		ret = mthca_table_get(dev, dev->qp_table.qp_table, qp->qpn);
@@ -1067,35 +1105,15 @@
 		if (ret)
 			goto err_qpc;
 
-		ret = mthca_table_get(dev, dev->qp_table.rdb_table,
-				      qp->qpn << dev->qp_table.rdb_shift);
-		if (ret)
-			goto err_eqpc;
+ 		ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+ 				      qp->qpn << dev->qp_table.rdb_shift);
+ 		if (ret)
+ 			goto err_eqpc;
 
-		qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
-						 qp->qpn, &qp->rq.db);
-		if (qp->rq.db_index < 0) {
-			ret = -ENOMEM;
-			goto err_rdb;
-		}
-
-		qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
-						 qp->qpn, &qp->sq.db);
-		if (qp->sq.db_index < 0) {
-			ret = -ENOMEM;
-			goto err_rq_db;
-		}
 	}
 
 	return 0;
 
-err_rq_db:
-	mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
-
-err_rdb:
-	mthca_table_put(dev, dev->qp_table.rdb_table,
-			qp->qpn << dev->qp_table.rdb_shift);
-
 err_eqpc:
 	mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
 
@@ -1105,6 +1123,35 @@
 	return ret;
 }
 
+static void mthca_unmap_memfree(struct mthca_dev *dev,
+				struct mthca_qp *qp)
+{
+	mthca_table_put(dev, dev->qp_table.rdb_table,
+			qp->qpn << dev->qp_table.rdb_shift);
+	mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+	mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
+}
+
+static int mthca_alloc_memfree(struct mthca_dev *dev,
+			       struct mthca_qp *qp)
+{
+	int ret = 0;
+
+	if (mthca_is_memfree(dev)) {
+		qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
+						 qp->qpn, &qp->rq.db);
+		if (qp->rq.db_index < 0)
+			return ret;
+
+		qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
+						 qp->qpn, &qp->sq.db);
+		if (qp->sq.db_index < 0)
+			mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
+	}
+
+	return ret;
+}
+
 static void mthca_free_memfree(struct mthca_dev *dev,
 			       struct mthca_qp *qp)
 {
@@ -1112,11 +1159,6 @@
 		mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
 		mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
 	}
-
-	mthca_table_put(dev, dev->qp_table.rdb_table,
-			qp->qpn << dev->qp_table.rdb_shift);
-	mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
-	mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
 }
 
 static void mthca_wq_init(struct mthca_wq* wq)
@@ -1147,13 +1189,28 @@
 	mthca_wq_init(&qp->sq);
 	mthca_wq_init(&qp->rq);
 
-	ret = mthca_alloc_memfree(dev, qp);
+	ret = mthca_map_memfree(dev, qp);
 	if (ret)
 		return ret;
 
 	ret = mthca_alloc_wqe_buf(dev, pd, qp);
 	if (ret) {
-		mthca_free_memfree(dev, qp);
+		mthca_unmap_memfree(dev, qp);
+		return ret;
+	}
+
+	/*
+	 * If this is a userspace QP, we're done now.  The doorbells
+	 * will be allocated and buffers will be initialized in
+	 * userspace.
+	 */
+	if (pd->ibpd.uobject)
+		return 0;
+
+	ret = mthca_alloc_memfree(dev, qp);
+	if (ret) {
+		mthca_free_wqe_buf(dev, qp);
+		mthca_unmap_memfree(dev, qp);
 		return ret;
 	}
 
@@ -1186,22 +1243,39 @@
 	return 0;
 }
 
-static void mthca_align_qp_size(struct mthca_dev *dev, struct mthca_qp *qp)
+static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap,
+			     struct mthca_qp *qp)
 {
-	int i;
+	/* Sanity check QP size before proceeding */
+	if (cap->max_send_wr  > 65536 || cap->max_recv_wr  > 65536 ||
+	    cap->max_send_sge > 64    || cap->max_recv_sge > 64)
+		return -EINVAL;
 
-	if (!mthca_is_memfree(dev))
-		return;
+	if (mthca_is_memfree(dev)) {
+		qp->rq.max = cap->max_recv_wr ?
+			roundup_pow_of_two(cap->max_recv_wr) : 0;
+		qp->sq.max = cap->max_send_wr ?
+			roundup_pow_of_two(cap->max_send_wr) : 0;
+	} else {
+		qp->rq.max = cap->max_recv_wr;
+		qp->sq.max = cap->max_send_wr;
+	}
 
-	for (i = 0; 1 << i < qp->rq.max; ++i)
-		; /* nothing */
+	qp->rq.max_gs = cap->max_recv_sge;
+	qp->sq.max_gs = max_t(int, cap->max_send_sge,
+			      ALIGN(cap->max_inline_data + MTHCA_INLINE_HEADER_SIZE,
+				    MTHCA_INLINE_CHUNK_SIZE) /
+			      sizeof (struct mthca_data_seg));
 
-	qp->rq.max = 1 << i;
+	/*
+	 * For MLX transport we need 2 extra S/G entries:
+	 * one for the header and one for the checksum at the end
+	 */
+	if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) ||
+	    qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg)
+		return -EINVAL;
 
-	for (i = 0; 1 << i < qp->sq.max; ++i)
-		; /* nothing */
-
-	qp->sq.max = 1 << i;
+	return 0;
 }
 
 int mthca_alloc_qp(struct mthca_dev *dev,
@@ -1210,11 +1284,14 @@
 		   struct mthca_cq *recv_cq,
 		   enum ib_qp_type type,
 		   enum ib_sig_type send_policy,
+		   struct ib_qp_cap *cap,
 		   struct mthca_qp *qp)
 {
 	int err;
 
-	mthca_align_qp_size(dev, qp);
+	err = mthca_set_qp_size(dev, cap, qp);
+	if (err)
+		return err;
 
 	switch (type) {
 	case IB_QPT_RC: qp->transport = RC; break;
@@ -1247,14 +1324,17 @@
 		    struct mthca_cq *send_cq,
 		    struct mthca_cq *recv_cq,
 		    enum ib_sig_type send_policy,
+		    struct ib_qp_cap *cap,
 		    int qpn,
 		    int port,
 		    struct mthca_sqp *sqp)
 {
-	int err = 0;
 	u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1;
+	int err;
 
-	mthca_align_qp_size(dev, &sqp->qp);
+	err = mthca_set_qp_size(dev, cap, &sqp->qp);
+	if (err)
+		return err;
 
 	sqp->header_buf_size = sqp->qp.sq.max * MTHCA_UD_HEADER_SIZE;
 	sqp->header_buf = dma_alloc_coherent(&dev->pdev->dev, sqp->header_buf_size,
@@ -1313,8 +1393,6 @@
 		   struct mthca_qp *qp)
 {
 	u8 status;
-	int size;
-	int i;
 	struct mthca_cq *send_cq;
 	struct mthca_cq *recv_cq;
 
@@ -1344,31 +1422,22 @@
 	if (qp->state != IB_QPS_RESET)
 		mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status);
 
-	mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn);
-	if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
-		mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
+	/*
+	 * If this is a userspace QP, the buffers, MR, CQs and so on
+	 * will be cleaned up in userspace, so all we have to do is
+	 * unref the mem-free tables and free the QPN in our table.
+	 */
+	if (!qp->ibqp.uobject) {
+		mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn);
+		if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
+			mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
 
-	mthca_free_mr(dev, &qp->mr);
-
-	size = PAGE_ALIGN(qp->send_wqe_offset +
-			  (qp->sq.max << qp->sq.wqe_shift));
-
-	if (qp->is_direct) {
-		pci_free_consistent(dev->pdev, size,
-				    qp->queue.direct.buf,
-				    pci_unmap_addr(&qp->queue.direct, mapping));
-	} else {
-		for (i = 0; i < size / PAGE_SIZE; ++i) {
-			pci_free_consistent(dev->pdev, PAGE_SIZE,
-					    qp->queue.page_list[i].buf,
-					    pci_unmap_addr(&qp->queue.page_list[i],
-							   mapping));
-		}
+		mthca_free_mr(dev, &qp->mr);
+		mthca_free_memfree(dev, qp);
+		mthca_free_wqe_buf(dev, qp);
 	}
 
-	kfree(qp->wrid);
-
-	mthca_free_memfree(dev, qp);
+	mthca_unmap_memfree(dev, qp);
 
 	if (is_sqp(dev, qp)) {
 		atomic_dec(&(to_mpd(qp->ibqp.pd)->sqp_count));
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h
new file mode 100644
index 0000000..3024c1b
--- /dev/null
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef MTHCA_USER_H
+#define MTHCA_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct mthca_alloc_ucontext_resp {
+	__u32 qp_tab_size;
+	__u32 uarc_size;
+};
+
+struct mthca_alloc_pd_resp {
+	__u32 pdn;
+	__u32 reserved;
+};
+
+struct mthca_create_cq {
+	__u32 lkey;
+	__u32 pdn;
+	__u64 arm_db_page;
+	__u64 set_db_page;
+	__u32 arm_db_index;
+	__u32 set_db_index;
+};
+
+struct mthca_create_cq_resp {
+	__u32 cqn;
+	__u32 reserved;
+};
+
+struct mthca_create_qp {
+	__u32 lkey;
+	__u32 reserved;
+	__u64 sq_db_page;
+	__u64 rq_db_page;
+	__u32 sq_db_index;
+	__u32 rq_db_index;
+};
+
+#endif /* MTHCA_USER_H */
diff --git a/drivers/infiniband/include/ib_user_verbs.h b/drivers/infiniband/include/ib_user_verbs.h
new file mode 100644
index 0000000..7c61370
--- /dev/null
+++ b/drivers/infiniband/include/ib_user_verbs.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: ib_user_verbs.h 2708 2005-06-24 17:27:21Z roland $
+ */
+
+#ifndef IB_USER_VERBS_H
+#define IB_USER_VERBS_H
+
+#include <linux/types.h>
+
+/*
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define IB_USER_VERBS_ABI_VERSION	1
+
+enum {
+	IB_USER_VERBS_CMD_QUERY_PARAMS,
+	IB_USER_VERBS_CMD_GET_CONTEXT,
+	IB_USER_VERBS_CMD_QUERY_DEVICE,
+	IB_USER_VERBS_CMD_QUERY_PORT,
+	IB_USER_VERBS_CMD_QUERY_GID,
+	IB_USER_VERBS_CMD_QUERY_PKEY,
+	IB_USER_VERBS_CMD_ALLOC_PD,
+	IB_USER_VERBS_CMD_DEALLOC_PD,
+	IB_USER_VERBS_CMD_CREATE_AH,
+	IB_USER_VERBS_CMD_MODIFY_AH,
+	IB_USER_VERBS_CMD_QUERY_AH,
+	IB_USER_VERBS_CMD_DESTROY_AH,
+	IB_USER_VERBS_CMD_REG_MR,
+	IB_USER_VERBS_CMD_REG_SMR,
+	IB_USER_VERBS_CMD_REREG_MR,
+	IB_USER_VERBS_CMD_QUERY_MR,
+	IB_USER_VERBS_CMD_DEREG_MR,
+	IB_USER_VERBS_CMD_ALLOC_MW,
+	IB_USER_VERBS_CMD_BIND_MW,
+	IB_USER_VERBS_CMD_DEALLOC_MW,
+	IB_USER_VERBS_CMD_CREATE_CQ,
+	IB_USER_VERBS_CMD_RESIZE_CQ,
+	IB_USER_VERBS_CMD_DESTROY_CQ,
+	IB_USER_VERBS_CMD_POLL_CQ,
+	IB_USER_VERBS_CMD_PEEK_CQ,
+	IB_USER_VERBS_CMD_REQ_NOTIFY_CQ,
+	IB_USER_VERBS_CMD_CREATE_QP,
+	IB_USER_VERBS_CMD_QUERY_QP,
+	IB_USER_VERBS_CMD_MODIFY_QP,
+	IB_USER_VERBS_CMD_DESTROY_QP,
+	IB_USER_VERBS_CMD_POST_SEND,
+	IB_USER_VERBS_CMD_POST_RECV,
+	IB_USER_VERBS_CMD_ATTACH_MCAST,
+	IB_USER_VERBS_CMD_DETACH_MCAST
+};
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct ib_uverbs_async_event_desc {
+	__u64 element;
+	__u32 event_type;	/* enum ib_event_type */
+	__u32 reserved;
+};
+
+struct ib_uverbs_comp_event_desc {
+	__u64 cq_handle;
+};
+
+/*
+ * All commands from userspace should start with a __u32 command field
+ * followed by __u16 in_words and out_words fields (which give the
+ * length of the command block and response buffer if any in 32-bit
+ * words).  The kernel driver will read these fields first and read
+ * the rest of the command struct based on these value.
+ */
+
+struct ib_uverbs_cmd_hdr {
+	__u32 command;
+	__u16 in_words;
+	__u16 out_words;
+};
+
+/*
+ * No driver_data for "query params" command, since this is intended
+ * to be a core function with no possible device dependence.
+ */
+struct ib_uverbs_query_params {
+	__u64 response;
+};
+
+struct ib_uverbs_query_params_resp {
+	__u32 num_cq_events;
+};
+
+struct ib_uverbs_get_context {
+	__u64 response;
+	__u64 cq_fd_tab;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_get_context_resp {
+	__u32 async_fd;
+	__u32 reserved;
+};
+
+struct ib_uverbs_query_device {
+	__u64 response;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_device_resp {
+	__u64 fw_ver;
+	__u64 node_guid;
+	__u64 sys_image_guid;
+	__u64 max_mr_size;
+	__u64 page_size_cap;
+	__u32 vendor_id;
+	__u32 vendor_part_id;
+	__u32 hw_ver;
+	__u32 max_qp;
+	__u32 max_qp_wr;
+	__u32 device_cap_flags;
+	__u32 max_sge;
+	__u32 max_sge_rd;
+	__u32 max_cq;
+	__u32 max_cqe;
+	__u32 max_mr;
+	__u32 max_pd;
+	__u32 max_qp_rd_atom;
+	__u32 max_ee_rd_atom;
+	__u32 max_res_rd_atom;
+	__u32 max_qp_init_rd_atom;
+	__u32 max_ee_init_rd_atom;
+	__u32 atomic_cap;
+	__u32 max_ee;
+	__u32 max_rdd;
+	__u32 max_mw;
+	__u32 max_raw_ipv6_qp;
+	__u32 max_raw_ethy_qp;
+	__u32 max_mcast_grp;
+	__u32 max_mcast_qp_attach;
+	__u32 max_total_mcast_qp_attach;
+	__u32 max_ah;
+	__u32 max_fmr;
+	__u32 max_map_per_fmr;
+	__u32 max_srq;
+	__u32 max_srq_wr;
+	__u32 max_srq_sge;
+	__u16 max_pkeys;
+	__u8  local_ca_ack_delay;
+	__u8  phys_port_cnt;
+	__u8  reserved[4];
+};
+
+struct ib_uverbs_query_port {
+	__u64 response;
+	__u8  port_num;
+	__u8  reserved[7];
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_port_resp {
+	__u32 port_cap_flags;
+	__u32 max_msg_sz;
+	__u32 bad_pkey_cntr;
+	__u32 qkey_viol_cntr;
+	__u32 gid_tbl_len;
+	__u16 pkey_tbl_len;
+	__u16 lid;
+	__u16 sm_lid;
+	__u8  state;
+	__u8  max_mtu;
+	__u8  active_mtu;
+	__u8  lmc;
+	__u8  max_vl_num;
+	__u8  sm_sl;
+	__u8  subnet_timeout;
+	__u8  init_type_reply;
+	__u8  active_width;
+	__u8  active_speed;
+	__u8  phys_state;
+	__u8  reserved[3];
+};
+
+struct ib_uverbs_query_gid {
+	__u64 response;
+	__u8  port_num;
+	__u8  index;
+	__u8  reserved[6];
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_gid_resp {
+	__u8  gid[16];
+};
+
+struct ib_uverbs_query_pkey {
+	__u64 response;
+	__u8  port_num;
+	__u8  index;
+	__u8  reserved[6];
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_pkey_resp {
+	__u16 pkey;
+	__u16 reserved;
+};
+
+struct ib_uverbs_alloc_pd {
+	__u64 response;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_alloc_pd_resp {
+	__u32 pd_handle;
+};
+
+struct ib_uverbs_dealloc_pd {
+	__u32 pd_handle;
+};
+
+struct ib_uverbs_reg_mr {
+	__u64 response;
+	__u64 start;
+	__u64 length;
+	__u64 hca_va;
+	__u32 pd_handle;
+	__u32 access_flags;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_reg_mr_resp {
+	__u32 mr_handle;
+	__u32 lkey;
+	__u32 rkey;
+};
+
+struct ib_uverbs_dereg_mr {
+	__u32 mr_handle;
+};
+
+struct ib_uverbs_create_cq {
+	__u64 response;
+	__u64 user_handle;
+	__u32 cqe;
+	__u32 event_handler;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_create_cq_resp {
+	__u32 cq_handle;
+	__u32 cqe;
+};
+
+struct ib_uverbs_destroy_cq {
+	__u32 cq_handle;
+};
+
+struct ib_uverbs_create_qp {
+	__u64 response;
+	__u64 user_handle;
+	__u32 pd_handle;
+	__u32 send_cq_handle;
+	__u32 recv_cq_handle;
+	__u32 srq_handle;
+	__u32 max_send_wr;
+	__u32 max_recv_wr;
+	__u32 max_send_sge;
+	__u32 max_recv_sge;
+	__u32 max_inline_data;
+	__u8  sq_sig_all;
+	__u8  qp_type;
+	__u8  is_srq;
+	__u8  reserved;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_create_qp_resp {
+	__u32 qp_handle;
+	__u32 qpn;
+};
+
+/*
+ * This struct needs to remain a multiple of 8 bytes to keep the
+ * alignment of the modify QP parameters.
+ */
+struct ib_uverbs_qp_dest {
+	__u8  dgid[16];
+	__u32 flow_label;
+	__u16 dlid;
+	__u16 reserved;
+	__u8  sgid_index;
+	__u8  hop_limit;
+	__u8  traffic_class;
+	__u8  sl;
+	__u8  src_path_bits;
+	__u8  static_rate;
+	__u8  is_global;
+	__u8  port_num;
+};
+
+struct ib_uverbs_modify_qp {
+	struct ib_uverbs_qp_dest dest;
+	struct ib_uverbs_qp_dest alt_dest;
+	__u32 qp_handle;
+	__u32 attr_mask;
+	__u32 qkey;
+	__u32 rq_psn;
+	__u32 sq_psn;
+	__u32 dest_qp_num;
+	__u32 qp_access_flags;
+	__u16 pkey_index;
+	__u16 alt_pkey_index;
+	__u8  qp_state;
+	__u8  cur_qp_state;
+	__u8  path_mtu;
+	__u8  path_mig_state;
+	__u8  en_sqd_async_notify;
+	__u8  max_rd_atomic;
+	__u8  max_dest_rd_atomic;
+	__u8  min_rnr_timer;
+	__u8  port_num;
+	__u8  timeout;
+	__u8  retry_cnt;
+	__u8  rnr_retry;
+	__u8  alt_port_num;
+	__u8  alt_timeout;
+	__u8  reserved[2];
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_modify_qp_resp {
+};
+
+struct ib_uverbs_destroy_qp {
+	__u32 qp_handle;
+};
+
+struct ib_uverbs_attach_mcast {
+	__u8  gid[16];
+	__u32 qp_handle;
+	__u16 mlid;
+	__u16 reserved;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_detach_mcast {
+	__u8  gid[16];
+	__u32 qp_handle;
+	__u16 mlid;
+	__u16 reserved;
+	__u64 driver_data[0];
+};
+
+#endif /* IB_USER_VERBS_H */
diff --git a/drivers/infiniband/include/ib_verbs.h b/drivers/infiniband/include/ib_verbs.h
index cf01f04..e5bd9a1 100644
--- a/drivers/infiniband/include/ib_verbs.h
+++ b/drivers/infiniband/include/ib_verbs.h
@@ -4,6 +4,7 @@
  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -41,7 +42,10 @@
 
 #include <linux/types.h>
 #include <linux/device.h>
+
 #include <asm/atomic.h>
+#include <asm/scatterlist.h>
+#include <asm/uaccess.h>
 
 union ib_gid {
 	u8	raw[16];
@@ -544,7 +548,7 @@
 	int			num_sge;
 	enum ib_wr_opcode	opcode;
 	int			send_flags;
-	u32			imm_data;
+	__be32			imm_data;
 	union {
 		struct {
 			u64	remote_addr;
@@ -618,29 +622,86 @@
 	u8	page_size;
 };
 
+struct ib_ucontext {
+	struct ib_device       *device;
+	struct list_head	pd_list;
+	struct list_head	mr_list;
+	struct list_head	mw_list;
+	struct list_head	cq_list;
+	struct list_head	qp_list;
+	struct list_head	srq_list;
+	struct list_head	ah_list;
+	spinlock_t              lock;
+};
+
+struct ib_uobject {
+	u64			user_handle;	/* handle given to us by userspace */
+	struct ib_ucontext     *context;	/* associated user context */
+	struct list_head	list;		/* link to context's list */
+	u32			id;		/* index into kernel idr */
+};
+
+struct ib_umem {
+	unsigned long		user_base;
+	unsigned long		virt_base;
+	size_t			length;
+	int			offset;
+	int			page_size;
+	int                     writable;
+	struct list_head	chunk_list;
+};
+
+struct ib_umem_chunk {
+	struct list_head	list;
+	int                     nents;
+	int                     nmap;
+	struct scatterlist      page_list[0];
+};
+
+struct ib_udata {
+	void __user *inbuf;
+	void __user *outbuf;
+	size_t       inlen;
+	size_t       outlen;
+};
+
+#define IB_UMEM_MAX_PAGE_CHUNK						\
+	((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) /	\
+	 ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] -	\
+	  (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
+
+struct ib_umem_object {
+	struct ib_uobject	uobject;
+	struct ib_umem		umem;
+};
+
 struct ib_pd {
-	struct ib_device *device;
-	atomic_t          usecnt; /* count all resources */
+	struct ib_device       *device;
+	struct ib_uobject      *uobject;
+	atomic_t          	usecnt; /* count all resources */
 };
 
 struct ib_ah {
 	struct ib_device	*device;
 	struct ib_pd		*pd;
+	struct ib_uobject	*uobject;
 };
 
 typedef void (*ib_comp_handler)(struct ib_cq *cq, void *cq_context);
 
 struct ib_cq {
-	struct ib_device *device;
-	ib_comp_handler   comp_handler;
-	void             (*event_handler)(struct ib_event *, void *);
-	void *            cq_context;
-	int               cqe;
-	atomic_t          usecnt; /* count number of work queues */
+	struct ib_device       *device;
+	struct ib_uobject      *uobject;
+	ib_comp_handler   	comp_handler;
+	void                  (*event_handler)(struct ib_event *, void *);
+	void *            	cq_context;
+	int               	cqe;
+	atomic_t          	usecnt; /* count number of work queues */
 };
 
 struct ib_srq {
 	struct ib_device	*device;
+	struct ib_uobject	*uobject;
 	struct ib_pd		*pd;
 	void			*srq_context;
 	atomic_t		usecnt;
@@ -652,6 +713,7 @@
 	struct ib_cq	       *send_cq;
 	struct ib_cq	       *recv_cq;
 	struct ib_srq	       *srq;
+	struct ib_uobject      *uobject;
 	void                  (*event_handler)(struct ib_event *, void *);
 	void		       *qp_context;
 	u32			qp_num;
@@ -659,16 +721,18 @@
 };
 
 struct ib_mr {
-	struct ib_device *device;
-	struct ib_pd     *pd;
-	u32		  lkey;
-	u32		  rkey;
-	atomic_t          usecnt; /* count number of MWs */
+	struct ib_device  *device;
+	struct ib_pd	  *pd;
+	struct ib_uobject *uobject;
+	u32		   lkey;
+	u32		   rkey;
+	atomic_t	   usecnt; /* count number of MWs */
 };
 
 struct ib_mw {
 	struct ib_device	*device;
 	struct ib_pd		*pd;
+	struct ib_uobject	*uobject;
 	u32			rkey;
 };
 
@@ -737,7 +801,14 @@
 	int		           (*modify_port)(struct ib_device *device,
 						  u8 port_num, int port_modify_mask,
 						  struct ib_port_modify *port_modify);
-	struct ib_pd *             (*alloc_pd)(struct ib_device *device);
+	struct ib_ucontext *       (*alloc_ucontext)(struct ib_device *device,
+						     struct ib_udata *udata);
+	int                        (*dealloc_ucontext)(struct ib_ucontext *context);
+	int                        (*mmap)(struct ib_ucontext *context,
+					   struct vm_area_struct *vma);
+	struct ib_pd *             (*alloc_pd)(struct ib_device *device,
+					       struct ib_ucontext *context,
+					       struct ib_udata *udata);
 	int                        (*dealloc_pd)(struct ib_pd *pd);
 	struct ib_ah *             (*create_ah)(struct ib_pd *pd,
 						struct ib_ah_attr *ah_attr);
@@ -747,7 +818,8 @@
 					       struct ib_ah_attr *ah_attr);
 	int                        (*destroy_ah)(struct ib_ah *ah);
 	struct ib_qp *             (*create_qp)(struct ib_pd *pd,
-						struct ib_qp_init_attr *qp_init_attr);
+						struct ib_qp_init_attr *qp_init_attr,
+						struct ib_udata *udata);
 	int                        (*modify_qp)(struct ib_qp *qp,
 						struct ib_qp_attr *qp_attr,
 						int qp_attr_mask);
@@ -762,8 +834,9 @@
 	int                        (*post_recv)(struct ib_qp *qp,
 						struct ib_recv_wr *recv_wr,
 						struct ib_recv_wr **bad_recv_wr);
-	struct ib_cq *             (*create_cq)(struct ib_device *device,
-						int cqe);
+	struct ib_cq *             (*create_cq)(struct ib_device *device, int cqe,
+						struct ib_ucontext *context,
+						struct ib_udata *udata);
 	int                        (*destroy_cq)(struct ib_cq *cq);
 	int                        (*resize_cq)(struct ib_cq *cq, int *cqe);
 	int                        (*poll_cq)(struct ib_cq *cq, int num_entries,
@@ -780,6 +853,10 @@
 						  int num_phys_buf,
 						  int mr_access_flags,
 						  u64 *iova_start);
+	struct ib_mr *             (*reg_user_mr)(struct ib_pd *pd,
+						  struct ib_umem *region,
+						  int mr_access_flags,
+						  struct ib_udata *udata);
 	int                        (*query_mr)(struct ib_mr *mr,
 					       struct ib_mr_attr *mr_attr);
 	int                        (*dereg_mr)(struct ib_mr *mr);
@@ -817,6 +894,7 @@
 						  struct ib_mad *in_mad,
 						  struct ib_mad *out_mad);
 
+	struct module               *owner;
 	struct class_device          class_dev;
 	struct kobject               ports_parent;
 	struct list_head             port_list;
@@ -852,6 +930,16 @@
 void  ib_set_client_data(struct ib_device *device, struct ib_client *client,
 			 void *data);
 
+static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len)
+{
+	return copy_from_user(dest, udata->inbuf, len) ? -EFAULT : 0;
+}
+
+static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len)
+{
+	return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0;
+}
+
 int ib_register_event_handler  (struct ib_event_handler *event_handler);
 int ib_unregister_event_handler(struct ib_event_handler *event_handler);
 void ib_dispatch_event(struct ib_event *event);
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index ee750e9..db9bad2 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -22,7 +22,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -161,11 +160,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &avmcs_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -500,6 +494,7 @@
 		.name	= "avm_cs",
 	},
 	.attach	= avmcs_attach,
+	.event	= avmcs_event,
 	.detach	= avmcs_detach,
 	.id_table = avmcs_ids,
 };
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 67c60e0..0e22991 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -21,7 +21,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -183,11 +182,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &avma1cs_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -514,6 +508,7 @@
 		.name	= "avma1_cs",
 	},
 	.attach		= avma1cs_attach,
+	.event		= avma1cs_event,
 	.detach		= avma1cs_detach,
 	.id_table	= avma1cs_ids,
 };
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index 9146be5..6fc6868 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -47,7 +47,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -212,11 +211,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &elsa_cs_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -521,6 +515,7 @@
 		.name	= "elsa_cs",
 	},
 	.attach		= elsa_cs_attach,
+	.event		= elsa_cs_event,
 	.detach		= elsa_cs_detach,
 	.id_table	= elsa_ids,
 };
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index ac89950..bab3568 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -279,7 +279,8 @@
 	if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
 		st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 	if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
-		if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) {
+		if (!test_bit(BC_FLG_BUSY, &bcs->Flag) &&
+		    skb_queue_empty(&bcs->squeue)) {
 			st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
 		}
 	}
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index 9022583..1615c1a 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -108,7 +108,8 @@
 static void
 set_peer_busy(struct Layer2 *l2) {
 	test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
-	if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
+	if (!skb_queue_empty(&l2->i_queue) ||
+	    !skb_queue_empty(&l2->ui_queue))
 		test_and_set_bit(FLG_L2BLOCK, &l2->flag);
 }
 
@@ -754,7 +755,7 @@
 		st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
 
 	if ((ST_L2_7==state) || (ST_L2_8 == state))
-		if (skb_queue_len(&st->l2.i_queue) && cansend(st))
+		if (!skb_queue_empty(&st->l2.i_queue) && cansend(st))
 			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
@@ -810,7 +811,7 @@
 	if (pr != -1)
 		st->l2.l2l3(st, pr, NULL);
 
-	if (skb_queue_len(&st->l2.i_queue) && cansend(st))
+	if (!skb_queue_empty(&st->l2.i_queue) && cansend(st))
 		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
@@ -1014,7 +1015,7 @@
 			if(typ != RR) FsmDelTimer(&st->l2.t203, 9);
 			restart_t200(st, 12);
 		}
-		if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
+		if (!skb_queue_empty(&st->l2.i_queue) && (typ == RR))
 			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 	} else
 		nrerrorrecovery(fi);
@@ -1120,7 +1121,7 @@
 		return;
 	}
 
-	if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
+	if (!skb_queue_empty(&st->l2.i_queue) && (fi->state == ST_L2_7))
 		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 	if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
 		enquiry_cr(st, RR, RSP, 0);
@@ -1138,7 +1139,7 @@
 		test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
 	} else
 		FsmChangeState(fi, ST_L2_4);
-	if (skb_queue_len(&st->l2.ui_queue))
+	if (!skb_queue_empty(&st->l2.ui_queue))
 		tx_ui(st);
 }
 
@@ -1301,7 +1302,7 @@
 		FsmDelTimer(&st->l2.t203, 13);
 		FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
 	}
-	if (skb_queue_len(&l2->i_queue) && cansend(st))
+	if (!skb_queue_empty(&l2->i_queue) && cansend(st))
 		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
@@ -1347,7 +1348,7 @@
 			}
 			invoke_retransmission(st, nr);
 			FsmChangeState(fi, ST_L2_7);
-			if (skb_queue_len(&l2->i_queue) && cansend(st))
+			if (!skb_queue_empty(&l2->i_queue) && cansend(st))
 				st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 		} else
 			nrerrorrecovery(fi);
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index abcc953..c9917cd 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -302,7 +302,7 @@
 				!test_bit(FLG_PTP, &p->st->l2.flag)) {
 				if (p->debug)
 					l3_debug(p->st, "release_l3_process: last process");
-				if (!skb_queue_len(&p->st->l3.squeue)) {
+				if (skb_queue_empty(&p->st->l3.squeue)) {
 					if (p->debug)
 						l3_debug(p->st, "release_l3_process: release link");
 					if (p->st->protocol != ISDN_PTYPE_NI1)
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 058147a..c6b5bf7 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -47,7 +47,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -226,11 +225,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &sedlbauer_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -634,6 +628,7 @@
 		.name	= "sedlbauer_cs",
 	},
 	.attach		= sedlbauer_attach,
+	.event		= sedlbauer_event,
 	.detach		= sedlbauer_detach,
 	.id_table	= sedlbauer_ids,
 };
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 107376f..0ddef1b 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -28,7 +28,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -193,11 +192,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &teles_cs_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -501,6 +495,7 @@
 		.name	= "teles_cs",
 	},
 	.attach		= teles_attach,
+	.event		= teles_cs_event,
 	.detach		= teles_detach,
 	.id_table       = teles_ids,
 };
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index ad5aa38..b37ef1f 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1223,7 +1223,7 @@
 		total += c;
 	}
 	atomic_dec(&info->xmit_lock);
-	if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
+	if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) {
 		if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
 			isdn_tty_senddown(info);
 			isdn_tty_tint(info);
@@ -1284,7 +1284,7 @@
 
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
 		return;
-	if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
+	if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue))
 		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 }
 
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 9fc0c1e..e0d1b01 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -304,12 +304,12 @@
 	isdn_ctrl cmd;
 
 	if (!(card->sndcount[channel] || card->xskb[channel] ||
-	      skb_queue_len(&card->spqueue[channel])))
+	      !skb_queue_empty(&card->spqueue[channel])))
 		return;
 	if (icn_trymaplock_channel(card, mch)) {
 		while (sbfree && 
 		       (card->sndcount[channel] ||
-			skb_queue_len(&card->spqueue[channel]) ||
+			!skb_queue_empty(&card->spqueue[channel]) ||
 			card->xskb[channel])) {
 			spin_lock_irqsave(&card->lock, flags);
 			if (card->xmit_lock[channel]) {
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index f5ae171..236291b 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -4,7 +4,7 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_PPC_PMAC)		+= macio_asic.o
+obj-$(CONFIG_PPC_PMAC)		+= macio_asic.o macio_sysfs.o
 
 obj-$(CONFIG_PMAC_MEDIABAY)	+= mediabay.o
 obj-$(CONFIG_MAC_EMUMOUSEBTN)	+= mac_hid.o
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index d0bda7e..1ee0033 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -33,7 +33,7 @@
 {
 	struct macio_dev * macio_dev = to_macio_device(dev);
 	struct macio_driver * macio_drv = to_macio_driver(drv);
-	const struct of_match * matches = macio_drv->match_table;
+	const struct of_device_id * matches = macio_drv->match_table;
 
 	if (!matches) 
 		return 0;
@@ -66,7 +66,7 @@
 	int error = -ENODEV;
 	struct macio_driver *drv;
 	struct macio_dev *macio_dev;
-	const struct of_match *match;
+	const struct of_device_id *match;
 
 	drv = to_macio_driver(dev->driver);
 	macio_dev = to_macio_device(dev);
@@ -126,11 +126,85 @@
 	return 0;
 }
 
+static int macio_hotplug (struct device *dev, char **envp, int num_envp,
+                          char *buffer, int buffer_size)
+{
+	struct macio_dev * macio_dev;
+	struct of_device * of;
+	char *scratch, *compat;
+	int i = 0;
+	int length = 0;
+	int cplen, seen = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	macio_dev = to_macio_device(dev);
+	if (!macio_dev)
+		return -ENODEV;
+
+	of = &macio_dev->ofdev;
+	scratch = buffer;
+
+	/* stuff we want to pass to /sbin/hotplug */
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length, "OF_NAME=%s",
+	                     of->node->name);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length, "OF_TYPE=%s",
+	                     of->node->type);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+        /* Since the compatible field can contain pretty much anything
+         * it's not really legal to split it out with commas. We split it
+         * up using a number of environment variables instead. */
+
+	compat = (char *) get_property(of->node, "compatible", &cplen);
+	while (compat && cplen > 0) {
+		int l;
+                envp[i++] = scratch;
+		length += scnprintf (scratch, buffer_size - length,
+		                     "OF_COMPATIBLE_%d=%s", seen, compat);
+		if ((buffer_size - length <= 0) || (i >= num_envp))
+			return -ENOMEM;
+		length++;
+		scratch += length;
+		l = strlen (compat) + 1;
+		compat += l;
+		cplen -= l;
+		seen++;
+	}
+
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length,
+	                     "OF_COMPATIBLE_N=%d", seen);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+	envp[i] = NULL;
+
+	return 0;
+}
+
+extern struct device_attribute macio_dev_attrs[];
+
 struct bus_type macio_bus_type = {
        .name	= "macio",
        .match	= macio_bus_match,
+       .hotplug = macio_hotplug,
        .suspend	= macio_device_suspend,
        .resume	= macio_device_resume,
+       .dev_attrs = macio_dev_attrs,
 };
 
 static int __init macio_bus_driver_init(void)
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
new file mode 100644
index 0000000..97d22bb
--- /dev/null
+++ b/drivers/macintosh/macio_sysfs.c
@@ -0,0 +1,50 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <asm/macio.h>
+
+
+#define macio_config_of_attr(field, format_string)			\
+static ssize_t								\
+field##_show (struct device *dev, struct device_attribute *attr,	\
+              char *buf)						\
+{									\
+	struct macio_dev *mdev = to_macio_device (dev);			\
+	return sprintf (buf, format_string, mdev->ofdev.node->field);	\
+}
+
+static ssize_t
+compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct of_device *of;
+	char *compat;
+	int cplen;
+	int length = 0;
+
+	of = &to_macio_device (dev)->ofdev;
+	compat = (char *) get_property(of->node, "compatible", &cplen);
+	if (!compat) {
+		*buf = '\0';
+		return 0;
+	}
+	while (cplen > 0) {
+		int l;
+		length += sprintf (buf, "%s\n", compat);
+		buf += length;
+		l = strlen (compat) + 1;
+		compat += l;
+		cplen -= l;
+	}
+
+	return length;
+}
+
+macio_config_of_attr (name, "%s\n");
+macio_config_of_attr (type, "%s\n");
+
+struct device_attribute macio_dev_attrs[] = {
+	__ATTR_RO(name),
+	__ATTR_RO(type),
+	__ATTR_RO(compatible),
+	__ATTR_NULL
+};
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 4be709e..7c16c25 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -642,7 +642,7 @@
 	}
 }
 
-static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_match *match)
+static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	struct media_bay_info* bay;
 	u32 __iomem *regbase;
@@ -797,23 +797,20 @@
  * Therefore we do it all by polling the media bay once each tick.
  */
 
-static struct of_match media_bay_match[] =
+static struct of_device_id media_bay_match[] =
 {
 	{
 	.name		= "media-bay",
-	.type		= OF_ANY_MATCH,
 	.compatible	= "keylargo-media-bay",
 	.data		= &keylargo_mb_ops,
 	},
 	{
 	.name		= "media-bay",
-	.type		= OF_ANY_MATCH,
 	.compatible	= "heathrow-media-bay",
 	.data		= &heathrow_mb_ops,
 	},
 	{
 	.name		= "media-bay",
-	.type		= OF_ANY_MATCH,
 	.compatible	= "ohare-media-bay",
 	.data		= &ohare_mb_ops,
 	},
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index feb4e24..703e3197 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -120,6 +120,7 @@
 #include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/of_device.h>
+#include <asm/macio.h>
 
 #include "therm_pm72.h"
 
@@ -1986,7 +1987,7 @@
 	}
 }
 
-static int fcu_of_probe(struct of_device* dev, const struct of_match *match)
+static int fcu_of_probe(struct of_device* dev, const struct of_device_id *match)
 {
 	int rc;
 
@@ -2009,12 +2010,10 @@
 	return 0;
 }
 
-static struct of_match fcu_of_match[] = 
+static struct of_device_id fcu_match[] = 
 {
 	{
-	.name 		= OF_ANY_MATCH,
 	.type		= "fcu",
-	.compatible	= OF_ANY_MATCH
 	},
 	{},
 };
@@ -2022,7 +2021,7 @@
 static struct of_platform_driver fcu_of_platform_driver = 
 {
 	.name 		= "temperature",
-	.match_table	= fcu_of_match,
+	.match_table	= fcu_match,
 	.probe		= fcu_of_probe,
 	.remove		= fcu_of_remove
 };
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 61400f0..cbb72eb 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -43,6 +43,7 @@
 #include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/of_device.h>
+#include <asm/macio.h>
 
 #define LOG_TEMP		0			/* continously log temperature */
 
@@ -450,7 +451,7 @@
 /************************************************************************/
 
 static int
-therm_of_probe( struct of_device *dev, const struct of_match *match )
+therm_of_probe( struct of_device *dev, const struct of_device_id *match )
 {
 	return i2c_add_driver( &g4fan_driver );
 }
@@ -461,9 +462,8 @@
 	return i2c_del_driver( &g4fan_driver );
 }
 
-static struct of_match therm_of_match[] = {{
+static struct of_device_id therm_of_match[] = {{
 	.name		= "fan",
-	.type		= OF_ANY_MATCH,
 	.compatible	= "adm1030"
     }, {}
 };
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 6e3cf7e..12031c9 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1060,6 +1060,7 @@
 	}
 
 	ti->private = ms;
+ 	ti->split_io = ms->rh.region_size;
 
 	r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
 	if (r) {
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 50e8b86..cd5828b 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -62,13 +62,15 @@
 int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
 {
 	unsigned long start;
+	int err;
 
 	/* wait for registers to be programmed */
 	start = jiffies;
 	while (1) {
-                if (saa7146_read(dev, MC2) & 2)
-                        break;
-		if (time_after(jiffies, start + HZ/20)) {
+		err = time_after(jiffies, start + HZ/20);
+		if (saa7146_read(dev, MC2) & 2)
+			break;
+		if (err) {
 			DEB_S(("timed out while waiting for registers getting programmed\n"));
 			return -ETIMEDOUT;
 		}
@@ -79,10 +81,11 @@
 	/* wait for transfer to complete */
 	start = jiffies;
 	while (1) {
+		err = time_after(jiffies, start + HZ/4);
 		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
 			break;
 		saa7146_read(dev, MC2);
-		if (time_after(jiffies, start + HZ/4)) {
+		if (err) {
 			DEB_S(("timed out while waiting for transfer completion\n"));
 			return -ETIMEDOUT;
 		}
@@ -512,7 +515,7 @@
 	ext->driver.remove = saa7146_remove_one;
 
 	printk("saa7146: register extension '%s'.\n",ext->name);
-	return pci_module_init(&ext->driver);
+	return pci_register_driver(&ext->driver);
 }
 
 int saa7146_unregister_extension(struct saa7146_extension* ext)
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 01387f8..3f0ec6b 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -40,6 +40,10 @@
 	depends on DVB_CORE && PCI
 source "drivers/media/dvb/bt8xx/Kconfig"
 
+comment "Supported Pluto2 Adapters"
+	depends on DVB_CORE && PCI
+source "drivers/media/dvb/pluto2/Kconfig"
+
 comment "Supported DVB Frontends"
 	depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index 3c6ff16..a7ad084 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index fafd0ab..d7417ea 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -35,17 +35,3 @@
 	help
 	  Say Y if you want to enable the module option to control debug messages
 	  of all B2C2 FlexCop drivers.
-
-config DVB_B2C2_SKYSTAR
-	tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
-	depends on DVB_CORE && PCI
-	select DVB_STV0299
-	select DVB_MT352
-	select DVB_MT312
-	select DVB_NXT2002
-	help
-	  Support for the Skystar2 PCI DVB card by Technisat, which
-	  is equipped with the FlexCopII chipset by B2C2, and
-	  for the B2C2/BBTI Air2PC-ATSC card.
-
-	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index 7703812..1a1c3bc 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -9,6 +9,4 @@
 b2c2-flexcop-usb-objs = flexcop-usb.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
-obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
-
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index 773d158..a94912a 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -108,6 +108,8 @@
 int  flexcop_device_initialize(struct flexcop_device*);
 void flexcop_device_exit(struct flexcop_device *fc);
 
+void flexcop_reset_block_300(struct flexcop_device *fc);
+
 /* from flexcop-dma.c */
 int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
 void flexcop_dma_free(struct flexcop_dma *dma);
@@ -115,7 +117,8 @@
 int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
 int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
 int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index);
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx);
+int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff);
 int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
 int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets);
 
@@ -151,6 +154,7 @@
 /* from flexcop-misc.c */
 void flexcop_determine_revision(struct flexcop_device *fc);
 void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
+void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num);
 
 /* from flexcop-hw-filter.c */
 int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
index 8d27060..cf4ed1d 100644
--- a/drivers/media/dvb/b2c2/flexcop-dma.c
+++ b/drivers/media/dvb/b2c2/flexcop-dma.c
@@ -37,22 +37,90 @@
 }
 EXPORT_SYMBOL(flexcop_dma_free);
 
-int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_config(struct flexcop_device *fc,
+		struct flexcop_dma *dma,
+		flexcop_dma_index_t dma_idx)
 {
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+	flexcop_ibi_value v0x0,v0x4,v0xc;
+	v0x0.raw = v0x4.raw = v0xc.raw = 0;
 
-	if (no & FC_DMA_1)
-		v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+	v0x0.dma_0x0.dma_address0        = dma->dma_addr0 >> 2;
+	v0xc.dma_0xc.dma_address1        = dma->dma_addr1 >> 2;
+	v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
 
-	if (no & FC_DMA_2)
-		v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+	if ((dma_idx & FC_DMA_1) == dma_idx) {
+		fc->write_ibi_reg(fc,dma1_000,v0x0);
+		fc->write_ibi_reg(fc,dma1_004,v0x4);
+		fc->write_ibi_reg(fc,dma1_00c,v0xc);
+	} else if ((dma_idx & FC_DMA_2) == dma_idx) {
+		fc->write_ibi_reg(fc,dma2_010,v0x0);
+		fc->write_ibi_reg(fc,dma2_014,v0x4);
+		fc->write_ibi_reg(fc,dma2_01c,v0xc);
+	} else {
+		err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call.");
+		return -EINVAL;
+	}
 
-	fc->write_ibi_reg(fc,ctrl_208,v);
 	return 0;
 }
-EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+EXPORT_SYMBOL(flexcop_dma_config);
 
-int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+/* start the DMA transfers, but not the DMA IRQs */
+int flexcop_dma_xfer_control(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx,
+		flexcop_dma_addr_index_t index,
+		int onoff)
+{
+	flexcop_ibi_value v0x0,v0xc;
+	flexcop_ibi_register r0x0,r0xc;
+
+	if ((dma_idx & FC_DMA_1) == dma_idx) {
+		r0x0 = dma1_000;
+		r0xc = dma1_00c;
+	} else if ((dma_idx & FC_DMA_2) == dma_idx) {
+		r0x0 = dma2_010;
+		r0xc = dma2_01c;
+	} else {
+		err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
+		return -EINVAL;
+	}
+
+	v0x0 = fc->read_ibi_reg(fc,r0x0);
+	v0xc = fc->read_ibi_reg(fc,r0xc);
+
+	deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+	deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+
+	if (index & FC_DMA_SUBADDR_0)
+		v0x0.dma_0x0.dma_0start = onoff;
+
+	if (index & FC_DMA_SUBADDR_1)
+		v0xc.dma_0xc.dma_1start = onoff;
+
+	fc->write_ibi_reg(fc,r0x0,v0x0);
+	fc->write_ibi_reg(fc,r0xc,v0xc);
+
+	deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+	deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_xfer_control);
+
+static int flexcop_dma_remap(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx,
+		int onoff)
+{
+	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__);
+	v.dma_0xc.remap_enable = onoff;
+	fc->write_ibi_reg(fc,r,v);
+	return 0;
+}
+
+int flexcop_dma_control_size_irq(struct flexcop_device *fc,
+		flexcop_dma_index_t no,
+		int onoff)
 {
 	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
 
@@ -67,75 +135,64 @@
 }
 EXPORT_SYMBOL(flexcop_dma_control_size_irq);
 
-int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
+		flexcop_dma_index_t no,
+		int onoff)
 {
 	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
 
 	if (no & FC_DMA_1)
+		v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+
+	if (no & FC_DMA_2)
+		v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+
+	fc->write_ibi_reg(fc,ctrl_208,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx,
+		u8 cycles)
+{
+	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+	flexcop_dma_remap(fc,dma_idx,0);
+
+	deb_info("%s\n",__FUNCTION__);
+	v.dma_0x4_write.dmatimer = cycles;
+	fc->write_ibi_reg(fc,r,v);
+	return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
+
+/* packet IRQ does not exist in FCII or FCIIb - according to data book and tests */
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc,
+		flexcop_dma_index_t no,
+		int onoff)
+{
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+	deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);
+	if (no & FC_DMA_1)
 		v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
 
 	if (no & FC_DMA_2)
 		v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
 
 	fc->write_ibi_reg(fc,ctrl_208,v);
+	deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);
+
 	return 0;
 }
 EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
 
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
-{
-
-	flexcop_ibi_value v0x0,v0x4,v0xc;
-	v0x0.raw = v0x4.raw = v0xc.raw = 0;
-
-	v0x0.dma_0x0.dma_address0        = dma->dma_addr0 >> 2;
-	v0xc.dma_0xc.dma_address1        = dma->dma_addr1 >> 2;
-	v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
-
-	if (index & FC_DMA_SUBADDR_0)
-		v0x0.dma_0x0.dma_0start = 1;
-
-	if (index & FC_DMA_SUBADDR_1)
-		v0xc.dma_0xc.dma_1start = 1;
-
-	if (dma_idx & FC_DMA_1) {
-		fc->write_ibi_reg(fc,dma1_000,v0x0);
-		fc->write_ibi_reg(fc,dma1_004,v0x4);
-		fc->write_ibi_reg(fc,dma1_00c,v0xc);
-	} else { /* (dma_idx & FC_DMA_2) */
-		fc->write_ibi_reg(fc,dma2_010,v0x0);
-		fc->write_ibi_reg(fc,dma2_014,v0x4);
-		fc->write_ibi_reg(fc,dma2_01c,v0xc);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_config);
-
-static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
-{
-	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
-	v.dma_0xc.remap_enable = onoff;
-	fc->write_ibi_reg(fc,r,v);
-	return 0;
-}
-
-/* 1 cycles = 1.97 msec */
-int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
-{
-	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
-
-	flexcop_dma_remap(fc,dma_idx,0);
-
-	v.dma_0x4_write.dmatimer = cycles >> 1;
-	fc->write_ibi_reg(fc,r,v);
-	return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_config_timer);
-
-int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
+int flexcop_dma_config_packet_count(struct flexcop_device *fc,
+		flexcop_dma_index_t dma_idx,
+		u8 packets)
 {
 	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
 	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
index 2baf43d..75cf237 100644
--- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c
+++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
@@ -10,6 +10,8 @@
 static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
 {
 	flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
+
+	deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off");
 }
 
 void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
@@ -151,7 +153,7 @@
 {
 	int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
 
-	fc->feedcount += onoff ? 1 : -1;
+	fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
 	if (dvbdmxfeed->index >= max_pid_filter)
 		fc->extra_feedcount += onoff ? 1 : -1;
 
@@ -178,8 +180,14 @@
 	/* if it was the first or last feed request change the stream-status */
 	if (fc->feedcount == onoff) {
 		flexcop_rcv_data_ctrl(fc,onoff);
-		if (fc->stream_control)
+		if (fc->stream_control) /* device specific stream control */
 			fc->stream_control(fc,onoff);
+
+		/* feeding stopped -> reset the flexcop filter*/
+		if (onoff == 0) {
+			flexcop_reset_block_300(fc);
+			flexcop_hw_filter_init(fc);
+		}
 	}
 
 	return 0;
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
index 2308254..3a08d38 100644
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -65,3 +65,15 @@
 			flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
 			flexcop_revision_names[fc->rev],suffix);
 }
+
+void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num)
+{
+	flexcop_ibi_value v;
+	int i;
+	for (i = 0; i < num; i++) {
+		v = fc->read_ibi_reg(fc,reg+4*i);
+		deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw);
+	}
+	deb_rdump("\n");
+}
+EXPORT_SYMBOL(flexcop_dump_reg);
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index ed717c0..2f76eb3 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -13,6 +13,10 @@
 module_param(enable_pid_filtering, int, 0444);
 MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
 
+static int irq_chk_intv;
+module_param(irq_chk_intv, int, 0644);
+MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging).");
+
 #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
 #define dprintk(level,args...) \
 	do { if ((debug & level)) printk(args); } while (0)
@@ -26,6 +30,7 @@
 #define deb_reg(args...)   dprintk(0x02,args)
 #define deb_ts(args...)    dprintk(0x04,args)
 #define deb_irq(args...)   dprintk(0x08,args)
+#define deb_chk(args...)   dprintk(0x10,args)
 
 static int debug = 0;
 module_param(debug, int, 0644);
@@ -56,6 +61,10 @@
 
 	spinlock_t irq_lock;
 
+	unsigned long last_irq;
+
+	struct work_struct irq_check_work;
+
 	struct flexcop_device *fc_dev;
 };
 
@@ -88,18 +97,55 @@
 	return 0;
 }
 
+static void flexcop_pci_irq_check_work(void *data)
+{
+	struct flexcop_pci *fc_pci = data;
+	struct flexcop_device *fc = fc_pci->fc_dev;
+
+	flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+
+	flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
+
+	if (v.sram_dest_reg_714.net_ovflow_error)
+		deb_chk("sram net_ovflow_error\n");
+	if (v.sram_dest_reg_714.media_ovflow_error)
+		deb_chk("sram media_ovflow_error\n");
+	if (v.sram_dest_reg_714.cai_ovflow_error)
+		deb_chk("sram cai_ovflow_error\n");
+	if (v.sram_dest_reg_714.cai_ovflow_error)
+		deb_chk("sram cai_ovflow_error\n");
+
+	schedule_delayed_work(&fc_pci->irq_check_work,
+			msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
+}
+
 /* When PID filtering is turned on, we use the timer IRQ, because small amounts
  * of data need to be passed to the user space instantly as well. When PID
  * filtering is turned off, we use the page-change-IRQ */
-static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct flexcop_pci *fc_pci = dev_id;
 	struct flexcop_device *fc = fc_pci->fc_dev;
-	flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c);
+	flexcop_ibi_value v;
 	irqreturn_t ret = IRQ_HANDLED;
 
 	spin_lock_irq(&fc_pci->irq_lock);
 
+	v = fc->read_ibi_reg(fc,irq_20c);
+
+   /* errors */
+	if (v.irq_20c.Data_receiver_error)
+		deb_chk("data receiver error\n");
+	if (v.irq_20c.Continuity_error_flag)
+		deb_chk("Contunuity error flag is set\n");
+	if (v.irq_20c.LLC_SNAP_FLAG_set)
+		deb_chk("LLC_SNAP_FLAG_set is set\n");
+	if (v.irq_20c.Transport_Error)
+		deb_chk("Transport error\n");
+
+	if ((fc_pci->count % 1000) == 0)
+		deb_chk("%d valid irq took place so far\n",fc_pci->count);
+
 	if (v.irq_20c.DMA1_IRQ_Status == 1) {
 		if (fc_pci->active_dma1_addr == 0)
 			flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
@@ -115,8 +161,9 @@
 			fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
 		u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
 
-		deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
-				v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
+		deb_irq("%u irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
+				jiffies_to_usecs(jiffies - fc_pci->last_irq),v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
+		fc_pci->last_irq = jiffies;
 
 		/* buffer end was reached, restarted from the beginning
 		 * pass the data from last_cur_pos to the buffer end to the demux
@@ -127,7 +174,6 @@
 					fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
 					(fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
 			fc_pci->last_dma1_cur_pos = 0;
-			fc_pci->count = 0;
 		}
 
 		if (cur_pos > fc_pci->last_dma1_cur_pos) {
@@ -139,16 +185,14 @@
 		deb_irq("\n");
 
 		fc_pci->last_dma1_cur_pos = cur_pos;
-	} else
+		fc_pci->count++;
+	} else {
+		deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw);
 		ret = IRQ_NONE;
+	}
 
 	spin_unlock_irq(&fc_pci->irq_lock);
 
-/* packet count would be ideal for hw filtering, but it isn't working. Either
- * the data book is wrong, or I'm unable to read it correctly */
-
-/*	if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */
-
 	return ret;
 }
 
@@ -156,30 +200,35 @@
 {
 	struct flexcop_pci *fc_pci = fc->bus_specific;
 	if (onoff) {
-		flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
-		flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
-		flexcop_dma_config_timer(fc,FC_DMA_1,1);
+		flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1);
+		flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2);
 
-		if (fc_pci->fc_dev->pid_filtering) {
-			fc_pci->last_dma1_cur_pos = 0;
-			flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
-		} else {
-			fc_pci->active_dma1_addr = 0;
-			flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
-		}
+		flexcop_dma_config_timer(fc,FC_DMA_1,0);
 
-/*		flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0);
-		flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */
+		flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1);
+		deb_irq("DMA xfer enabled\n");
 
-		deb_irq("irqs enabled\n");
+		fc_pci->last_dma1_cur_pos = 0;
+		flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
+		deb_irq("IRQ enabled\n");
+
+//		fc_pci->active_dma1_addr = 0;
+//		flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
+
+		if (irq_chk_intv > 0)
+			schedule_delayed_work(&fc_pci->irq_check_work,
+					msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
 	} else {
-		if (fc_pci->fc_dev->pid_filtering)
-			flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
-		else
-			flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+		if (irq_chk_intv > 0)
+			cancel_delayed_work(&fc_pci->irq_check_work);
 
-//		flexcop_dma_control_packet_irq(fc,FC_DMA_1,0);
-		deb_irq("irqs disabled\n");
+		flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
+		deb_irq("IRQ disabled\n");
+
+//		flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+
+		flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0);
+		deb_irq("DMA xfer disabled\n");
 	}
 
 	return 0;
@@ -198,6 +247,7 @@
 	flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO   | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
 
 	fc_pci->init_state |= FC_PCI_DMA_INIT;
+
 	goto success;
 dma1_free:
 	flexcop_dma_free(&fc_pci->dma[0]);
@@ -244,7 +294,7 @@
 
 	pci_set_drvdata(fc_pci->pdev, fc_pci);
 
-	if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq,
+	if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
 					SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0)
 		goto err_pci_iounmap;
 
@@ -324,6 +374,8 @@
 	if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
 		goto err_fc_exit;
 
+	INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
+
 	goto success;
 err_fc_exit:
 	flexcop_device_exit(fc);
@@ -350,17 +402,17 @@
 
 static struct pci_device_id flexcop_pci_tbl[] = {
 	{ PCI_DEVICE(0x13d0, 0x2103) },
-/*	{ PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */
+/*	{ PCI_DEVICE(0x13d0, 0x2200) }, ? */
 	{ },
 };
 
 MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
 
 static struct pci_driver flexcop_pci_driver = {
-	.name = "Technisat/B2C2 FlexCop II/IIb/III PCI",
+	.name     = "b2c2_flexcop_pci",
 	.id_table = flexcop_pci_tbl,
-	.probe = flexcop_pci_probe,
-	.remove = flexcop_pci_remove,
+	.probe    = flexcop_pci_probe,
+	.remove   = flexcop_pci_remove,
 };
 
 static int __init flexcop_pci_module_init(void)
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 75b50f2..4ae1eb5 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -36,555 +36,21 @@
 extern const char *flexcop_device_names[];
 
 /* FlexCop IBI Registers */
+#if defined(__LITTLE_ENDIAN)
+	#include "flexcop_ibi_value_le.h"
+#elif defined(__BIG_ENDIAN)
+	#include "flexcop_ibi_value_be.h"
+#else
+	#error no endian defined
+#endif
 
-/* flexcop_ibi_reg - a huge union representing the register structure */
-typedef union {
-	u32 raw;
-
-/* DMA 0x000 to 0x01c
- * DMA1 0x000 to 0x00c
- * DMA2 0x010 to 0x01c
- */
-	struct {
-		u32 dma_0start        : 1;   /* set: data will be delivered to dma1_address0 */
-        u32 dma_0No_update    : 1;   /* set: dma1_cur_address will be updated, unset: no update */
-        u32 dma_address0      :30;   /* physical/virtual host memory address0 DMA */
-	} dma_0x0;
-
-	struct {
-		u32 DMA_maxpackets    : 8;   /* (remapped) PCI DMA1 Packet Count Interrupt. This variable
-										is able to be read and written while bit(1) of register
-										0x00c (remap_enable) is set. This variable represents
-										the number of packets that will be transmitted to the PCI
-										host using PCI DMA1 before an interrupt to the PCI is
-										asserted. This functionality may be enabled using bit(20)
-										of register 0x208. N=0 disables the IRQ. */
-		u32 dma_addr_size     :24;   /* size of memory buffer in DWORDs (bytesize / 4) for DMA */
-	} dma_0x4_remap;
-
-	struct {
-		u32 dma1timer         : 7;   /* reading PCI DMA1 timer ... when remap_enable is 0 */
-		u32 unused            : 1;
-		u32 dma_addr_size     :24;
-	} dma_0x4_read;
-
-	struct {
-		u32 unused            : 1;
-		u32 dmatimer          : 7;   /* writing PCI DMA1 timer ... when remap_enable is 0 */
-		u32 dma_addr_size     :24;
-	} dma_0x4_write;
-
-	struct {
-		u32 unused            : 2;
-		u32 dma_cur_addr      :30;   /* current physical host memory address pointer for DMA */
-	} dma_0x8;
-
-	struct {
-		u32 dma_1start        : 1;   /* set: data will be delivered to dma_address1, when dma_address0 is full */
-		u32 remap_enable      : 1;   /* remap enable for 0x0x4(7:0) */
-		u32 dma_address1      :30;   /* Physical/virtual address 1 on DMA */
-	} dma_0xc;
-
-/* Two-wire Serial Master and Clock 0x100-0x110 */
-	struct {
-//		u32 slave_transmitter : 1;   /* ???*/
-		u32 chipaddr          : 7;   /* two-line serial address of the target slave */
-		u32 reserved1         : 1;
-		u32 baseaddr          : 8;   /* address of the location of the read/write operation */
-		u32 data1_reg         : 8;   /* first byte in two-line serial read/write operation */
-		u32 working_start     : 1;  /* when doing a write operation this indicator is 0 when ready
-									  * set to 1 when doing a write operation */
-		u32 twoWS_rw          : 1;   /* read/write indicator (1 = read, 0 write) */
-		u32 total_bytes       : 2;   /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/
-		u32 twoWS_port_reg    : 2;   /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */
-		u32 no_base_addr_ack_error : 1;   /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o
-									  * preceding address assignment write frame
-									  * ACK_ERROR = 1 when no ACK from slave in the last transaction */
-		u32 st_done           : 1;   /* indicator for transaction is done */
-	} tw_sm_c_100;
-
-	struct {
-		u32 data2_reg         : 8;   /* 2nd data byte */
-		u32 data3_reg         : 8;   /* 3rd data byte */
-		u32 data4_reg         : 8;   /* 4th data byte */
-		u32 exlicit_stops     : 1;   /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */
-		u32 force_stop        : 1;   /* isolated stop flag */
-		u32 unused            : 6;
-	} tw_sm_c_104;
-
-/* Clock. The register allows the FCIII to convert an incoming Master clock
- * (MCLK) signal into a lower frequency clock through the use of a LowCounter
- * (TLO) and a High- Counter (THI). The time counts for THI and TLO are
- * measured in MCLK; each count represents 4 MCLK input clock cycles.
- *
- * The default output for port #1 is set for Front End Demod communication. (0x108)
- * The default output for port #2 is set for EEPROM communication. (0x10c)
- * The default output for port #3 is set for Tuner communication. (0x110)
- */
-	struct {
-		u32 thi1              : 6;   /* Thi for port #1 (def: 100110b; 38) */
-		u32 reserved1         : 2;
-		u32 tlo1              : 5;   /* Tlo for port #1 (def: 11100b; 28) */
-		u32 reserved2         :19;
-	} tw_sm_c_108;
-
-	struct {
-		u32 thi1              : 6;   /* Thi for port #2 (def: 111001b; 57) */
-		u32 reserved1         : 2;
-		u32 tlo1              : 5;   /* Tlo for port #2 (def: 11100b; 28) */
-		u32 reserved2         :19;
-	} tw_sm_c_10c;
-
-	struct {
-		u32 thi1              : 6;   /* Thi for port #3 (def: 111001b; 57) */
-		u32 reserved1         : 2;
-		u32 tlo1              : 5;   /* Tlo for port #3 (def: 11100b; 28) */
-		u32 reserved2         :19;
-	} tw_sm_c_110;
-
-/* LNB Switch Frequency 0x200
- * Clock that creates the LNB switch tone. The default is set to have a fixed
- * low output (not oscillating) to the LNB_CTL line.
- */
-	struct {
-		u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */
-		u32 LNB_CTLLowCount_sig  :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master
-										Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */
-		u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */
-	} lnb_switch_freq_200;
-
-/* ACPI, Peripheral Reset, LNB Polarity
- * ACPI power conservation mode, LNB polarity selection (low or high voltage),
- * and peripheral reset.
- */
-	struct {
-		u32 ACPI1_sig         : 1;   /* turn of the power of tuner and LNB, not implemented in FCIII */
-		u32 ACPI3_sig         : 1;   /* turn of power of the complete satelite receiver board (except FCIII) */
-		u32 LNB_L_H_sig       : 1;   /* low or high voltage for LNB. (0 = low, 1 = high) */
-		u32 Per_reset_sig     : 1;   /* misc. init reset (default: 1), to reset set to low and back to high */
-		u32 reserved          :20;
-		u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */
-		u32 Rev_N_sig_reserved1 : 2;
-		u32 Rev_N_sig_caps    : 1;   /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */
-		u32 Rev_N_sig_reserved2 : 1;
-	} misc_204;
-
-/* Control and Status 0x208 to 0x21c */
-/* Gross enable and disable control */
-	struct {
-		u32 Stream1_filter_sig : 1;  /* Stream1 PID filtering */
-		u32 Stream2_filter_sig : 1;  /* Stream2 PID filtering */
-		u32 PCR_filter_sig    : 1;   /* PCR PID filter */
-		u32 PMT_filter_sig    : 1;   /* PMT PID filter */
-
-		u32 EMM_filter_sig    : 1;   /* EMM PID filter */
-		u32 ECM_filter_sig    : 1;   /* ECM PID filter */
-		u32 Null_filter_sig   : 1;   /* Filters null packets, PID=0x1fff. */
-		u32 Mask_filter_sig   : 1;   /* mask PID filter */
-
-		u32 WAN_Enable_sig    : 1;   /* WAN output line through V8 memory space is activated. */
-		u32 WAN_CA_Enable_sig : 1;   /* not in FCIII */
-		u32 CA_Enable_sig     : 1;   /* not in FCIII */
-		u32 SMC_Enable_sig    : 1;   /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */
-
-		u32 Per_CA_Enable_sig : 1;   /* not in FCIII */
-		u32 Multi2_Enable_sig : 1;   /* ? */
-		u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */
-		u32 Rcv_Data_sig      : 1;   /* PID filtering module enable. When this bit is a one, the PID filter will
-										examine and process packets according to all other (individual) PID
-										filtering controls. If it a zero, no packet processing of any kind will
-										take place. All data from the tuner will be thrown away. */
-
-		u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI
-									  * interrupt after the specified count for filling the buffer. */
-		u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt
-											after a specified amount of time. */
-		u32 DMA2_IRQ_Enable_sig : 1;   /* same as DMA1_IRQ_Enable_sig but for DMA2 */
-		u32 DMA2_Timer_Enable_sig : 1;   /* same as DMA1_Timer_Enable_sig but for DMA2 */
-
-		u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */
-		u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet	count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */
-		u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the
-											PCI host to indicate that mailbox data is available. */
-
-		u32 unused            : 9;
-	} ctrl_208;
-
-/* General status. When a PCI interrupt occurs, this register is read to
- * discover the reason for the interrupt.
- */
-	struct {
-		u32 DMA1_IRQ_Status   : 1;   /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */
-		u32 DMA1_Timer_Status : 1;   /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */
-		u32 DMA2_IRQ_Status   : 1;   /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */
-		u32 DMA2_Timer_Status : 1;   /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */
-		u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */
-		u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/
-		u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */
-		u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */
-		u32 Continuity_error_flag : 1;   /* 1 indicates a continuity error in the TS stream. */
-		u32 LLC_SNAP_FLAG_set : 1;   /* 1 indicates that the LCC_SNAP_FLAG was set. */
-		u32 Transport_Error   : 1;   /*  When set indicates that an unexpected packet was received. */
-		u32 reserved          :21;
-	} irq_20c;
-
-
-/* Software reset register */
-	struct {
-		u32 reset_blocks      : 8;   /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00.
-										Each bit location represents a 0x100 block of registers. Writing
-										a one in a bit location resets that block of registers and the logic
-										that it controls. */
-		u32 Block_reset_enable : 8;  /* This variable is set to 0xB2 when the register is written. */
-		u32 Special_controls  :16;   /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A;
-										Turns off pci encryption => 0xC259 Note: pci_encryption default
-										at power-up is ON. */
-	} sw_reset_210;
-
-	struct {
-		u32 vuart_oe_sig      : 1;   /* When clear, the V8 processor has sole control of the serial UART
-										(RS-232 Smart Card interface). When set, the IBI interface
-										defined by register 0x600 controls the serial UART. */
-		u32 v2WS_oe_sig       : 1;   /* When clear, the V8 processor has direct control of the Two-line
-										Serial Master EEPROM target. When set, the Two-line Serial Master
-										EEPROM target interface is controlled by IBI register 0x100. */
-		u32 halt_V8_sig       : 1;   /* When set, contiguous wait states are applied to the V8-space
-										bus masters. Once this signal is cleared, normal V8-space
-										operations resume. */
-		u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry
-										  to process section packed transport streams. */
-		u32 s2p_sel_sig       : 1;   /* Serial to parallel conversion. When set, polarized transport data
-										within the FlexCop3 front end circuitry is converted from a serial
-										stream into parallel data before downstream processing otherwise
-										interprets the data. */
-		u32 unused1           : 3;
-		u32 polarity_PS_CLK_sig: 1;  /* This signal is used to invert the input polarity of the tranport
-										stream CLOCK signal before any processing occurs on the transport
-										stream within FlexCop3. */
-		u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport
-										stream VALID signal before any processing occurs on the transport
-										stream within FlexCop3. */
-		u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport
-										stream SYNC signal before any processing occurs on the transport
-										stream within FlexCop3. */
-		u32 polarity_PS_ERR_sig: 1;  /* This signal is used to invert the input polarity of the tranport
-										stream ERROR signal before any processing occurs on the transport
-										stream within FlexCop3. */
-		u32 unused2           :20;
-	} misc_214;
-
-/* Mailbox from V8 to host */
-	struct {
-		u32 Mailbox_from_V8   :32;   /* When this register is written by either the V8 processor or by an
-										end host, an interrupt is generated to the PCI host to indicate
-										that mailbox data is available. Reading register 20c will clear
-										the IRQ. */
-	} mbox_v8_to_host_218;
-
-/* Mailbox from host to v8 Mailbox_to_V8
- * Mailbox_to_V8 mailbox storage register
- * used to send messages from PCI to V8. Writing to this register will send an
- * IRQ to the V8. Then it can read the data from here. Reading this register
- * will clear the IRQ. If the V8 is halted and bit 31 of this register is set,
- * then this register is used instead as a direct interface to access the
- * V8space memory.
- */
-	struct {
-		u32 sysramaccess_data : 8;   /* Data byte written or read from the specified address in V8 SysRAM. */
-		u32 sysramaccess_addr :15;   /* 15 bit address used to access V8 Sys-RAM. */
-		u32 unused            : 7;
-		u32 sysramaccess_write: 1;   /* Write flag used to latch data into the V8 SysRAM. */
-		u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows
-										  this IBI register interface to directly drive the V8-space memory. */
-	} mbox_host_to_v8_21c;
-
-
-/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */
-	struct {
-		u32 Stream1_PID       :13;   /* Primary use is receiving Net data, so these 13 bits normally
-										hold the PID value for the desired network stream. */
-		u32 Stream1_trans     : 1;   /* When set, Net translation will take place for Net data ferried in TS packets. */
-		u32 MAC_Multicast_filter : 1;   /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */
-		u32 debug_flag_pid_saved : 1;
-		u32 Stream2_PID       :13;   /* 13 bits for Stream 2 PID filter value. General use. */
-		u32 Stream2_trans     : 1;   /* When set Tables/CAI translation will take place for the data ferried in
-										Stream2_PID TS packets. */
-		u32 debug_flag_write_status00 : 1;
-		u32 debug_fifo_problem : 1;
-	} pid_filter_300;
-
-	struct {
-		u32 PCR_PID           :13;   /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */
-		u32 PCR_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
-		u32 debug_overrun3    : 1;
-		u32 debug_overrun2    : 1;
-		u32 PMT_PID           :13;   /* stream PID filter value. Primary use is Program Management Table segment filtering. */
-		u32 PMT_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
-		u32 reserved          : 2;
-	} pid_filter_304;
-
-	struct {
-		u32 EMM_PID           :13;   /* EMM PID filter value. Primary use is Entitlement Management Messaging for
-										conditional access-related data. */
-		u32 EMM_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
-		u32 EMM_filter_4      : 1;   /* When set will pass only EMM data possessing the same ID code as the
-										first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */
-		u32 EMM_filter_6      : 1;   /* When set will pass only EMM data possessing the same 6-byte code as the end-users
-										complete 6-byte Smart Card ID number. */
-		u32 ECM_PID           :13;   /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional
-										access-related data. */
-		u32 ECM_trans         : 1;   /* When set, Tables/CAI translation will take place for these packets. */
-		u32 reserved          : 2;
-	} pid_filter_308;
-
-	struct {
-		u32 Group_PID     :13;   /* PID value for group filtering. */
-		u32 Group_trans   : 1;   /* When set, Tables/CAI translation will take place for these packets. */
-		u32 unused1       : 2;
-		u32 Group_mask    :13;   /* Mask value used in logical "and" equation that defines group filtering */
-		u32 unused2       : 3;
-	} pid_filter_30c_ext_ind_0_7;
-
-	struct {
-		u32 net_master_read :17;
-		u32 unused        :15;
-	} pid_filter_30c_ext_ind_1;
-
-	struct {
-		u32 net_master_write :17;
-		u32 unused        :15;
-	} pid_filter_30c_ext_ind_2;
-
-	struct {
-		u32 next_net_master_write :17;
-		u32 unused        :15;
-	} pid_filter_30c_ext_ind_3;
-
-	struct {
-		u32 unused1       : 1;
-		u32 state_write   :10;
-		u32 reserved1     : 6;   /* default: 000100 */
-		u32 stack_read    :10;
-		u32 reserved2     : 5;   /* default: 00100 */
-	} pid_filter_30c_ext_ind_4;
-
-	struct {
-		u32 stack_cnt     :10;
-		u32 unused        :22;
-	} pid_filter_30c_ext_ind_5;
-
-	struct {
-		u32 pid_fsm_save_reg0 : 2;
-		u32 pid_fsm_save_reg1 : 2;
-		u32 pid_fsm_save_reg2 : 2;
-		u32 pid_fsm_save_reg3 : 2;
-		u32 pid_fsm_save_reg4 : 2;
-		u32 pid_fsm_save_reg300 : 2;
-		u32 write_status1 : 2;
-		u32 write_status4 : 2;
-		u32 data_size_reg :12;
-		u32 unused        : 4;
-	} pid_filter_30c_ext_ind_6;
-
-	struct {
-		u32 index_reg         : 5;   /* (Index pointer) Points at an internal PIDn register. A binary code
-										representing one of 32 internal PIDn registers as well as its
-										corresponding internal MAC_lown register. */
-		u32 extra_index_reg   : 3;   /* This vector is used to select between sets of debug signals routed to register 0x30c. */
-		u32 AB_select         : 1;   /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register
-										0=MAC_highB register, 1=MAC_highA */
-		u32 pass_alltables    : 1;   /* 1=Net packets are not filtered against the Network Table ID found in register 0x400.
-										All types of networks (DVB, ATSC, ISDB) are passed. */
-		u32 unused            :22;
-	} index_reg_310;
-
-	struct {
-		u32 PID               :13;   /* PID value */
-		u32 PID_trans         : 1;   /* translation will take place for packets filtered */
-		u32 PID_enable_bit    : 1;   /* When set this PID filter is enabled */
-		u32 reserved          :17;
-	} pid_n_reg_314;
-
-	struct {
-		u32 A4_byte           : 8;
-		u32 A5_byte           : 8;
-		u32 A6_byte           : 8;
-		u32 Enable_bit        : 1;   /* enabled (1) or disabled (1) */
-		u32 HighAB_bit        : 1;   /* use MAC_highA (1) or MAC_highB (0) as MSB */
-		u32 reserved          : 6;
-	} mac_low_reg_318;
-
-	struct {
-		u32 A1_byte           : 8;
-		u32 A2_byte           : 8;
-		u32 A3_byte           : 8;
-		u32 reserved          : 8;
-	} mac_high_reg_31c;
-
-/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */
-	struct {
-		u32 reserved          :16;
 #define fc_data_Tag_ID_DVB  0x3e
 #define fc_data_Tag_ID_ATSC 0x3f
 #define fc_data_Tag_ID_IDSB 0x8b
-		u32 data_Tag_ID       :16;
-	} data_tag_400;
 
-	struct {
-		u32 Card_IDbyte6      : 8;
-		u32 Card_IDbyte5      : 8;
-		u32 Card_IDbyte4      : 8;
-		u32 Card_IDbyte3      : 8;
-	} card_id_408;
-
-	struct {
-		u32 Card_IDbyte2      : 8;
-		u32 Card_IDbyte1      : 8;
-	} card_id_40c;
-
-	/* holding the unique mac address of the receiver which houses the FlexCopIII */
-	struct {
-		u32 MAC1              : 8;
-		u32 MAC2              : 8;
-		u32 MAC3              : 8;
-		u32 MAC6              : 8;
-	} mac_address_418;
-
-	struct {
-		u32 MAC7              : 8;
-		u32 MAC8              : 8;
-		u32 reserved          : 16;
-	} mac_address_41c;
-
-	struct {
-		u32 transmitter_data_byte : 8;
-		u32 ReceiveDataReady  : 1;
-		u32 ReceiveByteFrameError: 1;
-		u32 txbuffempty       : 1;
-		u32 reserved          :21;
-	} ci_600;
-
-	struct {
-		u32 pi_d              : 8;
-		u32 pi_ha             :20;
-		u32 pi_rw             : 1;
-		u32 pi_component_reg  : 3;
-	} pi_604;
-
-	struct {
-		u32 serialReset       : 1;
-		u32 oncecycle_read    : 1;
-		u32 Timer_Read_req    : 1;
-		u32 Timer_Load_req    : 1;
-		u32 timer_data        : 7;
-		u32 unused            : 1; /* ??? not mentioned in data book */
-		u32 Timer_addr        : 5;
-		u32 reserved          : 3;
-		u32 pcmcia_a_mod_pwr_n : 1;
-		u32 pcmcia_b_mod_pwr_n : 1;
-		u32 config_Done_stat  : 1;
-		u32 config_Init_stat  : 1;
-		u32 config_Prog_n     : 1;
-		u32 config_wr_n       : 1;
-		u32 config_cs_n       : 1;
-		u32 config_cclk       : 1;
-		u32 pi_CiMax_IRQ_n    : 1;
-		u32 pi_timeout_status : 1;
-		u32 pi_wait_n         : 1;
-		u32 pi_busy_n         : 1;
-	} pi_608;
-
-	struct {
-		u32 PID               :13;
-		u32 key_enable        : 1;
 #define fc_key_code_default 0x1
 #define fc_key_code_even    0x2
 #define fc_key_code_odd     0x3
-		u32 key_code          : 2;
-		u32 key_array_col     : 3;
-		u32 key_array_row     : 5;
-		u32 dvb_en            : 1; /* 0=TS bypasses the Descrambler */
-		u32 rw_flag           : 1;
-		u32 reserved          : 6;
-	} dvb_reg_60c;
-
-/* SRAM and Output Destination 0x700 to 0x714 */
-	struct {
-		u32 sram_addr         :15;
-		u32 sram_rw           : 1;   /* 0=write, 1=read */
-		u32 sram_data         : 8;
-		u32 sc_xfer_bit       : 1;
-		u32 reserved1         : 3;
-		u32 oe_pin_reg        : 1;
-		u32 ce_pin_reg        : 1;
-		u32 reserved2         : 1;
-		u32 start_sram_ibi    : 1;
-	} sram_ctrl_reg_700;
-
-	struct {
-		u32 net_addr_read     :16;
-		u32 net_addr_write    :16;
-	} net_buf_reg_704;
-
-	struct {
-		u32 cai_read          :11;
-		u32 reserved1         : 5;
-		u32 cai_write         :11;
-		u32 reserved2         : 6;
-		u32 cai_cnt           : 4;
-	} cai_buf_reg_708;
-
-	struct {
-		u32 cao_read          :11;
-		u32 reserved1         : 5;
-		u32 cap_write         :11;
-		u32 reserved2         : 6;
-		u32 cao_cnt           : 4;
-	} cao_buf_reg_70c;
-
-	struct {
-		u32 media_read        :11;
-		u32 reserved1         : 5;
-		u32 media_write       :11;
-		u32 reserved2         : 6;
-		u32 media_cnt         : 4;
-	} media_buf_reg_710;
-
-	struct {
-		u32 NET_Dest          : 2;
-		u32 CAI_Dest          : 2;
-		u32 CAO_Dest          : 2;
-		u32 MEDIA_Dest        : 2;
-		u32 net_ovflow_error  : 1;
-		u32 media_ovflow_error : 1;
-		u32 cai_ovflow_error  : 1;
-		u32 cao_ovflow_error  : 1;
-		u32 ctrl_usb_wan      : 1;
-		u32 ctrl_sramdma      : 1;
-		u32 ctrl_maximumfill  : 1;
-		u32 reserved          :17;
-	} sram_dest_reg_714;
-
-	struct {
-		u32 net_cnt           :12;
-		u32 reserved1         : 4;
-		u32 net_addr_read     : 1;
-		u32 reserved2         : 3;
-		u32 net_addr_write    : 1;
-		u32 reserved3         :11;
-	} net_buf_reg_718;
-
-	struct {
-		u32 wan_speed_sig     : 2;
-		u32 reserved1         : 6;
-		u32 wan_wait_state    : 8;
-		u32 sram_chip         : 2;
-		u32 sram_memmap       : 2;
-		u32 reserved2         : 4;
-		u32 wan_pkt_frame     : 4;
-		u32 reserved3         : 4;
-	} wan_ctrl_reg_71c;
-} flexcop_ibi_value;
 
 extern flexcop_ibi_value ibi_zero;
 
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 0113449..0a78ba3 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -545,7 +545,7 @@
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver flexcop_usb_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "Technisat/B2C2 FlexCop II/IIb/III USB",
+	.name		= "b2c2_flexcop_usb",
 	.probe		= flexcop_usb_probe,
 	.disconnect = flexcop_usb_disconnect,
 	.id_table	= flexcop_usb_table,
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 8b5d14d..12873d4 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -46,7 +46,7 @@
 
 int b2c2_flexcop_debug;
 module_param_named(debug, b2c2_flexcop_debug,  int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS);
 #undef DEBSTATUS
 
 /* global zero for ibi values */
@@ -173,9 +173,20 @@
 	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
 
 	v210.raw = 0;
-	v210.sw_reset_210.reset_blocks = 0xff;
+	v210.sw_reset_210.reset_block_000 = 1;
+	v210.sw_reset_210.reset_block_100 = 1;
+	v210.sw_reset_210.reset_block_200 = 1;
+	v210.sw_reset_210.reset_block_300 = 1;
+	v210.sw_reset_210.reset_block_400 = 1;
+	v210.sw_reset_210.reset_block_500 = 1;
+	v210.sw_reset_210.reset_block_600 = 1;
+	v210.sw_reset_210.reset_block_700 = 1;
 	v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+	v210.sw_reset_210.Special_controls = 0xc259;
+
 	fc->write_ibi_reg(fc,sw_reset_210,v210);
+	msleep(1);
 
 /* reset the periphical devices */
 
@@ -186,6 +197,25 @@
 	fc->write_ibi_reg(fc,misc_204,v204);
 }
 
+void flexcop_reset_block_300(struct flexcop_device *fc)
+{
+	flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208),
+					  v210 = fc->read_ibi_reg(fc,sw_reset_210);
+
+	deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw);
+
+	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+	v210.sw_reset_210.reset_block_300 = 1;
+	v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+	fc->write_ibi_reg(fc,sw_reset_210,v210);
+	msleep(1);
+
+	fc->write_ibi_reg(fc,ctrl_208,v208_save);
+}
+EXPORT_SYMBOL(flexcop_reset_block_300);
+
 struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
 {
 	void *bus;
diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h
index caa343a..0cebe1d 100644
--- a/drivers/media/dvb/b2c2/flexcop.h
+++ b/drivers/media/dvb/b2c2/flexcop.h
@@ -26,5 +26,6 @@
 #define deb_i2c(args...)   dprintk(0x04,args)
 #define deb_ts(args...)    dprintk(0x08,args)
 #define deb_sram(args...)  dprintk(0x10,args)
+#define deb_rdump(args...)  dprintk(0x20,args)
 
 #endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
new file mode 100644
index 0000000..ed9a675
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
@@ -0,0 +1,458 @@
+/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * register descriptions
+ *
+ * see flexcop.c for copyright information.
+ */
+
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+	u32 raw;
+
+	struct {
+		u32 dma_address0                   :30;
+		u32 dma_0No_update                 : 1;
+		u32 dma_0start                     : 1;
+	} dma_0x0;
+
+	struct {
+		u32 dma_addr_size                  :24;
+		u32 DMA_maxpackets                 : 8;
+	} dma_0x4_remap;
+
+	struct {
+		u32 dma_addr_size                  :24;
+		u32 unused                         : 1;
+		u32 dma1timer                      : 7;
+	} dma_0x4_read;
+
+	struct {
+		u32 dma_addr_size                  :24;
+		u32 dmatimer                       : 7;
+		u32 unused                         : 1;
+	} dma_0x4_write;
+
+	struct {
+		u32 dma_cur_addr                   :30;
+		u32 unused                         : 2;
+	} dma_0x8;
+
+	struct {
+		u32 dma_address1                   :30;
+		u32 remap_enable                   : 1;
+		u32 dma_1start                     : 1;
+	} dma_0xc;
+
+	struct {
+		u32 st_done                        : 1;
+		u32 no_base_addr_ack_error         : 1;
+		u32 twoWS_port_reg                 : 2;
+		u32 total_bytes                    : 2;
+		u32 twoWS_rw                       : 1;
+		u32 working_start                  : 1;
+		u32 data1_reg                      : 8;
+		u32 baseaddr                       : 8;
+		u32 reserved1                      : 1;
+		u32 chipaddr                       : 7;
+	} tw_sm_c_100;
+
+	struct {
+		u32 unused                         : 6;
+		u32 force_stop                     : 1;
+		u32 exlicit_stops                  : 1;
+		u32 data4_reg                      : 8;
+		u32 data3_reg                      : 8;
+		u32 data2_reg                      : 8;
+	} tw_sm_c_104;
+
+	struct {
+		u32 reserved2                      :19;
+		u32 tlo1                           : 5;
+		u32 reserved1                      : 2;
+		u32 thi1                           : 6;
+	} tw_sm_c_108;
+
+	struct {
+		u32 reserved2                      :19;
+		u32 tlo1                           : 5;
+		u32 reserved1                      : 2;
+		u32 thi1                           : 6;
+	} tw_sm_c_10c;
+
+	struct {
+		u32 reserved2                      :19;
+		u32 tlo1                           : 5;
+		u32 reserved1                      : 2;
+		u32 thi1                           : 6;
+	} tw_sm_c_110;
+
+	struct {
+		u32 LNB_CTLPrescaler_sig           : 2;
+		u32 LNB_CTLLowCount_sig            :15;
+		u32 LNB_CTLHighCount_sig           :15;
+	} lnb_switch_freq_200;
+
+	struct {
+		u32 Rev_N_sig_reserved2            : 1;
+		u32 Rev_N_sig_caps                 : 1;
+		u32 Rev_N_sig_reserved1            : 2;
+		u32 Rev_N_sig_revision_hi          : 4;
+		u32 reserved                       :20;
+		u32 Per_reset_sig                  : 1;
+		u32 LNB_L_H_sig                    : 1;
+		u32 ACPI3_sig                      : 1;
+		u32 ACPI1_sig                      : 1;
+	} misc_204;
+
+	struct {
+		u32 unused                         : 9;
+		u32 Mailbox_from_V8_Enable_sig     : 1;
+		u32 DMA2_Size_IRQ_Enable_sig       : 1;
+		u32 DMA1_Size_IRQ_Enable_sig       : 1;
+		u32 DMA2_Timer_Enable_sig          : 1;
+		u32 DMA2_IRQ_Enable_sig            : 1;
+		u32 DMA1_Timer_Enable_sig          : 1;
+		u32 DMA1_IRQ_Enable_sig            : 1;
+		u32 Rcv_Data_sig                   : 1;
+		u32 MAC_filter_Mode_sig            : 1;
+		u32 Multi2_Enable_sig              : 1;
+		u32 Per_CA_Enable_sig              : 1;
+		u32 SMC_Enable_sig                 : 1;
+		u32 CA_Enable_sig                  : 1;
+		u32 WAN_CA_Enable_sig              : 1;
+		u32 WAN_Enable_sig                 : 1;
+		u32 Mask_filter_sig                : 1;
+		u32 Null_filter_sig                : 1;
+		u32 ECM_filter_sig                 : 1;
+		u32 EMM_filter_sig                 : 1;
+		u32 PMT_filter_sig                 : 1;
+		u32 PCR_filter_sig                 : 1;
+		u32 Stream2_filter_sig             : 1;
+		u32 Stream1_filter_sig             : 1;
+	} ctrl_208;
+
+	struct {
+		u32 reserved                       :21;
+		u32 Transport_Error                : 1;
+		u32 LLC_SNAP_FLAG_set              : 1;
+		u32 Continuity_error_flag          : 1;
+		u32 Data_receiver_error            : 1;
+		u32 Mailbox_from_V8_Status_sig     : 1;
+		u32 DMA2_Size_IRQ_Status           : 1;
+		u32 DMA1_Size_IRQ_Status           : 1;
+		u32 DMA2_Timer_Status              : 1;
+		u32 DMA2_IRQ_Status                : 1;
+		u32 DMA1_Timer_Status              : 1;
+		u32 DMA1_IRQ_Status                : 1;
+	} irq_20c;
+
+	struct {
+		u32 Special_controls               :16;
+		u32 Block_reset_enable             : 8;
+		u32 reset_block_700                : 1;
+		u32 reset_block_600                : 1;
+		u32 reset_block_500                : 1;
+		u32 reset_block_400                : 1;
+		u32 reset_block_300                : 1;
+		u32 reset_block_200                : 1;
+		u32 reset_block_100                : 1;
+		u32 reset_block_000                : 1;
+	} sw_reset_210;
+
+	struct {
+		u32 unused2                        :20;
+		u32 polarity_PS_ERR_sig            : 1;
+		u32 polarity_PS_SYNC_sig           : 1;
+		u32 polarity_PS_VALID_sig          : 1;
+		u32 polarity_PS_CLK_sig            : 1;
+		u32 unused1                        : 3;
+		u32 s2p_sel_sig                    : 1;
+		u32 section_pkg_enable_sig         : 1;
+		u32 halt_V8_sig                    : 1;
+		u32 v2WS_oe_sig                    : 1;
+		u32 vuart_oe_sig                   : 1;
+	} misc_214;
+
+	struct {
+		u32 Mailbox_from_V8                :32;
+	} mbox_v8_to_host_218;
+
+	struct {
+		u32 sysramaccess_busmuster         : 1;
+		u32 sysramaccess_write             : 1;
+		u32 unused                         : 7;
+		u32 sysramaccess_addr              :15;
+		u32 sysramaccess_data              : 8;
+	} mbox_host_to_v8_21c;
+
+	struct {
+		u32 debug_fifo_problem             : 1;
+		u32 debug_flag_write_status00      : 1;
+		u32 Stream2_trans                  : 1;
+		u32 Stream2_PID                    :13;
+		u32 debug_flag_pid_saved           : 1;
+		u32 MAC_Multicast_filter           : 1;
+		u32 Stream1_trans                  : 1;
+		u32 Stream1_PID                    :13;
+	} pid_filter_300;
+
+	struct {
+		u32 reserved                       : 2;
+		u32 PMT_trans                      : 1;
+		u32 PMT_PID                        :13;
+		u32 debug_overrun2                 : 1;
+		u32 debug_overrun3                 : 1;
+		u32 PCR_trans                      : 1;
+		u32 PCR_PID                        :13;
+	} pid_filter_304;
+
+	struct {
+		u32 reserved                       : 2;
+		u32 ECM_trans                      : 1;
+		u32 ECM_PID                        :13;
+		u32 EMM_filter_6                   : 1;
+		u32 EMM_filter_4                   : 1;
+		u32 EMM_trans                      : 1;
+		u32 EMM_PID                        :13;
+	} pid_filter_308;
+
+	struct {
+		u32 unused2                        : 3;
+		u32 Group_mask                     :13;
+		u32 unused1                        : 2;
+		u32 Group_trans                    : 1;
+		u32 Group_PID                      :13;
+	} pid_filter_30c_ext_ind_0_7;
+
+	struct {
+		u32 unused                         :15;
+		u32 net_master_read                :17;
+	} pid_filter_30c_ext_ind_1;
+
+	struct {
+		u32 unused                         :15;
+		u32 net_master_write               :17;
+	} pid_filter_30c_ext_ind_2;
+
+	struct {
+		u32 unused                         :15;
+		u32 next_net_master_write          :17;
+	} pid_filter_30c_ext_ind_3;
+
+	struct {
+		u32 reserved2                      : 5;
+		u32 stack_read                     :10;
+		u32 reserved1                      : 6;
+		u32 state_write                    :10;
+		u32 unused1                        : 1;
+	} pid_filter_30c_ext_ind_4;
+
+	struct {
+		u32 unused                         :22;
+		u32 stack_cnt                      :10;
+	} pid_filter_30c_ext_ind_5;
+
+	struct {
+		u32 unused                         : 4;
+		u32 data_size_reg                  :12;
+		u32 write_status4                  : 2;
+		u32 write_status1                  : 2;
+		u32 pid_fsm_save_reg300            : 2;
+		u32 pid_fsm_save_reg4              : 2;
+		u32 pid_fsm_save_reg3              : 2;
+		u32 pid_fsm_save_reg2              : 2;
+		u32 pid_fsm_save_reg1              : 2;
+		u32 pid_fsm_save_reg0              : 2;
+	} pid_filter_30c_ext_ind_6;
+
+	struct {
+		u32 unused                         :22;
+		u32 pass_alltables                 : 1;
+		u32 AB_select                      : 1;
+		u32 extra_index_reg                : 3;
+		u32 index_reg                      : 5;
+	} index_reg_310;
+
+	struct {
+		u32 reserved                       :17;
+		u32 PID_enable_bit                 : 1;
+		u32 PID_trans                      : 1;
+		u32 PID                            :13;
+	} pid_n_reg_314;
+
+	struct {
+		u32 reserved                       : 6;
+		u32 HighAB_bit                     : 1;
+		u32 Enable_bit                     : 1;
+		u32 A6_byte                        : 8;
+		u32 A5_byte                        : 8;
+		u32 A4_byte                        : 8;
+	} mac_low_reg_318;
+
+	struct {
+		u32 reserved                       : 8;
+		u32 A3_byte                        : 8;
+		u32 A2_byte                        : 8;
+		u32 A1_byte                        : 8;
+	} mac_high_reg_31c;
+
+	struct {
+		u32 data_Tag_ID                    :16;
+		u32 reserved                       :16;
+	} data_tag_400;
+
+	struct {
+		u32 Card_IDbyte3                   : 8;
+		u32 Card_IDbyte4                   : 8;
+		u32 Card_IDbyte5                   : 8;
+		u32 Card_IDbyte6                   : 8;
+	} card_id_408;
+
+	struct {
+		u32 Card_IDbyte1                   : 8;
+		u32 Card_IDbyte2                   : 8;
+	} card_id_40c;
+
+	struct {
+		u32 MAC6                           : 8;
+		u32 MAC3                           : 8;
+		u32 MAC2                           : 8;
+		u32 MAC1                           : 8;
+	} mac_address_418;
+
+	struct {
+		u32 reserved                       :16;
+		u32 MAC8                           : 8;
+		u32 MAC7                           : 8;
+	} mac_address_41c;
+
+	struct {
+		u32 reserved                       :21;
+		u32 txbuffempty                    : 1;
+		u32 ReceiveByteFrameError          : 1;
+		u32 ReceiveDataReady               : 1;
+		u32 transmitter_data_byte          : 8;
+	} ci_600;
+
+	struct {
+		u32 pi_component_reg               : 3;
+		u32 pi_rw                          : 1;
+		u32 pi_ha                          :20;
+		u32 pi_d                           : 8;
+	} pi_604;
+
+	struct {
+		u32 pi_busy_n                      : 1;
+		u32 pi_wait_n                      : 1;
+		u32 pi_timeout_status              : 1;
+		u32 pi_CiMax_IRQ_n                 : 1;
+		u32 config_cclk                    : 1;
+		u32 config_cs_n                    : 1;
+		u32 config_wr_n                    : 1;
+		u32 config_Prog_n                  : 1;
+		u32 config_Init_stat               : 1;
+		u32 config_Done_stat               : 1;
+		u32 pcmcia_b_mod_pwr_n             : 1;
+		u32 pcmcia_a_mod_pwr_n             : 1;
+		u32 reserved                       : 3;
+		u32 Timer_addr                     : 5;
+		u32 unused                         : 1;
+		u32 timer_data                     : 7;
+		u32 Timer_Load_req                 : 1;
+		u32 Timer_Read_req                 : 1;
+		u32 oncecycle_read                 : 1;
+		u32 serialReset                    : 1;
+	} pi_608;
+
+	struct {
+		u32 reserved                       : 6;
+		u32 rw_flag                        : 1;
+		u32 dvb_en                         : 1;
+		u32 key_array_row                  : 5;
+		u32 key_array_col                  : 3;
+		u32 key_code                       : 2;
+		u32 key_enable                     : 1;
+		u32 PID                            :13;
+	} dvb_reg_60c;
+
+	struct {
+		u32 start_sram_ibi                 : 1;
+		u32 reserved2                      : 1;
+		u32 ce_pin_reg                     : 1;
+		u32 oe_pin_reg                     : 1;
+		u32 reserved1                      : 3;
+		u32 sc_xfer_bit                    : 1;
+		u32 sram_data                      : 8;
+		u32 sram_rw                        : 1;
+		u32 sram_addr                      :15;
+	} sram_ctrl_reg_700;
+
+	struct {
+		u32 net_addr_write                 :16;
+		u32 net_addr_read                  :16;
+	} net_buf_reg_704;
+
+	struct {
+		u32 cai_cnt                        : 4;
+		u32 reserved2                      : 6;
+		u32 cai_write                      :11;
+		u32 reserved1                      : 5;
+		u32 cai_read                       :11;
+	} cai_buf_reg_708;
+
+	struct {
+		u32 cao_cnt                        : 4;
+		u32 reserved2                      : 6;
+		u32 cap_write                      :11;
+		u32 reserved1                      : 5;
+		u32 cao_read                       :11;
+	} cao_buf_reg_70c;
+
+	struct {
+		u32 media_cnt                      : 4;
+		u32 reserved2                      : 6;
+		u32 media_write                    :11;
+		u32 reserved1                      : 5;
+		u32 media_read                     :11;
+	} media_buf_reg_710;
+
+	struct {
+		u32 reserved                       :17;
+		u32 ctrl_maximumfill               : 1;
+		u32 ctrl_sramdma                   : 1;
+		u32 ctrl_usb_wan                   : 1;
+		u32 cao_ovflow_error               : 1;
+		u32 cai_ovflow_error               : 1;
+		u32 media_ovflow_error             : 1;
+		u32 net_ovflow_error               : 1;
+		u32 MEDIA_Dest                     : 2;
+		u32 CAO_Dest                       : 2;
+		u32 CAI_Dest                       : 2;
+		u32 NET_Dest                       : 2;
+	} sram_dest_reg_714;
+
+	struct {
+		u32 reserved3                      :11;
+		u32 net_addr_write                 : 1;
+		u32 reserved2                      : 3;
+		u32 net_addr_read                  : 1;
+		u32 reserved1                      : 4;
+		u32 net_cnt                        :12;
+	} net_buf_reg_718;
+
+	struct {
+		u32 reserved3                      : 4;
+		u32 wan_pkt_frame                  : 4;
+		u32 reserved2                      : 4;
+		u32 sram_memmap                    : 2;
+		u32 sram_chip                      : 2;
+		u32 wan_wait_state                 : 8;
+		u32 reserved1                      : 6;
+		u32 wan_speed_sig                  : 2;
+	} wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
new file mode 100644
index 0000000..49f2315
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
@@ -0,0 +1,458 @@
+/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * register descriptions
+ *
+ * see flexcop.c for copyright information.
+ */
+
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+	u32 raw;
+
+	struct {
+		u32 dma_0start                     : 1;
+		u32 dma_0No_update                 : 1;
+		u32 dma_address0                   :30;
+	} dma_0x0;
+
+	struct {
+		u32 DMA_maxpackets                 : 8;
+		u32 dma_addr_size                  :24;
+	} dma_0x4_remap;
+
+	struct {
+		u32 dma1timer                      : 7;
+		u32 unused                         : 1;
+		u32 dma_addr_size                  :24;
+	} dma_0x4_read;
+
+	struct {
+		u32 unused                         : 1;
+		u32 dmatimer                       : 7;
+		u32 dma_addr_size                  :24;
+	} dma_0x4_write;
+
+	struct {
+		u32 unused                         : 2;
+		u32 dma_cur_addr                   :30;
+	} dma_0x8;
+
+	struct {
+		u32 dma_1start                     : 1;
+		u32 remap_enable                   : 1;
+		u32 dma_address1                   :30;
+	} dma_0xc;
+
+	struct {
+		u32 chipaddr                       : 7;
+		u32 reserved1                      : 1;
+		u32 baseaddr                       : 8;
+		u32 data1_reg                      : 8;
+		u32 working_start                  : 1;
+		u32 twoWS_rw                       : 1;
+		u32 total_bytes                    : 2;
+		u32 twoWS_port_reg                 : 2;
+		u32 no_base_addr_ack_error         : 1;
+		u32 st_done                        : 1;
+	} tw_sm_c_100;
+
+	struct {
+		u32 data2_reg                      : 8;
+		u32 data3_reg                      : 8;
+		u32 data4_reg                      : 8;
+		u32 exlicit_stops                  : 1;
+		u32 force_stop                     : 1;
+		u32 unused                         : 6;
+	} tw_sm_c_104;
+
+	struct {
+		u32 thi1                           : 6;
+		u32 reserved1                      : 2;
+		u32 tlo1                           : 5;
+		u32 reserved2                      :19;
+	} tw_sm_c_108;
+
+	struct {
+		u32 thi1                           : 6;
+		u32 reserved1                      : 2;
+		u32 tlo1                           : 5;
+		u32 reserved2                      :19;
+	} tw_sm_c_10c;
+
+	struct {
+		u32 thi1                           : 6;
+		u32 reserved1                      : 2;
+		u32 tlo1                           : 5;
+		u32 reserved2                      :19;
+	} tw_sm_c_110;
+
+	struct {
+		u32 LNB_CTLHighCount_sig           :15;
+		u32 LNB_CTLLowCount_sig            :15;
+		u32 LNB_CTLPrescaler_sig           : 2;
+	} lnb_switch_freq_200;
+
+	struct {
+		u32 ACPI1_sig                      : 1;
+		u32 ACPI3_sig                      : 1;
+		u32 LNB_L_H_sig                    : 1;
+		u32 Per_reset_sig                  : 1;
+		u32 reserved                       :20;
+		u32 Rev_N_sig_revision_hi          : 4;
+		u32 Rev_N_sig_reserved1            : 2;
+		u32 Rev_N_sig_caps                 : 1;
+		u32 Rev_N_sig_reserved2            : 1;
+	} misc_204;
+
+	struct {
+		u32 Stream1_filter_sig             : 1;
+		u32 Stream2_filter_sig             : 1;
+		u32 PCR_filter_sig                 : 1;
+		u32 PMT_filter_sig                 : 1;
+		u32 EMM_filter_sig                 : 1;
+		u32 ECM_filter_sig                 : 1;
+		u32 Null_filter_sig                : 1;
+		u32 Mask_filter_sig                : 1;
+		u32 WAN_Enable_sig                 : 1;
+		u32 WAN_CA_Enable_sig              : 1;
+		u32 CA_Enable_sig                  : 1;
+		u32 SMC_Enable_sig                 : 1;
+		u32 Per_CA_Enable_sig              : 1;
+		u32 Multi2_Enable_sig              : 1;
+		u32 MAC_filter_Mode_sig            : 1;
+		u32 Rcv_Data_sig                   : 1;
+		u32 DMA1_IRQ_Enable_sig            : 1;
+		u32 DMA1_Timer_Enable_sig          : 1;
+		u32 DMA2_IRQ_Enable_sig            : 1;
+		u32 DMA2_Timer_Enable_sig          : 1;
+		u32 DMA1_Size_IRQ_Enable_sig       : 1;
+		u32 DMA2_Size_IRQ_Enable_sig       : 1;
+		u32 Mailbox_from_V8_Enable_sig     : 1;
+		u32 unused                         : 9;
+	} ctrl_208;
+
+	struct {
+		u32 DMA1_IRQ_Status                : 1;
+		u32 DMA1_Timer_Status              : 1;
+		u32 DMA2_IRQ_Status                : 1;
+		u32 DMA2_Timer_Status              : 1;
+		u32 DMA1_Size_IRQ_Status           : 1;
+		u32 DMA2_Size_IRQ_Status           : 1;
+		u32 Mailbox_from_V8_Status_sig     : 1;
+		u32 Data_receiver_error            : 1;
+		u32 Continuity_error_flag          : 1;
+		u32 LLC_SNAP_FLAG_set              : 1;
+		u32 Transport_Error                : 1;
+		u32 reserved                       :21;
+	} irq_20c;
+
+	struct {
+		u32 reset_block_000                : 1;
+		u32 reset_block_100                : 1;
+		u32 reset_block_200                : 1;
+		u32 reset_block_300                : 1;
+		u32 reset_block_400                : 1;
+		u32 reset_block_500                : 1;
+		u32 reset_block_600                : 1;
+		u32 reset_block_700                : 1;
+		u32 Block_reset_enable             : 8;
+		u32 Special_controls               :16;
+	} sw_reset_210;
+
+	struct {
+		u32 vuart_oe_sig                   : 1;
+		u32 v2WS_oe_sig                    : 1;
+		u32 halt_V8_sig                    : 1;
+		u32 section_pkg_enable_sig         : 1;
+		u32 s2p_sel_sig                    : 1;
+		u32 unused1                        : 3;
+		u32 polarity_PS_CLK_sig            : 1;
+		u32 polarity_PS_VALID_sig          : 1;
+		u32 polarity_PS_SYNC_sig           : 1;
+		u32 polarity_PS_ERR_sig            : 1;
+		u32 unused2                        :20;
+	} misc_214;
+
+	struct {
+		u32 Mailbox_from_V8                :32;
+	} mbox_v8_to_host_218;
+
+	struct {
+		u32 sysramaccess_data              : 8;
+		u32 sysramaccess_addr              :15;
+		u32 unused                         : 7;
+		u32 sysramaccess_write             : 1;
+		u32 sysramaccess_busmuster         : 1;
+	} mbox_host_to_v8_21c;
+
+	struct {
+		u32 Stream1_PID                    :13;
+		u32 Stream1_trans                  : 1;
+		u32 MAC_Multicast_filter           : 1;
+		u32 debug_flag_pid_saved           : 1;
+		u32 Stream2_PID                    :13;
+		u32 Stream2_trans                  : 1;
+		u32 debug_flag_write_status00      : 1;
+		u32 debug_fifo_problem             : 1;
+	} pid_filter_300;
+
+	struct {
+		u32 PCR_PID                        :13;
+		u32 PCR_trans                      : 1;
+		u32 debug_overrun3                 : 1;
+		u32 debug_overrun2                 : 1;
+		u32 PMT_PID                        :13;
+		u32 PMT_trans                      : 1;
+		u32 reserved                       : 2;
+	} pid_filter_304;
+
+	struct {
+		u32 EMM_PID                        :13;
+		u32 EMM_trans                      : 1;
+		u32 EMM_filter_4                   : 1;
+		u32 EMM_filter_6                   : 1;
+		u32 ECM_PID                        :13;
+		u32 ECM_trans                      : 1;
+		u32 reserved                       : 2;
+	} pid_filter_308;
+
+	struct {
+		u32 Group_PID                      :13;
+		u32 Group_trans                    : 1;
+		u32 unused1                        : 2;
+		u32 Group_mask                     :13;
+		u32 unused2                        : 3;
+	} pid_filter_30c_ext_ind_0_7;
+
+	struct {
+		u32 net_master_read                :17;
+		u32 unused                         :15;
+	} pid_filter_30c_ext_ind_1;
+
+	struct {
+		u32 net_master_write               :17;
+		u32 unused                         :15;
+	} pid_filter_30c_ext_ind_2;
+
+	struct {
+		u32 next_net_master_write          :17;
+		u32 unused                         :15;
+	} pid_filter_30c_ext_ind_3;
+
+	struct {
+		u32 unused1                        : 1;
+		u32 state_write                    :10;
+		u32 reserved1                      : 6;
+		u32 stack_read                     :10;
+		u32 reserved2                      : 5;
+	} pid_filter_30c_ext_ind_4;
+
+	struct {
+		u32 stack_cnt                      :10;
+		u32 unused                         :22;
+	} pid_filter_30c_ext_ind_5;
+
+	struct {
+		u32 pid_fsm_save_reg0              : 2;
+		u32 pid_fsm_save_reg1              : 2;
+		u32 pid_fsm_save_reg2              : 2;
+		u32 pid_fsm_save_reg3              : 2;
+		u32 pid_fsm_save_reg4              : 2;
+		u32 pid_fsm_save_reg300            : 2;
+		u32 write_status1                  : 2;
+		u32 write_status4                  : 2;
+		u32 data_size_reg                  :12;
+		u32 unused                         : 4;
+	} pid_filter_30c_ext_ind_6;
+
+	struct {
+		u32 index_reg                      : 5;
+		u32 extra_index_reg                : 3;
+		u32 AB_select                      : 1;
+		u32 pass_alltables                 : 1;
+		u32 unused                         :22;
+	} index_reg_310;
+
+	struct {
+		u32 PID                            :13;
+		u32 PID_trans                      : 1;
+		u32 PID_enable_bit                 : 1;
+		u32 reserved                       :17;
+	} pid_n_reg_314;
+
+	struct {
+		u32 A4_byte                        : 8;
+		u32 A5_byte                        : 8;
+		u32 A6_byte                        : 8;
+		u32 Enable_bit                     : 1;
+		u32 HighAB_bit                     : 1;
+		u32 reserved                       : 6;
+	} mac_low_reg_318;
+
+	struct {
+		u32 A1_byte                        : 8;
+		u32 A2_byte                        : 8;
+		u32 A3_byte                        : 8;
+		u32 reserved                       : 8;
+	} mac_high_reg_31c;
+
+	struct {
+		u32 reserved                       :16;
+		u32 data_Tag_ID                    :16;
+	} data_tag_400;
+
+	struct {
+		u32 Card_IDbyte6                   : 8;
+		u32 Card_IDbyte5                   : 8;
+		u32 Card_IDbyte4                   : 8;
+		u32 Card_IDbyte3                   : 8;
+	} card_id_408;
+
+	struct {
+		u32 Card_IDbyte2                   : 8;
+		u32 Card_IDbyte1                   : 8;
+	} card_id_40c;
+
+	struct {
+		u32 MAC1                           : 8;
+		u32 MAC2                           : 8;
+		u32 MAC3                           : 8;
+		u32 MAC6                           : 8;
+	} mac_address_418;
+
+	struct {
+		u32 MAC7                           : 8;
+		u32 MAC8                           : 8;
+		u32 reserved                       :16;
+	} mac_address_41c;
+
+	struct {
+		u32 transmitter_data_byte          : 8;
+		u32 ReceiveDataReady               : 1;
+		u32 ReceiveByteFrameError          : 1;
+		u32 txbuffempty                    : 1;
+		u32 reserved                       :21;
+	} ci_600;
+
+	struct {
+		u32 pi_d                           : 8;
+		u32 pi_ha                          :20;
+		u32 pi_rw                          : 1;
+		u32 pi_component_reg               : 3;
+	} pi_604;
+
+	struct {
+		u32 serialReset                    : 1;
+		u32 oncecycle_read                 : 1;
+		u32 Timer_Read_req                 : 1;
+		u32 Timer_Load_req                 : 1;
+		u32 timer_data                     : 7;
+		u32 unused                         : 1;
+		u32 Timer_addr                     : 5;
+		u32 reserved                       : 3;
+		u32 pcmcia_a_mod_pwr_n             : 1;
+		u32 pcmcia_b_mod_pwr_n             : 1;
+		u32 config_Done_stat               : 1;
+		u32 config_Init_stat               : 1;
+		u32 config_Prog_n                  : 1;
+		u32 config_wr_n                    : 1;
+		u32 config_cs_n                    : 1;
+		u32 config_cclk                    : 1;
+		u32 pi_CiMax_IRQ_n                 : 1;
+		u32 pi_timeout_status              : 1;
+		u32 pi_wait_n                      : 1;
+		u32 pi_busy_n                      : 1;
+	} pi_608;
+
+	struct {
+		u32 PID                            :13;
+		u32 key_enable                     : 1;
+		u32 key_code                       : 2;
+		u32 key_array_col                  : 3;
+		u32 key_array_row                  : 5;
+		u32 dvb_en                         : 1;
+		u32 rw_flag                        : 1;
+		u32 reserved                       : 6;
+	} dvb_reg_60c;
+
+	struct {
+		u32 sram_addr                      :15;
+		u32 sram_rw                        : 1;
+		u32 sram_data                      : 8;
+		u32 sc_xfer_bit                    : 1;
+		u32 reserved1                      : 3;
+		u32 oe_pin_reg                     : 1;
+		u32 ce_pin_reg                     : 1;
+		u32 reserved2                      : 1;
+		u32 start_sram_ibi                 : 1;
+	} sram_ctrl_reg_700;
+
+	struct {
+		u32 net_addr_read                  :16;
+		u32 net_addr_write                 :16;
+	} net_buf_reg_704;
+
+	struct {
+		u32 cai_read                       :11;
+		u32 reserved1                      : 5;
+		u32 cai_write                      :11;
+		u32 reserved2                      : 6;
+		u32 cai_cnt                        : 4;
+	} cai_buf_reg_708;
+
+	struct {
+		u32 cao_read                       :11;
+		u32 reserved1                      : 5;
+		u32 cap_write                      :11;
+		u32 reserved2                      : 6;
+		u32 cao_cnt                        : 4;
+	} cao_buf_reg_70c;
+
+	struct {
+		u32 media_read                     :11;
+		u32 reserved1                      : 5;
+		u32 media_write                    :11;
+		u32 reserved2                      : 6;
+		u32 media_cnt                      : 4;
+	} media_buf_reg_710;
+
+	struct {
+		u32 NET_Dest                       : 2;
+		u32 CAI_Dest                       : 2;
+		u32 CAO_Dest                       : 2;
+		u32 MEDIA_Dest                     : 2;
+		u32 net_ovflow_error               : 1;
+		u32 media_ovflow_error             : 1;
+		u32 cai_ovflow_error               : 1;
+		u32 cao_ovflow_error               : 1;
+		u32 ctrl_usb_wan                   : 1;
+		u32 ctrl_sramdma                   : 1;
+		u32 ctrl_maximumfill               : 1;
+		u32 reserved                       :17;
+	} sram_dest_reg_714;
+
+	struct {
+		u32 net_cnt                        :12;
+		u32 reserved1                      : 4;
+		u32 net_addr_read                  : 1;
+		u32 reserved2                      : 3;
+		u32 net_addr_write                 : 1;
+		u32 reserved3                      :11;
+	} net_buf_reg_718;
+
+	struct {
+		u32 wan_speed_sig                  : 2;
+		u32 reserved1                      : 6;
+		u32 wan_wait_state                 : 8;
+		u32 sram_chip                      : 2;
+		u32 sram_memmap                    : 2;
+		u32 reserved2                      : 4;
+		u32 wan_pkt_frame                  : 4;
+		u32 reserved3                      : 4;
+	} wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c
deleted file mode 100644
index acbc4c3..0000000
--- a/drivers/media/dvb/b2c2/skystar2.c
+++ /dev/null
@@ -1,2644 +0,0 @@
-/*
- * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card
- *              based on the FlexCopII by B2C2,Inc.
- *
- * Copyright (C) 2003  Vadim Catana, skystar@moldova.cc
- *
- * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
- * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
- *     Vincenzo Di Massa, hawk.it at tiscalinet.it
- *
- * Converted to Linux coding style
- * Misc reorganization, polishing, restyling
- *     Roberto Ragusa, skystar2-c5b8 at robertoragusa dot it
- *
- * Added hardware filtering support,
- *     Niklas Peinecke, peinecke at gdv.uni-hannover.de
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/version.h>
-
-#include <asm/io.h>
-
-#include "dvb_frontend.h"
-
-#include <linux/dvb/frontend.h>
-#include <linux/dvb/dmx.h>
-#include "dvb_demux.h"
-#include "dmxdev.h"
-#include "dvb_filter.h"
-#include "dvbdev.h"
-#include "demux.h"
-#include "dvb_net.h"
-#include "stv0299.h"
-#include "mt352.h"
-#include "mt312.h"
-#include "nxt2002.h"
-
-static int debug;
-static int enable_hw_filters = 2;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Set debugging level (0 = default, 1 = most messages, 2 = all messages).");
-module_param(enable_hw_filters, int, 0444);
-MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2");
-
-#define dprintk(x...)	do { if (debug>=1) printk(x); } while (0)
-#define ddprintk(x...)	do { if (debug>=2) printk(x); } while (0)
-
-#define SIZE_OF_BUF_DMA1	0x3ac00
-#define SIZE_OF_BUF_DMA2	0x758
-
-#define MAX_N_HW_FILTERS	(6+32)
-#define N_PID_SLOTS		256
-
-struct dmaq {
-	u32 bus_addr;
-	u32 head;
-	u32 tail;
-	u32 buffer_size;
-	u8 *buffer;
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
-#define __iomem
-#endif
-
-struct adapter {
-	struct pci_dev *pdev;
-
-	u8 card_revision;
-	u32 b2c2_revision;
-	u32 pid_filter_max;
-	u32 mac_filter_max;
-	u32 irq;
-	void __iomem *io_mem;
-	unsigned long io_port;
-	u8 mac_addr[8];
-	u32 dw_sram_type;
-
-	struct dvb_adapter dvb_adapter;
-	struct dvb_demux demux;
-	struct dmxdev dmxdev;
-	struct dmx_frontend hw_frontend;
-	struct dmx_frontend mem_frontend;
-	struct i2c_adapter i2c_adap;
-	struct dvb_net dvbnet;
-
-	struct semaphore i2c_sem;
-
-	struct dmaq dmaq1;
-	struct dmaq dmaq2;
-
-	u32 dma_ctrl;
-	u32 dma_status;
-
-	int capturing;
-
-	spinlock_t lock;
-
-	int useable_hw_filters;
-	u16 hw_pids[MAX_N_HW_FILTERS];
-	u16 pid_list[N_PID_SLOTS];
-	int pid_rc[N_PID_SLOTS];	// ref counters for the pids
-	int pid_count;
-	int whole_bandwidth_count;
-	u32 mac_filter;
-
-	struct dvb_frontend* fe;
-	int (*fe_sleep)(struct dvb_frontend* fe);
-};
-
-#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg)
-#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg)
-
-static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue)
-{
-	u32 tmp;
-
-	tmp = read_reg_dw(adapter, reg);
-	tmp = (tmp & ~zeromask) | orvalue;
-	write_reg_dw(adapter, reg, tmp);
-}
-
-/* i2c functions */
-static int i2c_main_write_for_flex2(struct adapter *adapter, u32 command, u8 *buf, int retries)
-{
-	int i;
-	u32 value;
-
-	write_reg_dw(adapter, 0x100, 0);
-	write_reg_dw(adapter, 0x100, command);
-
-	for (i = 0; i < retries; i++) {
-		value = read_reg_dw(adapter, 0x100);
-
-		if ((value & 0x40000000) == 0) {
-			if ((value & 0x81000000) == 0x80000000) {
-				if (buf != 0)
-					*buf = (value >> 0x10) & 0xff;
-
-				return 1;
-			}
-		} else {
-			write_reg_dw(adapter, 0x100, 0);
-			write_reg_dw(adapter, 0x100, command);
-		}
-	}
-
-	return 0;
-}
-
-/* device = 0x10000000 for tuner, 0x20000000 for eeprom */
-static void i2c_main_setup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len, u32 *command)
-{
-	*command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr;
-
-	if (op != 0)
-		*command = *command | 0x03000000;
-	else
-		*command = *command | 0x01000000;
-}
-
-static int flex_i2c_read4(struct adapter *adapter, u32 device, u32 chip_addr, u16 addr, u8 *buf, u8 len)
-{
-	u32 command;
-	u32 value;
-
-	int result, i;
-
-	i2c_main_setup(device, chip_addr, 1, addr, 0, len, &command);
-
-	result = i2c_main_write_for_flex2(adapter, command, buf, 100000);
-
-	if ((result & 0xff) != 0) {
-		if (len > 1) {
-			value = read_reg_dw(adapter, 0x104);
-
-			for (i = 1; i < len; i++) {
-				buf[i] = value & 0xff;
-				value = value >> 8;
-			}
-		}
-	}
-
-	return result;
-}
-
-static int flex_i2c_write4(struct adapter *adapter, u32 device, u32 chip_addr, u32 addr, u8 *buf, u8 len)
-{
-	u32 command;
-	u32 value;
-	int i;
-
-	if (len > 1) {
-		value = 0;
-
-		for (i = len; i > 1; i--) {
-			value = value << 8;
-			value = value | buf[i - 1];
-		}
-
-		write_reg_dw(adapter, 0x104, value);
-	}
-
-	i2c_main_setup(device, chip_addr, 0, addr, buf[0], len, &command);
-
-	return i2c_main_write_for_flex2(adapter, command, NULL, 100000);
-}
-
-static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret)
-{
-	if (device == 0x20000000)
-		*ret = bus | ((addr >> 8) & 3);
-	else
-		*ret = bus;
-}
-
-static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
-{
-	u32 chipaddr;
-	u32 bytes_to_transfer;
-	u8 *start;
-
-	ddprintk("%s:\n", __FUNCTION__);
-
-	start = buf;
-
-	while (len != 0) {
-		bytes_to_transfer = len;
-
-		if (bytes_to_transfer > 4)
-			bytes_to_transfer = 4;
-
-		fixchipaddr(device, bus, addr, &chipaddr);
-
-		if (flex_i2c_read4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0)
-			return buf - start;
-
-		buf = buf + bytes_to_transfer;
-		addr = addr + bytes_to_transfer;
-		len = len - bytes_to_transfer;
-	};
-
-	return buf - start;
-}
-
-static u32 flex_i2c_write(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
-{
-	u32 chipaddr;
-	u32 bytes_to_transfer;
-	u8 *start;
-
-	ddprintk("%s:\n", __FUNCTION__);
-
-	start = buf;
-
-	while (len != 0) {
-		bytes_to_transfer = len;
-
-		if (bytes_to_transfer > 4)
-			bytes_to_transfer = 4;
-
-		fixchipaddr(device, bus, addr, &chipaddr);
-
-		if (flex_i2c_write4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0)
-			return buf - start;
-
-		buf = buf + bytes_to_transfer;
-		addr = addr + bytes_to_transfer;
-		len = len - bytes_to_transfer;
-	}
-
-	return buf - start;
-}
-
-static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num)
-{
-	struct adapter *tmp = i2c_get_adapdata(adapter);
-	int i, ret = 0;
-
-	if (down_interruptible(&tmp->i2c_sem))
-		return -ERESTARTSYS;
-
-	ddprintk("%s: %d messages to transfer\n", __FUNCTION__, num);
-
-		for (i = 0; i < num; i++) {
-		ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
-			 msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
-	}
-
-	// read command
-	if ((num == 2) && (msgs[0].flags == 0) && (msgs[1].flags == I2C_M_RD) && (msgs[0].buf != NULL) && (msgs[1].buf != NULL)) {
-
-		ret = flex_i2c_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
-
-		up(&tmp->i2c_sem);
-
-		if (ret != msgs[1].len) {
-			dprintk("%s: read error !\n", __FUNCTION__);
-
-			for (i = 0; i < 2; i++) {
-				dprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
-				       msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
-		}
-
-			return -EREMOTEIO;
-		}
-
-		return num;
-	}
-	// write command
-	for (i = 0; i < num; i++) {
-
-		if ((msgs[i].flags != 0) || (msgs[i].buf == NULL) || (msgs[i].len < 2))
-			return -EINVAL;
-
-		ret = flex_i2c_write(tmp, 0x10000000, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
-
-		up(&tmp->i2c_sem);
-
-		if (ret != msgs[0].len - 1) {
-			dprintk("%s: write error %i !\n", __FUNCTION__, ret);
-
-			dprintk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i,
-			       msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
-
-			return -EREMOTEIO;
-		}
-
-		return num;
-	}
-
-	printk("%s: unknown command format !\n", __FUNCTION__);
-
-	return -EINVAL;
-}
-
-/* SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board,
-   but it seems that FlexCopII can work with more than one chip) */
-static void sram_set_net_dest(struct adapter *adapter, u8 dest)
-{
-	u32 tmp;
-
-	udelay(1000);
-
-	tmp = (read_reg_dw(adapter, 0x714) & 0xfffffffc) | (dest & 3);
-
-	udelay(1000);
-
-	write_reg_dw(adapter, 0x714, tmp);
-	write_reg_dw(adapter, 0x714, tmp);
-
-	udelay(1000);
-
-	/* return value is never used? */
-/*	return tmp; */
-}
-
-static void sram_set_cai_dest(struct adapter *adapter, u8 dest)
-{
-	u32 tmp;
-
-	udelay(1000);
-
-	tmp = (read_reg_dw(adapter, 0x714) & 0xfffffff3) | ((dest & 3) << 2);
-
-	udelay(1000);
-	udelay(1000);
-
-	write_reg_dw(adapter, 0x714, tmp);
-	write_reg_dw(adapter, 0x714, tmp);
-
-	udelay(1000);
-
-	/* return value is never used? */
-/*	return tmp; */
-}
-
-static void sram_set_cao_dest(struct adapter *adapter, u8 dest)
-{
-	u32 tmp;
-
-	udelay(1000);
-
-	tmp = (read_reg_dw(adapter, 0x714) & 0xffffffcf) | ((dest & 3) << 4);
-
-	udelay(1000);
-	udelay(1000);
-
-	write_reg_dw(adapter, 0x714, tmp);
-	write_reg_dw(adapter, 0x714, tmp);
-
-	udelay(1000);
-
-	/* return value is never used? */
-/*	return tmp; */
-}
-
-static void sram_set_media_dest(struct adapter *adapter, u8 dest)
-{
-	u32 tmp;
-
-	udelay(1000);
-
-	tmp = (read_reg_dw(adapter, 0x714) & 0xffffff3f) | ((dest & 3) << 6);
-
-	udelay(1000);
-	udelay(1000);
-
-	write_reg_dw(adapter, 0x714, tmp);
-	write_reg_dw(adapter, 0x714, tmp);
-
-	udelay(1000);
-
-	/* return value is never used? */
-/*	return tmp; */
-}
-
-/* SRAM memory is accessed through a buffer register in the FlexCop
-   chip (0x700). This register has the following structure:
-    bits 0-14  : address
-    bit  15    : read/write flag
-    bits 16-23 : 8-bit word to write
-    bits 24-27 : = 4
-    bits 28-29 : memory bank selector
-    bit  31    : busy flag
-*/
-static void flex_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
-	int i, retries;
-	u32 command;
-
-	for (i = 0; i < len; i++) {
-		command = bank | addr | 0x04000000 | (*buf << 0x10);
-
-		retries = 2;
-
-		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
-			mdelay(1);
-			retries--;
-		};
-
-		if (retries == 0)
-			printk("%s: SRAM timeout\n", __FUNCTION__);
-
-		write_reg_dw(adapter, 0x700, command);
-
-		buf++;
-		addr++;
-	}
-}
-
-static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
-	int i, retries;
-	u32 command, value;
-
-	for (i = 0; i < len; i++) {
-		command = bank | addr | 0x04008000;
-
-		retries = 10000;
-
-		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
-			mdelay(1);
-			retries--;
-		};
-
-		if (retries == 0)
-			printk("%s: SRAM timeout\n", __FUNCTION__);
-
-		write_reg_dw(adapter, 0x700, command);
-
-		retries = 10000;
-
-		while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
-			mdelay(1);
-			retries--;
-		};
-
-		if (retries == 0)
-			printk("%s: SRAM timeout\n", __FUNCTION__);
-
-		value = read_reg_dw(adapter, 0x700) >> 0x10;
-
-		*buf = (value & 0xff);
-
-		addr++;
-		buf++;
-	}
-}
-
-static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
-	u32 bank;
-
-	bank = 0;
-
-	if (adapter->dw_sram_type == 0x20000) {
-		bank = (addr & 0x18000) << 0x0d;
-	}
-
-	if (adapter->dw_sram_type == 0x00000) {
-		if ((addr >> 0x0f) == 0)
-			bank = 0x20000000;
-		else
-			bank = 0x10000000;
-	}
-
-	flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
-	u32 bank;
-
-	bank = 0;
-
-	if (adapter->dw_sram_type == 0x20000) {
-		bank = (addr & 0x18000) << 0x0d;
-	}
-
-	if (adapter->dw_sram_type == 0x00000) {
-		if ((addr >> 0x0f) == 0)
-			bank = 0x20000000;
-		else
-			bank = 0x10000000;
-	}
-
-	flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
-	u32 length;
-
-	while (len != 0) {
-		length = len;
-
-		// check if the address range belongs to the same 
-		// 32K memory chip. If not, the data is read from 
-		// one chip at a time.
-		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
-			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
-		}
-
-		sram_read_chunk(adapter, addr, buf, length);
-
-		addr = addr + length;
-		buf = buf + length;
-		len = len - length;
-	}
-}
-
-static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
-	u32 length;
-
-	while (len != 0) {
-		length = len;
-
-		// check if the address range belongs to the same 
-		// 32K memory chip. If not, the data is written to
-		// one chip at a time.
-		if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
-			length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
-		}
-
-		sram_write_chunk(adapter, addr, buf, length);
-
-		addr = addr + length;
-		buf = buf + length;
-		len = len - length;
-	}
-}
-
-static void sram_set_size(struct adapter *adapter, u32 mask)
-{
-	write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
-}
-
-static void sram_init(struct adapter *adapter)
-{
-	u32 tmp;
-
-	tmp = read_reg_dw(adapter, 0x71c);
-
-	write_reg_dw(adapter, 0x71c, 1);
-
-	if (read_reg_dw(adapter, 0x71c) != 0) {
-		write_reg_dw(adapter, 0x71c, tmp);
-
-		adapter->dw_sram_type = tmp & 0x30000;
-
-		ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
-
-	} else {
-
-		adapter->dw_sram_type = 0x10000;
-
-		ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
-	}
-
-	/* return value is never used? */
-/*	return adapter->dw_sram_type; */
-}
-
-static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
-{
-	u8 tmp1, tmp2;
-
-	dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
-
-	sram_set_size(adapter, mask);
-	sram_init(adapter);
-
-	tmp2 = 0xa5;
-	tmp1 = 0x4f;
-
-	sram_write(adapter, addr, &tmp2, 1);
-	sram_write(adapter, addr + 4, &tmp1, 1);
-
-	tmp2 = 0;
-
-	mdelay(20);
-
-	sram_read(adapter, addr, &tmp2, 1);
-	sram_read(adapter, addr, &tmp2, 1);
-
-	dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
-
-	if (tmp2 != 0xa5)
-		return 0;
-
-	tmp2 = 0x5a;
-	tmp1 = 0xf4;
-
-	sram_write(adapter, addr, &tmp2, 1);
-	sram_write(adapter, addr + 4, &tmp1, 1);
-
-	tmp2 = 0;
-
-	mdelay(20);
-
-	sram_read(adapter, addr, &tmp2, 1);
-	sram_read(adapter, addr, &tmp2, 1);
-
-	dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
-
-	if (tmp2 != 0x5a)
-		return 0;
-
-	return 1;
-}
-
-static u32 sram_length(struct adapter *adapter)
-{
-	if (adapter->dw_sram_type == 0x10000)
-		return 32768;	//  32K
-	if (adapter->dw_sram_type == 0x00000)
-		return 65536;	//  64K        
-	if (adapter->dw_sram_type == 0x20000)
-		return 131072;	// 128K
-
-	return 32768;		// 32K
-}
-
-/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
-    - for 128K there are 4x32K chips at bank 0,1,2,3.
-    - for  64K there are 2x32K chips at bank 1,2.
-    - for  32K there is one 32K chip at bank 0.
-
-   FlexCop works only with one bank at a time. The bank is selected
-   by bits 28-29 of the 0x700 register.
-  
-   bank 0 covers addresses 0x00000-0x07fff
-   bank 1 covers addresses 0x08000-0x0ffff
-   bank 2 covers addresses 0x10000-0x17fff
-   bank 3 covers addresses 0x18000-0x1ffff
-*/
-static int sram_detect_for_flex2(struct adapter *adapter)
-{
-	u32 tmp, tmp2, tmp3;
-
-	dprintk("%s:\n", __FUNCTION__);
-
-	tmp = read_reg_dw(adapter, 0x208);
-	write_reg_dw(adapter, 0x208, 0);
-
-	tmp2 = read_reg_dw(adapter, 0x71c);
-
-	dprintk("%s: tmp2 = %x\n", __FUNCTION__, tmp2);
-
-	write_reg_dw(adapter, 0x71c, 1);
-
-	tmp3 = read_reg_dw(adapter, 0x71c);
-
-	dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
-
-	write_reg_dw(adapter, 0x71c, tmp2);
-
-	// check for internal SRAM ???
-	tmp3--;
-	if (tmp3 != 0) {
-		sram_set_size(adapter, 0x10000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-
-		dprintk("%s: sram size = 32K\n", __FUNCTION__);
-
-		return 32;
-	}
-
-	if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
-		sram_set_size(adapter, 0x20000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-
-		dprintk("%s: sram size = 128K\n", __FUNCTION__);
-
-		return 128;
-	}
-
-	if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
-		sram_set_size(adapter, 0x00000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-
-		dprintk("%s: sram size = 64K\n", __FUNCTION__);
-
-		return 64;
-	}
-
-	if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
-		sram_set_size(adapter, 0x10000);
-		sram_init(adapter);
-		write_reg_dw(adapter, 0x208, tmp);
-
-		dprintk("%s: sram size = 32K\n", __FUNCTION__);
-
-		return 32;
-	}
-
-	sram_set_size(adapter, 0x10000);
-	sram_init(adapter);
-	write_reg_dw(adapter, 0x208, tmp);
-
-	dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
-
-	return 0;
-}
-
-static void sll_detect_sram_size(struct adapter *adapter)
-{
-	sram_detect_for_flex2(adapter);
-}
-
-/* EEPROM (Skystar2 has one "24LC08B" chip on board) */
-/*
-static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
-{
-	return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
-}
-*/
-
-static int eeprom_read(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
-{
-	return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len);
-}
-
-static u8 calc_lrc(u8 *buf, int len)
-{
-	int i;
-	u8 sum;
-
-	sum = 0;
-
-	for (i = 0; i < len; i++)
-		sum = sum ^ buf[i];
-
-	return sum;
-}
-
-static int eeprom_lrc_read(struct adapter *adapter, u32 addr, u32 len, u8 *buf, int retries)
-{
-	int i;
-
-	for (i = 0; i < retries; i++) {
-		if (eeprom_read(adapter, addr, buf, len) == len) {
-			if (calc_lrc(buf, len - 1) == buf[len - 1])
-				return 1;
-		}
-	}
-
-	return 0;
-}
-
-/*
-static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
-{
-	int i;
-
-	for (i = 0; i < retries; i++) {
-		if (eeprom_write(adapter, addr, wbuf, len) == len) {
-			if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
-				return 1;
-		}
-	}
-
-	return 0;
-}
-*/
-
-
-/* These functions could be used to unlock SkyStar2 cards. */
-
-/*
-static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
-{
-	u8 rbuf[20];
-	u8 wbuf[20];
-
-	if (len != 16)
-		return 0;
-
-	memcpy(wbuf, key, len);
-
-	wbuf[16] = 0;
-	wbuf[17] = 0;
-	wbuf[18] = 0;
-	wbuf[19] = calc_lrc(wbuf, 19);
-
-	return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
-}
-
-static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
-{
-	u8 buf[20];
-
-	if (len != 16)
-		return 0;
-
-	if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
-		return 0;
-
-	memcpy(key, buf, len);
-
-	return 1;
-}
-*/
-
-static int eeprom_get_mac_addr(struct adapter *adapter, char type, u8 *mac)
-{
-	u8 tmp[8];
-
-	if (eeprom_lrc_read(adapter, 0x3f8, 8, tmp, 4) != 0) {
-		if (type != 0) {
-			mac[0] = tmp[0];
-			mac[1] = tmp[1];
-			mac[2] = tmp[2];
-			mac[3] = 0xfe;
-			mac[4] = 0xff;
-			mac[5] = tmp[3];
-			mac[6] = tmp[4];
-			mac[7] = tmp[5];
-
-		} else {
-
-			mac[0] = tmp[0];
-			mac[1] = tmp[1];
-			mac[2] = tmp[2];
-			mac[3] = tmp[3];
-			mac[4] = tmp[4];
-			mac[5] = tmp[5];
-		}
-
-		return 1;
-
-	} else {
-
-		if (type == 0) {
-			memset(mac, 0, 6);
-
-		} else {
-
-			memset(mac, 0, 8);
-		}
-
-		return 0;
-	}
-}
-
-/*
-static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
-{
-	u8 tmp[8];
-
-	if (type != 0) {
-		tmp[0] = mac[0];
-		tmp[1] = mac[1];
-		tmp[2] = mac[2];
-		tmp[3] = mac[5];
-		tmp[4] = mac[6];
-		tmp[5] = mac[7];
-
-	} else {
-
-		tmp[0] = mac[0];
-		tmp[1] = mac[1];
-		tmp[2] = mac[2];
-		tmp[3] = mac[3];
-		tmp[4] = mac[4];
-		tmp[5] = mac[5];
-	}
-
-	tmp[6] = 0;
-	tmp[7] = calc_lrc(tmp, 7);
-
-	if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
-		return 1;
-
-	return 0;
-}
-*/
-
-/* PID filter */
-
-/* every flexcop has 6 "lower" hw PID filters     */
-/* these are enabled by setting bits 0-5 of 0x208 */
-/* for the 32 additional filters we have to select one */
-/* of them through 0x310 and modify through 0x314 */
-/* op: 0=disable, 1=enable */
-static void filter_enable_hw_filter(struct adapter *adapter, int id, u8 op)
-{
-	dprintk("%s: id=%d op=%d\n", __FUNCTION__, id, op);
-	if (id <= 5) {
-		u32 mask = (0x00000001 << id);
-		write_reg_bitfield(adapter, 0x208, mask, op ? mask : 0);
-	} else {
-		/* select */
-		write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f);
-		/* modify */
-		write_reg_bitfield(adapter, 0x314, 0x00006000, op ? 0x00004000 : 0);
-	}
-}
-
-/* this sets the PID that should pass the specified filter */
-static void pid_set_hw_pid(struct adapter *adapter, int id, u16 pid)
-{
-	dprintk("%s: id=%d  pid=%d\n", __FUNCTION__, id, pid);
-	if (id <= 5) {
-		u32 adr = 0x300 + ((id & 6) << 1);
-		int shift = (id & 1) ? 16 : 0;
-		dprintk("%s: id=%d  addr=%x %c  pid=%d\n", __FUNCTION__, id, adr, (id & 1) ? 'h' : 'l', pid);
-		write_reg_bitfield(adapter, adr, (0x7fff) << shift, (pid & 0x1fff) << shift);
-	} else {
-		/* select */
-		write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f);
-		/* modify */
-		write_reg_bitfield(adapter, 0x314, 0x1fff, pid & 0x1fff);
-	}
-}
-
-
-/*
-static void filter_enable_null_filter(struct adapter *adapter, u32 op)
-{
-	dprintk("%s: op=%x\n", __FUNCTION__, op);
-
-	write_reg_bitfield(adapter, 0x208, 0x00000040, op?0x00000040:0);
-}
-*/
-
-static void filter_enable_mask_filter(struct adapter *adapter, u32 op)
-{
-	dprintk("%s: op=%x\n", __FUNCTION__, op);
-
-	write_reg_bitfield(adapter, 0x208, 0x00000080, op ? 0x00000080 : 0);
-}
-
-
-static void ctrl_enable_mac(struct adapter *adapter, u32 op)
-{
-	write_reg_bitfield(adapter, 0x208, 0x00004000, op ? 0x00004000 : 0);
-}
-
-static int ca_set_mac_dst_addr_filter(struct adapter *adapter, u8 *mac)
-{
-	u32 tmp1, tmp2;
-
-	tmp1 = (mac[3] << 0x18) | (mac[2] << 0x10) | (mac[1] << 0x08) | mac[0];
-	tmp2 = (mac[5] << 0x08) | mac[4];
-
-	write_reg_dw(adapter, 0x418, tmp1);
-	write_reg_dw(adapter, 0x41c, tmp2);
-
-	return 0;
-}
-
-/*
-static void set_ignore_mac_filter(struct adapter *adapter, u8 op)
-{
-	if (op != 0) {
-		write_reg_bitfield(adapter, 0x208, 0x00004000, 0);
-		adapter->mac_filter = 1;
-	} else {
-		if (adapter->mac_filter != 0) {
-			adapter->mac_filter = 0;
-			write_reg_bitfield(adapter, 0x208, 0x00004000, 0x00004000);
-		}
-	}
-}
-*/
-
-/*
-static void check_null_filter_enable(struct adapter *adapter)
-{
-	filter_enable_null_filter(adapter, 1);
-	filter_enable_mask_filter(adapter, 1);
-}
-*/
-
-static void pid_set_group_pid(struct adapter *adapter, u16 pid)
-{
-	u32 value;
-
-	dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-	value = (pid & 0x3fff) | (read_reg_dw(adapter, 0x30c) & 0xffff0000);
-	write_reg_dw(adapter, 0x30c, value);
-}
-
-static void pid_set_group_mask(struct adapter *adapter, u16 pid)
-{
-	u32 value;
-
-	dprintk("%s: pid=%x\n", __FUNCTION__, pid);
-	value = ((pid & 0x3fff) << 0x10) | (read_reg_dw(adapter, 0x30c) & 0xffff);
-	write_reg_dw(adapter, 0x30c, value);
-}
-
-/*
-static int pid_get_group_pid(struct adapter *adapter)
-{
-	return read_reg_dw(adapter, 0x30c) & 0x00001fff;
-}
-
-static int pid_get_group_mask(struct adapter *adapter)
-{
-	return (read_reg_dw(adapter, 0x30c) >> 0x10)& 0x00001fff;
-}
-*/
-
-/*
-static void reset_hardware_pid_filter(struct adapter *adapter)
-{
-	pid_set_stream1_pid(adapter, 0x1fff);
-
-	pid_set_stream2_pid(adapter, 0x1fff);
-	filter_enable_stream2_filter(adapter, 0);
-
-	pid_set_pcr_pid(adapter, 0x1fff);
-	filter_enable_pcr_filter(adapter, 0);
-
-	pid_set_pmt_pid(adapter, 0x1fff);
-	filter_enable_pmt_filter(adapter, 0);
-
-	pid_set_ecm_pid(adapter, 0x1fff);
-	filter_enable_ecm_filter(adapter, 0);
-
-	pid_set_emm_pid(adapter, 0x1fff);
-	filter_enable_emm_filter(adapter, 0);
-}
-*/
-
-static void init_pids(struct adapter *adapter)
-{
-	int i;
-
-	adapter->pid_count = 0;
-	adapter->whole_bandwidth_count = 0;
-	for (i = 0; i < adapter->useable_hw_filters; i++) {
-		dprintk("%s: setting filter %d to 0x1fff\n", __FUNCTION__, i);
-		adapter->hw_pids[i] = 0x1fff;
-		pid_set_hw_pid(adapter, i, 0x1fff);
-}
-
-	pid_set_group_pid(adapter, 0);
-	pid_set_group_mask(adapter, 0x1fe0);
-}
-
-static void open_whole_bandwidth(struct adapter *adapter)
-{
-	dprintk("%s:\n", __FUNCTION__);
-	pid_set_group_pid(adapter, 0);
-	pid_set_group_mask(adapter, 0);
-/*
-	filter_enable_mask_filter(adapter, 1);
-*/
-}
-
-static void close_whole_bandwidth(struct adapter *adapter)
-{
-	dprintk("%s:\n", __FUNCTION__);
-	pid_set_group_pid(adapter, 0);
-	pid_set_group_mask(adapter, 0x1fe0);
-/*
-	filter_enable_mask_filter(adapter, 1);
-*/
-}
-
-static void whole_bandwidth_inc(struct adapter *adapter)
-{
-	if (adapter->whole_bandwidth_count++ == 0)
-		open_whole_bandwidth(adapter);
-}
-
-static void whole_bandwidth_dec(struct adapter *adapter)
-{
-	if (--adapter->whole_bandwidth_count <= 0)
-		close_whole_bandwidth(adapter);
-}
-
-/* The specified PID has to be let through the
-   hw filters.
-   We try to allocate an hardware filter and open whole
-   bandwidth when allocation is impossible.
-   All pids<=0x1f pass through the group filter.
-   Returns 1 on success, -1 on error */
-static int add_hw_pid(struct adapter *adapter, u16 pid)
-{
-	int i;
-
-	dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-	if (pid <= 0x1f)
-		return 1;
-
-	/* we can't use a filter for 0x2000, so no search */
-	if (pid != 0x2000) {
-		/* find an unused hardware filter */
-		for (i = 0; i < adapter->useable_hw_filters; i++) {
-			dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i);
-			if (adapter->hw_pids[i] == 0x1fff) {
-				dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i);
-				adapter->hw_pids[i] = pid;
-				pid_set_hw_pid(adapter, i, pid);
-				filter_enable_hw_filter(adapter, i, 1);
-		return 1;
-	}
-	}
-	}
-	/* if we have not used a filter, this pid depends on whole bandwidth */
-	dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid);
-	whole_bandwidth_inc(adapter);
-		return 1;
-	}
-
-/* returns -1 if the pid was not present in the filters */
-static int remove_hw_pid(struct adapter *adapter, u16 pid)
-{
-	int i;
-
-	dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-	if (pid <= 0x1f)
-		return 1;
-
-	/* we can't use a filter for 0x2000, so no search */
-	if (pid != 0x2000) {
-		for (i = 0; i < adapter->useable_hw_filters; i++) {
-			dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i);
-			if (adapter->hw_pids[i] == pid) {	// find the pid slot
-				dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i);
-				adapter->hw_pids[i] = 0x1fff;
-				pid_set_hw_pid(adapter, i, 0x1fff);
-				filter_enable_hw_filter(adapter, i, 0);
-		return 1;
-	}
-	}
-	}
-	/* if we have not used a filter, this pid depended on whole bandwith */
-	dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid);
-	whole_bandwidth_dec(adapter);
-		return 1;
-	}
-
-/* Adds a PID to the filters.
-   Adding a pid more than once is possible, we keep reference counts.
-   Whole stream available through pid==0x2000.
-   Returns 1 on success, -1 on error */
-static int add_pid(struct adapter *adapter, u16 pid)
-{
-	int i;
-
-	dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-	if (pid > 0x1ffe && pid != 0x2000)
-		return -1;
-
-	// check if the pid is already present
-	for (i = 0; i < adapter->pid_count; i++)
-		if (adapter->pid_list[i] == pid) {
-			adapter->pid_rc[i]++;	// increment ref counter
-		return 1;
-		}
-
-	if (adapter->pid_count == N_PID_SLOTS)
-		return -1;	// no more pids can be added
-	adapter->pid_list[adapter->pid_count] = pid;	// register pid
-	adapter->pid_rc[adapter->pid_count] = 1;
-	adapter->pid_count++;
-	// hardware setting
-	add_hw_pid(adapter, pid);
-
-			return 1;
-		}
-
-/* Removes a PID from the filters. */
-static int remove_pid(struct adapter *adapter, u16 pid)
-{
-	int i;
-
-	dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
-	if (pid > 0x1ffe && pid != 0x2000)
-		return -1;
-
-	// check if the pid is present (it must be!)
-	for (i = 0; i < adapter->pid_count; i++) {
-		if (adapter->pid_list[i] == pid) {
-			adapter->pid_rc[i]--;
-			if (adapter->pid_rc[i] <= 0) {
-				// remove from the list
-				adapter->pid_count--;
-				adapter->pid_list[i]=adapter->pid_list[adapter->pid_count];
-				adapter->pid_rc[i] = adapter->pid_rc[adapter->pid_count];
-				// hardware setting
-				remove_hw_pid(adapter, pid);
-			}
-			return 1;
-		}
-	}
-
-	return -1;
-}
-
-
-/* dma & irq */
-static void ctrl_enable_smc(struct adapter *adapter, u32 op)
-{
-	write_reg_bitfield(adapter, 0x208, 0x00000800, op ? 0x00000800 : 0);
-}
-
-static void dma_enable_disable_irq(struct adapter *adapter, u32 flag1, u32 flag2, u32 flag3)
-{
-	adapter->dma_ctrl = adapter->dma_ctrl & 0x000f0000;
-
-	if (flag1 == 0) {
-		if (flag2 == 0)
-			adapter->dma_ctrl = adapter->dma_ctrl & ~0x00010000;
-		else
-			adapter->dma_ctrl = adapter->dma_ctrl | 0x00010000;
-
-		if (flag3 == 0)
-			adapter->dma_ctrl = adapter->dma_ctrl & ~0x00020000;
-		else
-			adapter->dma_ctrl = adapter->dma_ctrl | 0x00020000;
-
-	} else {
-
-		if (flag2 == 0)
-			adapter->dma_ctrl = adapter->dma_ctrl & ~0x00040000;
-		else
-			adapter->dma_ctrl = adapter->dma_ctrl | 0x00040000;
-
-		if (flag3 == 0)
-			adapter->dma_ctrl = adapter->dma_ctrl & ~0x00080000;
-		else
-			adapter->dma_ctrl = adapter->dma_ctrl | 0x00080000;
-	}
-}
-
-static void irq_dma_enable_disable_irq(struct adapter *adapter, u32 op)
-{
-	u32 value;
-
-	value = read_reg_dw(adapter, 0x208) & 0xfff0ffff;
-
-	if (op != 0)
-		value = value | (adapter->dma_ctrl & 0x000f0000);
-
-	write_reg_dw(adapter, 0x208, value);
-}
-
-/* FlexCopII has 2 dma channels. DMA1 is used to transfer TS data to
-   system memory.
-
-   The DMA1 buffer is divided in 2 subbuffers of equal size.
-   FlexCopII will transfer TS data to one subbuffer, signal an interrupt
-   when the subbuffer is full and continue fillig the second subbuffer.
-
-   For DMA1:
-       subbuffer size in 32-bit words is stored in the first 24 bits of
-       register 0x004. The last 8 bits of register 0x004 contain the number
-       of subbuffers.
-       
-       the first 30 bits of register 0x000 contain the address of the first
-       subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1,
-       when dma1 is enabled.
-
-       the first 30 bits of register 0x00c contain the address of the second
-       subbuffer. the last 2 bits contain 1.
-
-       register 0x008 will contain the address of the subbuffer that was filled
-       with TS data, when FlexCopII will generate an interrupt.
-
-   For DMA2:
-       subbuffer size in 32-bit words is stored in the first 24 bits of
-       register 0x014. The last 8 bits of register 0x014 contain the number
-       of subbuffers.
-       
-       the first 30 bits of register 0x010 contain the address of the first
-       subbuffer.  The last 2 bits contain 0, when dma1 is disabled and 1,
-       when dma1 is enabled.
-
-       the first 30 bits of register 0x01c contain the address of the second
-       subbuffer. the last 2 bits contain 1.
-
-       register 0x018 contains the address of the subbuffer that was filled
-       with TS data, when FlexCopII generates an interrupt.
-*/
-static int dma_init_dma(struct adapter *adapter, u32 dma_channel)
-{
-	u32 subbuffers, subbufsize, subbuf0, subbuf1;
-
-	if (dma_channel == 0) {
-		dprintk("%s: Initializing DMA1 channel\n", __FUNCTION__);
-
-		subbuffers = 2;
-
-		subbufsize = (((adapter->dmaq1.buffer_size / 2) / 4) << 8) | subbuffers;
-
-		subbuf0 = adapter->dmaq1.bus_addr & 0xfffffffc;
-
-		subbuf1 = ((adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) & 0xfffffffc) | 1;
-
-		dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
-		udelay(1000);
-		write_reg_dw(adapter, 0x000, subbuf0);
-
-		dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
-		udelay(1000);
-		write_reg_dw(adapter, 0x004, subbufsize);
-
-		dprintk("%s: second subbuffer address = 0x%x\n", __FUNCTION__, subbuf1);
-		udelay(1000);
-		write_reg_dw(adapter, 0x00c, subbuf1);
-
-		dprintk("%s: counter = 0x%x\n", __FUNCTION__, adapter->dmaq1.bus_addr & 0xfffffffc);
-		write_reg_dw(adapter, 0x008, adapter->dmaq1.bus_addr & 0xfffffffc);
-		udelay(1000);
-
-		dma_enable_disable_irq(adapter, 0, 1, subbuffers ? 1 : 0);
-
-		irq_dma_enable_disable_irq(adapter, 1);
-
-		sram_set_media_dest(adapter, 1);
-		sram_set_net_dest(adapter, 1);
-		sram_set_cai_dest(adapter, 2);
-		sram_set_cao_dest(adapter, 2);
-	}
-
-	if (dma_channel == 1) {
-		dprintk("%s: Initializing DMA2 channel\n", __FUNCTION__);
-
-		subbuffers = 2;
-
-		subbufsize = (((adapter->dmaq2.buffer_size / 2) / 4) << 8) | subbuffers;
-
-		subbuf0 = adapter->dmaq2.bus_addr & 0xfffffffc;
-
-		subbuf1 = ((adapter->dmaq2.bus_addr + adapter->dmaq2.buffer_size / 2) & 0xfffffffc) | 1;
-
-		dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
-		udelay(1000);
-		write_reg_dw(adapter, 0x010, subbuf0);
-
-		dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
-		udelay(1000);
-		write_reg_dw(adapter, 0x014, subbufsize);
-
-		dprintk("%s: second buffer address = 0x%x\n", __FUNCTION__, subbuf1);
-		udelay(1000);
-		write_reg_dw(adapter, 0x01c, subbuf1);
-
-		sram_set_cai_dest(adapter, 2);
-	}
-
-	return 0;
-}
-
-static void ctrl_enable_receive_data(struct adapter *adapter, u32 op)
-{
-	if (op == 0) {
-		write_reg_bitfield(adapter, 0x208, 0x00008000, 0);
-		adapter->dma_status = adapter->dma_status & ~0x00000004;
-	} else {
-		write_reg_bitfield(adapter, 0x208, 0x00008000, 0x00008000);
-		adapter->dma_status = adapter->dma_status | 0x00000004;
-	}
-}
-
-/* bit 0 of dma_mask is set to 1 if dma1 channel has to be enabled/disabled
-   bit 1 of dma_mask is set to 1 if dma2 channel has to be enabled/disabled
-*/
-static void dma_start_stop(struct adapter *adapter, u32 dma_mask, int start_stop)
-{
-	u32 dma_enable, dma1_enable, dma2_enable;
-
-	dprintk("%s: dma_mask=%x\n", __FUNCTION__, dma_mask);
-
-	if (start_stop == 1) {
-		dprintk("%s: starting dma\n", __FUNCTION__);
-
-		dma1_enable = 0;
-		dma2_enable = 0;
-
-		if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) == 0) && (adapter->dmaq1.bus_addr != 0)) {
-			adapter->dma_status = adapter->dma_status | 1;
-			dma1_enable = 1;
-		}
-
-		if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) == 0) && (adapter->dmaq2.bus_addr != 0)) {
-			adapter->dma_status = adapter->dma_status | 2;
-			dma2_enable = 1;
-		}
-		// enable dma1 and dma2
-		if ((dma1_enable == 1) && (dma2_enable == 1)) {
-			write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1);
-			write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
-			write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1);
-
-			ctrl_enable_receive_data(adapter, 1);
-
-			return;
-		}
-		// enable dma1
-		if ((dma1_enable == 1) && (dma2_enable == 0)) {
-			write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1);
-			write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
-
-			ctrl_enable_receive_data(adapter, 1);
-
-			return;
-		}
-		// enable dma2
-		if ((dma1_enable == 0) && (dma2_enable == 1)) {
-			write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1);
-
-			ctrl_enable_receive_data(adapter, 1);
-
-			return;
-		}
-		// start dma
-		if ((dma1_enable == 0) && (dma2_enable == 0)) {
-			ctrl_enable_receive_data(adapter, 1);
-
-			return;
-		}
-
-	} else {
-
-		dprintk("%s: stopping dma\n", __FUNCTION__);
-
-		dma_enable = adapter->dma_status & 0x00000003;
-
-		if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0)) {
-			dma_enable = dma_enable & 0xfffffffe;
-		}
-
-		if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0)) {
-			dma_enable = dma_enable & 0xfffffffd;
-		}
-		//stop dma
-		if ((dma_enable == 0) && ((adapter->dma_status & 4) != 0)) {
-			ctrl_enable_receive_data(adapter, 0);
-
-			udelay(3000);
-		}
-		//disable dma1
-		if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0) && (adapter->dmaq1.bus_addr != 0)) {
-			write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr);
-			write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
-
-			adapter->dma_status = adapter->dma_status & ~0x00000001;
-		}
-		//disable dma2
-		if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0) && (adapter->dmaq2.bus_addr != 0)) {
-			write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr);
-
-			adapter->dma_status = adapter->dma_status & ~0x00000002;
-		}
-	}
-}
-
-static void open_stream(struct adapter *adapter, u16 pid)
-{
-	u32 dma_mask;
-
-	++adapter->capturing;
-
-	filter_enable_mask_filter(adapter, 1);
-
-	add_pid(adapter, pid);
-
-	dprintk("%s: adapter->dma_status=%x\n", __FUNCTION__, adapter->dma_status);
-
-	if ((adapter->dma_status & 7) != 7) {
-		dma_mask = 0;
-
-		if (((adapter->dma_status & 0x10000000) != 0) && ((adapter->dma_status & 1) == 0)) {
-			dma_mask = dma_mask | 1;
-
-			adapter->dmaq1.head = 0;
-			adapter->dmaq1.tail = 0;
-
-			memset(adapter->dmaq1.buffer, 0, adapter->dmaq1.buffer_size);
-		}
-
-		if (((adapter->dma_status & 0x20000000) != 0) && ((adapter->dma_status & 2) == 0)) {
-			dma_mask = dma_mask | 2;
-
-			adapter->dmaq2.head = 0;
-			adapter->dmaq2.tail = 0;
-		}
-
-		if (dma_mask != 0) {
-			irq_dma_enable_disable_irq(adapter, 1);
-
-			dma_start_stop(adapter, dma_mask, 1);
-		}
-	}
-}
-
-static void close_stream(struct adapter *adapter, u16 pid)
-{
-	if (adapter->capturing > 0)
-		--adapter->capturing;
-
-	dprintk("%s: dma_status=%x\n", __FUNCTION__, adapter->dma_status);
-
-	if (adapter->capturing == 0) {
-		u32 dma_mask = 0;
-
-	if ((adapter->dma_status & 1) != 0)
-		dma_mask = dma_mask | 0x00000001;
-	if ((adapter->dma_status & 2) != 0)
-		dma_mask = dma_mask | 0x00000002;
-
-	if (dma_mask != 0) {
-			dma_start_stop(adapter, dma_mask, 0);
-	}
-	}
-	remove_pid(adapter, pid);
-}
-
-static void interrupt_service_dma1(struct adapter *adapter)
-{
-	struct dvb_demux *dvbdmx = &adapter->demux;
-
-	int n_cur_dma_counter;
-	u32 n_num_bytes_parsed;
-	u32 n_num_new_bytes_transferred;
-	u32 dw_default_packet_size = 188;
-	u8 gb_tmp_buffer[188];
-	u8 *pb_dma_buf_cur_pos;
-
-	n_cur_dma_counter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr;
-	n_cur_dma_counter = (n_cur_dma_counter / dw_default_packet_size) * dw_default_packet_size;
-
-	if ((n_cur_dma_counter < 0) || (n_cur_dma_counter > adapter->dmaq1.buffer_size)) {
-		dprintk("%s: dma counter outside dma buffer\n", __FUNCTION__);
-		return;
-	}
-
-	adapter->dmaq1.head = n_cur_dma_counter;
-
-	if (adapter->dmaq1.tail <= n_cur_dma_counter) {
-		n_num_new_bytes_transferred = n_cur_dma_counter - adapter->dmaq1.tail;
-
-	} else {
-
-		n_num_new_bytes_transferred = (adapter->dmaq1.buffer_size - adapter->dmaq1.tail) + n_cur_dma_counter;
-	}
-
-	ddprintk("%s: n_cur_dma_counter = %d\n", __FUNCTION__, n_cur_dma_counter);
-	ddprintk("%s: dmaq1.tail        = %d\n", __FUNCTION__, adapter->dmaq1.tail);
-	ddprintk("%s: bytes_transferred = %d\n", __FUNCTION__, n_num_new_bytes_transferred);
-
-	if (n_num_new_bytes_transferred < dw_default_packet_size)
-		return;
-
-	n_num_bytes_parsed = 0;
-
-	while (n_num_bytes_parsed < n_num_new_bytes_transferred) {
-		pb_dma_buf_cur_pos = adapter->dmaq1.buffer + adapter->dmaq1.tail;
-
-		if (adapter->dmaq1.buffer + adapter->dmaq1.buffer_size < adapter->dmaq1.buffer + adapter->dmaq1.tail + 188) {
-			memcpy(gb_tmp_buffer, adapter->dmaq1.buffer + adapter->dmaq1.tail,
-			       adapter->dmaq1.buffer_size - adapter->dmaq1.tail);
-			memcpy(gb_tmp_buffer + (adapter->dmaq1.buffer_size - adapter->dmaq1.tail), adapter->dmaq1.buffer,
-			       (188 - (adapter->dmaq1.buffer_size - adapter->dmaq1.tail)));
-
-			pb_dma_buf_cur_pos = gb_tmp_buffer;
-		}
-
-		if (adapter->capturing != 0) {
-			dvb_dmx_swfilter_packets(dvbdmx, pb_dma_buf_cur_pos, dw_default_packet_size / 188);
-		}
-
-		n_num_bytes_parsed = n_num_bytes_parsed + dw_default_packet_size;
-
-		adapter->dmaq1.tail = adapter->dmaq1.tail + dw_default_packet_size;
-
-		if (adapter->dmaq1.tail >= adapter->dmaq1.buffer_size)
-			adapter->dmaq1.tail = adapter->dmaq1.tail - adapter->dmaq1.buffer_size;
-	};
-}
-
-static void interrupt_service_dma2(struct adapter *adapter)
-{
-	printk("%s:\n", __FUNCTION__);
-}
-
-static irqreturn_t isr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct adapter *tmp = dev_id;
-
-	u32 value;
-
-	ddprintk("%s:\n", __FUNCTION__);
-
-	spin_lock_irq(&tmp->lock);
-
-	if (0 == ((value = read_reg_dw(tmp, 0x20c)) & 0x0f)) {
-		spin_unlock_irq(&tmp->lock);
-		return IRQ_NONE;
-	}
-	
-	while (value != 0) {
-		if ((value & 0x03) != 0)
-			interrupt_service_dma1(tmp);
-		if ((value & 0x0c) != 0)
-			interrupt_service_dma2(tmp);
-		value = read_reg_dw(tmp, 0x20c) & 0x0f;
-	}
-
-	spin_unlock_irq(&tmp->lock);
-	return IRQ_HANDLED;
-}
-
-static int init_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq,
-			      int size, int dmaq_offset)
-{
-	struct pci_dev *pdev = adapter->pdev;
-	dma_addr_t dma_addr;
-
-	dmaq->head = 0;
-	dmaq->tail = 0;
-
-	dmaq->buffer = pci_alloc_consistent(pdev, size + 0x80, &dma_addr);
-	if (!dmaq->buffer)
-		return -ENOMEM;
-
-	dmaq->bus_addr = dma_addr;
-	dmaq->buffer_size = size;
-
-	dma_init_dma(adapter, dmaq_offset);
-
-	ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n",
-		 __FUNCTION__, dmaq->buffer, size);
-
-	return 0;
-	}
-
-static int init_dma_queue(struct adapter *adapter)
-{
-	struct {
-		struct dmaq *dmaq;
-		u32 dma_status;
-		int size;
-	} dmaq_desc[] = {
-		{ &adapter->dmaq1, 0x10000000, SIZE_OF_BUF_DMA1 },
-		{ &adapter->dmaq2, 0x20000000, SIZE_OF_BUF_DMA2 }
-	}, *p = dmaq_desc;
-	int i;
-
-	for (i = 0; i < 2; i++, p++) {
-		if (init_dma_queue_one(adapter, p->dmaq, p->size, i) < 0)
-			adapter->dma_status &= ~p->dma_status;
-		else
-			adapter->dma_status |= p->dma_status;
-	}
-	return (adapter->dma_status & 0x30000000) ? 0 : -ENOMEM;
-}
-
-static void free_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq)
-{
-	if (dmaq->buffer) {
-		pci_free_consistent(adapter->pdev, dmaq->buffer_size + 0x80,
-				    dmaq->buffer, dmaq->bus_addr);
-		memset(dmaq, 0, sizeof(*dmaq));
-	}
-}
-
-static void free_dma_queue(struct adapter *adapter)
-{
-	struct dmaq *dmaq[] = {
-		&adapter->dmaq1,
-		&adapter->dmaq2,
-		NULL
-	}, **p;
-
-	for (p = dmaq; *p; p++)
-		free_dma_queue_one(adapter, *p);
-	}
-
-static void release_adapter(struct adapter *adapter)
-{
-	struct pci_dev *pdev = adapter->pdev;
-
-	iounmap(adapter->io_mem);
-	pci_disable_device(pdev);
-	pci_release_region(pdev, 0);
-	pci_release_region(pdev, 1);
-}
-
-static void free_adapter_object(struct adapter *adapter)
-{
-	dprintk("%s:\n", __FUNCTION__);
-
-	close_stream(adapter, 0);
-		free_irq(adapter->irq, adapter);
-	free_dma_queue(adapter);
-	release_adapter(adapter);
-	kfree(adapter);
-}
-
-static struct pci_driver skystar2_pci_driver;
-
-static int claim_adapter(struct adapter *adapter)
-{
-	struct pci_dev *pdev = adapter->pdev;
-	u16 var;
-	int ret;
-
-	ret = pci_request_region(pdev, 1, skystar2_pci_driver.name);
-	if (ret < 0)
-		goto out;
-
-	ret = pci_request_region(pdev, 0, skystar2_pci_driver.name);
-	if (ret < 0)
-		goto err_pci_release_1;
-
-	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision);
-
-	dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision);
-
-	ret = pci_enable_device(pdev);
-	if (ret < 0)
-		goto err_pci_release_0;
-
-	pci_read_config_word(pdev, 4, &var);
-
-	if ((var & 4) == 0)
-		pci_set_master(pdev);
-
-	adapter->io_port = pdev->resource[1].start;
-
-	adapter->io_mem = ioremap(pdev->resource[0].start, 0x800);
-
-	if (!adapter->io_mem) {
-		dprintk("%s: can not map io memory\n", __FUNCTION__);
-		ret = -EIO;
-		goto err_pci_disable;
-	}
-
-	dprintk("%s: io memory maped at %p\n", __FUNCTION__, adapter->io_mem);
-
-	ret = 1;
-out:
-	return ret;
-
-err_pci_disable:
-	pci_disable_device(pdev);
-err_pci_release_0:
-	pci_release_region(pdev, 0);
-err_pci_release_1:
-	pci_release_region(pdev, 1);
-	goto out;
-}
-
-/*
-static int sll_reset_flexcop(struct adapter *adapter)
-{
-	write_reg_dw(adapter, 0x208, 0);
-	write_reg_dw(adapter, 0x210, 0xb2ff);
-
-	return 0;
-}
-*/
-
-static void decide_how_many_hw_filters(struct adapter *adapter)
-{
-	int hw_filters;
-	int mod_option_hw_filters;
-
-	// FlexCop IIb & III have 6+32 hw filters    
-	// FlexCop II has 6 hw filters, every other should have at least 6
-	switch (adapter->b2c2_revision) {
-	case 0x82:		/* II */
-		hw_filters = 6;
-		break;
-	case 0xc3:		/* IIB */
-		hw_filters = 6 + 32;
-		break;
-	case 0xc0:		/* III */
-		hw_filters = 6 + 32;
-		break;
-	default:
-		hw_filters = 6;
-		break;
-	}
-	printk("%s: the chip has %i hardware filters", __FILE__, hw_filters);
-
-	mod_option_hw_filters = 0;
-	if (enable_hw_filters >= 1)
-		mod_option_hw_filters += 6;
-	if (enable_hw_filters >= 2)
-		mod_option_hw_filters += 32;
-
-	if (mod_option_hw_filters >= hw_filters) {
-		adapter->useable_hw_filters = hw_filters;
-	} else {
-		adapter->useable_hw_filters = mod_option_hw_filters;
-		printk(", but only %d will be used because of module option", mod_option_hw_filters);
-	}
-	printk("\n");
-	dprintk("%s: useable_hardware_filters set to %i\n", __FILE__, adapter->useable_hw_filters);
-}
-
-static int driver_initialize(struct pci_dev *pdev)
-{
-	struct adapter *adapter;
-	u32 tmp;
-	int ret = -ENOMEM;
-
-	adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL);
-	if (!adapter) {
-		dprintk("%s: out of memory!\n", __FUNCTION__);
-		goto out;
-	}
-
-	memset(adapter, 0, sizeof(struct adapter));
-
-	pci_set_drvdata(pdev,adapter);
-
-	adapter->pdev = pdev;
-	adapter->irq = pdev->irq;
-
-	ret = claim_adapter(adapter);
-	if (ret < 0)
-		goto err_kfree;
-
-	irq_dma_enable_disable_irq(adapter, 0);
-
-	ret = request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter);
-	if (ret < 0) {
-		dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq);
-		goto err_release_adapter;
-	}
-
-	read_reg_dw(adapter, 0x208);
-	write_reg_dw(adapter, 0x208, 0);
-	write_reg_dw(adapter, 0x210, 0xb2ff);
-	write_reg_dw(adapter, 0x208, 0x40);
-
-	ret = init_dma_queue(adapter);
-	if (ret < 0)
-		goto err_free_irq;
-
-	adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18);
-
-	switch (adapter->b2c2_revision) {
-	case 0x82:
-		printk("%s: FlexCopII(rev.130) chip found\n", __FILE__);
-		break;
-	case 0xc3:
-		printk("%s: FlexCopIIB(rev.195) chip found\n", __FILE__);
-		break;
-	case 0xc0:
-		printk("%s: FlexCopIII(rev.192) chip found\n", __FILE__);
-		break;
-	default:
-		printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision);
-		printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__);
-		ret = -ENODEV;
-		goto err_free_dma_queue;
-		}
-
-	decide_how_many_hw_filters(adapter);
-
-	init_pids(adapter);
-
-	tmp = read_reg_dw(adapter, 0x204);
-
-	write_reg_dw(adapter, 0x204, 0);
-	mdelay(20);
-
-	write_reg_dw(adapter, 0x204, tmp);
-	mdelay(10);
-
-	tmp = read_reg_dw(adapter, 0x308);
-	write_reg_dw(adapter, 0x308, 0x4000 | tmp);
-
-	adapter->dw_sram_type = 0x10000;
-
-	sll_detect_sram_size(adapter);
-
-	dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, sram_length(adapter), adapter->dw_sram_type);
-
-	sram_set_media_dest(adapter, 1);
-	sram_set_net_dest(adapter, 1);
-
-	ctrl_enable_smc(adapter, 0);
-
-	sram_set_cai_dest(adapter, 2);
-	sram_set_cao_dest(adapter, 2);
-
-	dma_enable_disable_irq(adapter, 1, 0, 0);
-
-	if (eeprom_get_mac_addr(adapter, 0, adapter->mac_addr) != 0) {
-		printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0],
-		       adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5],
-		       adapter->mac_addr[6], adapter->mac_addr[7]
-		    );
-
-		ca_set_mac_dst_addr_filter(adapter, adapter->mac_addr);
-		ctrl_enable_mac(adapter, 1);
-	}
-
-	spin_lock_init(&adapter->lock);
-
-out:
-	return ret;
-
-err_free_dma_queue:
-	free_dma_queue(adapter);
-err_free_irq:
-	free_irq(pdev->irq, adapter);
-err_release_adapter:
-	release_adapter(adapter);
-err_kfree:
-	pci_set_drvdata(pdev, NULL);
-	kfree(adapter);
-	goto out;
-}
-
-static void driver_halt(struct pci_dev *pdev)
-{
-	struct adapter *adapter = pci_get_drvdata(pdev);
-
-	irq_dma_enable_disable_irq(adapter, 0);
-
-	ctrl_enable_receive_data(adapter, 0);
-
-	free_adapter_object(adapter);
-
-	pci_set_drvdata(pdev, NULL);
-}
-
-static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct adapter *adapter = (struct adapter *) dvbdmx->priv;
-
-	dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
-
-	open_stream(adapter, dvbdmxfeed->pid);
-
-	return 0;
-}
-
-static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-	struct adapter *adapter = (struct adapter *) dvbdmx->priv;
-
-	dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
-
-	close_stream(adapter, dvbdmxfeed->pid);
-
-	return 0;
-}
-
-/* lnb control */
-static void set_tuner_tone(struct adapter *adapter, u8 tone)
-{
-	u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc };
-	u16 ax;
-
-	dprintk("%s: %u\n", __FUNCTION__, tone);
-
-	switch (tone) {
-	case 1:
-		ax = wz_half_period_for_45_mhz[0];
-		break;
-	case 2:
-		ax = wz_half_period_for_45_mhz[1];
-		break;
-	case 3:
-		ax = wz_half_period_for_45_mhz[2];
-		break;
-	case 4:
-		ax = wz_half_period_for_45_mhz[3];
-		break;
-
-	default:
-		ax = 0;
-	}
-
-	if (ax != 0) {
-		write_reg_dw(adapter, 0x200, ((ax << 0x0f) + (ax & 0x7fff)) | 0x40000000);
-
-	} else {
-
-		write_reg_dw(adapter, 0x200, 0x40ff8000);
-	}
-}
-
-static void set_tuner_polarity(struct adapter *adapter, u8 polarity)
-{
-	u32 var;
-
-	dprintk("%s : polarity = %u \n", __FUNCTION__, polarity);
-
-	var = read_reg_dw(adapter, 0x204);
-
-	if (polarity == 0) {
-		dprintk("%s: LNB power off\n", __FUNCTION__);
-		var = var | 1;
-	};
-
-	if (polarity == 1) {
-		var = var & ~1;
-		var = var & ~4;
-	};
-
-	if (polarity == 2) {
-		var = var & ~1;
-		var = var | 4;
-	}
-
-	write_reg_dw(adapter, 0x204, var);
-}
-
-static void diseqc_send_bit(struct adapter *adapter, int data)
-{
-	set_tuner_tone(adapter, 1);
-	udelay(data ? 500 : 1000);
-	set_tuner_tone(adapter, 0);
-	udelay(data ? 1000 : 500);
-}
-
-
-static void diseqc_send_byte(struct adapter *adapter, int data)
-		{
-	int i, par = 1, d;
-
-	for (i = 7; i >= 0; i--) {
-		d = (data >> i) & 1;
-		par ^= d;
-		diseqc_send_bit(adapter, d);
-	}
-
-	diseqc_send_bit(adapter, par);
-		}
-
-
-static int send_diseqc_msg(struct adapter *adapter, int len, u8 *msg, unsigned long burst)
-{
-	int i;
-
-	set_tuner_tone(adapter, 0);
-	mdelay(16);
-
-	for (i = 0; i < len; i++)
-		diseqc_send_byte(adapter, msg[i]);
-
-	mdelay(16);
-
-	if (burst != -1) {
-		if (burst)
-			diseqc_send_byte(adapter, 0xff);
-		else {
-			set_tuner_tone(adapter, 1);
-			udelay(12500);
-			set_tuner_tone(adapter, 0);
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int flexcop_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	switch(tone) {
-		case SEC_TONE_ON:
-			set_tuner_tone(adapter, 1);
-			break;
-		case SEC_TONE_OFF:
-			set_tuner_tone(adapter, 0);
-				break;
-			default:
-				return -EINVAL;
-			};
-
-	return 0;
-}
-
-static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-		{
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-			send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0);
-
-	return 0;
-		}
-
-static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	send_diseqc_msg(adapter, 0, NULL, minicmd);
-
-	return 0;
-}
-
-static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-		{
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
-
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
-		set_tuner_polarity(adapter, 1);
-		return 0;
-
-	case SEC_VOLTAGE_18:
-		dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
-		set_tuner_polarity(adapter, 2);
-			return 0;
-
-	default:
-		return -EINVAL;
-	}
-	}
-
-static int flexcop_sleep(struct dvb_frontend* fe)
-		{
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	dprintk("%s: FE_SLEEP\n", __FUNCTION__);
-			set_tuner_polarity(adapter, 0);
-
-	if (adapter->fe_sleep) return adapter->fe_sleep(fe);
-	return 0;
-		}
-
-static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
-		{
-	printk("flexcop_i2c_func\n");
-
-	return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm    flexcop_algo = {
-	.name		= "flexcop i2c algorithm",
-	.id		= I2C_ALGO_BIT,
-	.master_xfer	= master_xfer,
-	.functionality	= flexcop_i2c_func,
-};
-
-
-
-
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-	stv0299_writereg (fe, 0x13, aclk);
-	stv0299_writereg (fe, 0x14, bclk);
-	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
-
-	return 0;
-}
-
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	div = params->frequency / 125;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x84;  // 0xC4
-	buf[3] = 0x08;
-
-	if (params->frequency < 1500000) buf[3] |= 0x10;
-
-	if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static u8 samsung_tbmu24112_inittab[] = {
-	     0x01, 0x15,
-	     0x02, 0x30,
-	     0x03, 0x00,
-	     0x04, 0x7D,
-	     0x05, 0x35,
-	     0x06, 0x02,
-	     0x07, 0x00,
-	     0x08, 0xC3,
-	     0x0C, 0x00,
-	     0x0D, 0x81,
-	     0x0E, 0x23,
-	     0x0F, 0x12,
-	     0x10, 0x7E,
-	     0x11, 0x84,
-	     0x12, 0xB9,
-	     0x13, 0x88,
-	     0x14, 0x89,
-	     0x15, 0xC9,
-	     0x16, 0x00,
-	     0x17, 0x5C,
-	     0x18, 0x00,
-	     0x19, 0x00,
-	     0x1A, 0x00,
-	     0x1C, 0x00,
-	     0x1D, 0x00,
-	     0x1E, 0x00,
-	     0x1F, 0x3A,
-	     0x20, 0x2E,
-	     0x21, 0x80,
-	     0x22, 0xFF,
-	     0x23, 0xC1,
-	     0x28, 0x00,
-	     0x29, 0x1E,
-	     0x2A, 0x14,
-	     0x2B, 0x0F,
-	     0x2C, 0x09,
-	     0x2D, 0x05,
-	     0x31, 0x1F,
-	     0x32, 0x19,
-	     0x33, 0xFE,
-	     0x34, 0x93,
-	     0xff, 0xff,
-			};
-
-static struct stv0299_config samsung_tbmu24112_config = {
-	.demod_address = 0x68,
-	.inittab = samsung_tbmu24112_inittab,
-	.mclk = 88000000UL,
-	.invert = 0,
-	.enhanced_tuning = 0,
-	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_LK,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
-   	.pll_set = samsung_tbmu24112_pll_set,
-};
-
-
-
-static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
-{
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	return request_firmware(fw, name, &adapter->pdev->dev);
-}
-
-
-static struct nxt2002_config samsung_tbmv_config = {
-	.demod_address = 0x0A,
-	.request_firmware = nxt2002_request_firmware,
-};
-
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
-{
-	static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
-	static u8 mt352_reset [] = { 0x50, 0x80 };
-	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
-	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	udelay(2000);
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
-	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
-	return 0;
-}
-
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
-{
-	u32 div;
-	unsigned char bs = 0;
-
-	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
-	if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
-	if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
-
-	pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
-	pllbuf[1] = div >> 8;
-   	pllbuf[2] = div & 0xff;
-   	pllbuf[3] = 0xcc;
-   	pllbuf[4] = bs;
-
-	return 0;
-}
-
-static struct mt352_config samsung_tdtc9251dh0_config = {
-
-	.demod_address = 0x0f,
-	.demod_init = samsung_tdtc9251dh0_demod_init,
-   	.pll_set = samsung_tdtc9251dh0_pll_set,
-};
-
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
-	div = (params->frequency + (125/2)) / 125;
-
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = (div >> 0) & 0xff;
-	buf[2] = 0x84 | ((div >> 10) & 0x60);
-	buf[3] = 0x80;
-
-	if (params->frequency < 1550000)
-		buf[3] |= 0x02;
-
-	if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
-	.demod_address = 0x0e,
-   	.pll_set = skystar23_samsung_tbdu18132_pll_set,
-};
-
-
-
-
-static void frontend_init(struct adapter *skystar2)
-{
-	switch(skystar2->pdev->device) {
-	case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC)
-
-		// Attempt to load the Nextwave nxt2002 for ATSC support 
-		skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap);
-		if (skystar2->fe != NULL) {
-			skystar2->fe_sleep = skystar2->fe->ops->sleep;
-			skystar2->fe->ops->sleep = flexcop_sleep;
-			break;
-		}
-
-		// try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935))
-		skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap);
-		if (skystar2->fe != NULL) {
-			skystar2->fe->ops->set_voltage = flexcop_set_voltage;
-			skystar2->fe_sleep = skystar2->fe->ops->sleep;
-			skystar2->fe->ops->sleep = flexcop_sleep;
-			break;
-}
-
-		// try the airstar2 (mt352/Samsung tdtc9251dh0(??))
-		skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap);
-		if (skystar2->fe != NULL) {
-			skystar2->fe->ops->info.frequency_min = 474000000;
-			skystar2->fe->ops->info.frequency_max = 858000000;
-			break;
-		}
-
-		// try the skystar2 v2.3 (vp310/Samsung tbdu18132(tsa5059))
-		skystar2->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &skystar2->i2c_adap);
-		if (skystar2->fe != NULL) {
-			skystar2->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-			skystar2->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
-			skystar2->fe->ops->set_tone = flexcop_set_tone;
-			skystar2->fe->ops->set_voltage = flexcop_set_voltage;
-			skystar2->fe_sleep = skystar2->fe->ops->sleep;
-			skystar2->fe->ops->sleep = flexcop_sleep;
-			break;
-		}
-		break;
-	}
-
-	if (skystar2->fe == NULL) {
-		printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
-		       skystar2->pdev->vendor,
-		       skystar2->pdev->device,
-		       skystar2->pdev->subsystem_vendor,
-		       skystar2->pdev->subsystem_device);
-	} else {
-		if (dvb_register_frontend(&skystar2->dvb_adapter, skystar2->fe)) {
-			printk("skystar2: Frontend registration failed!\n");
-			if (skystar2->fe->ops->release)
-				skystar2->fe->ops->release(skystar2->fe);
-			skystar2->fe = NULL;
-		}
-	}
-}
-
-
-static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	struct adapter *adapter;
-	struct dvb_adapter *dvb_adapter;
-	struct dvb_demux *dvbdemux;
-	struct dmx_demux *dmx;
-	int ret = -ENODEV;
-
-	if (!pdev)
-		goto out;
-
-	ret = driver_initialize(pdev);
-	if (ret < 0)
-		goto out;
-
-	adapter = pci_get_drvdata(pdev);
-	dvb_adapter = &adapter->dvb_adapter;
-
-	ret = dvb_register_adapter(dvb_adapter, skystar2_pci_driver.name,
-				   THIS_MODULE);
-	if (ret < 0) {
-		printk("%s: Error registering DVB adapter\n", __FUNCTION__);
-		goto err_halt;
-	}
-
-	dvb_adapter->priv = adapter;
-
-
-	init_MUTEX(&adapter->i2c_sem);
-
-
-	memset(&adapter->i2c_adap, 0, sizeof(struct i2c_adapter));
-	strcpy(adapter->i2c_adap.name, "SkyStar2");
-
-	i2c_set_adapdata(&adapter->i2c_adap, adapter);
-
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
-	adapter->i2c_adap.class 	    = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
-	adapter->i2c_adap.class 	    = I2C_CLASS_TV_DIGITAL;
-#endif
-	adapter->i2c_adap.algo              = &flexcop_algo;
-	adapter->i2c_adap.algo_data         = NULL;
-	adapter->i2c_adap.id                = I2C_ALGO_BIT;
-
-	ret = i2c_add_adapter(&adapter->i2c_adap);
-	if (ret < 0)
-		goto err_dvb_unregister;
-
-	dvbdemux = &adapter->demux;
-
-	dvbdemux->priv = adapter;
-	dvbdemux->filternum = N_PID_SLOTS;
-	dvbdemux->feednum = N_PID_SLOTS;
-	dvbdemux->start_feed = dvb_start_feed;
-	dvbdemux->stop_feed = dvb_stop_feed;
-	dvbdemux->write_to_decoder = NULL;
-	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
-
-	ret = dvb_dmx_init(&adapter->demux);
-	if (ret < 0)
-		goto err_i2c_del;
-
-	dmx = &dvbdemux->dmx;
-
-	adapter->hw_frontend.source = DMX_FRONTEND_0;
-	adapter->dmxdev.filternum = N_PID_SLOTS;
-	adapter->dmxdev.demux = dmx;
-	adapter->dmxdev.capabilities = 0;
-
-	ret = dvb_dmxdev_init(&adapter->dmxdev, &adapter->dvb_adapter);
-	if (ret < 0)
-		goto err_dmx_release;
-
-	ret = dmx->add_frontend(dmx, &adapter->hw_frontend);
-	if (ret < 0)
-		goto err_dmxdev_release;
-
-	adapter->mem_frontend.source = DMX_MEMORY_FE;
-
-	ret = dmx->add_frontend(dmx, &adapter->mem_frontend);
-	if (ret < 0)
-		goto err_remove_hw_frontend;
-
-	ret = dmx->connect_frontend(dmx, &adapter->hw_frontend);
-	if (ret < 0)
-		goto err_remove_mem_frontend;
-
-	dvb_net_init(&adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
-
-	frontend_init(adapter);
-out:
-	return ret;
-
-err_remove_mem_frontend:
-	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
-err_remove_hw_frontend:
-	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
-err_dmxdev_release:
-	dvb_dmxdev_release(&adapter->dmxdev);
-err_dmx_release:
-	dvb_dmx_release(&adapter->demux);
-err_i2c_del:
-	i2c_del_adapter(&adapter->i2c_adap);
-err_dvb_unregister:
-	dvb_unregister_adapter(&adapter->dvb_adapter);
-err_halt:
-	driver_halt(pdev);
-	goto out;
-}
-
-static void skystar2_remove(struct pci_dev *pdev)
-{
-	struct adapter *adapter = pci_get_drvdata(pdev);
-	struct dvb_demux *dvbdemux;
-	struct dmx_demux *dmx;
-
-	if (!adapter)
-		return;
-
-		dvb_net_release(&adapter->dvbnet);
-		dvbdemux = &adapter->demux;
-	dmx = &dvbdemux->dmx;
-
-	dmx->close(dmx);
-	dmx->remove_frontend(dmx, &adapter->hw_frontend);
-	dmx->remove_frontend(dmx, &adapter->mem_frontend);
-
-		dvb_dmxdev_release(&adapter->dmxdev);
-	dvb_dmx_release(dvbdemux);
-
-	if (adapter->fe != NULL)
-		dvb_unregister_frontend(adapter->fe);
-
-	dvb_unregister_adapter(&adapter->dvb_adapter);
-
-			i2c_del_adapter(&adapter->i2c_adap);
-
-		driver_halt(pdev);
-	}
-
-static struct pci_device_id skystar2_pci_tbl[] = {
-	{0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
-/*	{0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */	//FCIII
-	{0,},
-};
-
-MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl);
-
-static struct pci_driver skystar2_pci_driver = {
-	.name = "SkyStar2",
-	.id_table = skystar2_pci_tbl,
-	.probe = skystar2_probe,
-	.remove = skystar2_remove,
-};
-
-static int skystar2_init(void)
-{
-	return pci_register_driver(&skystar2_pci_driver);
-}
-
-static void skystar2_cleanup(void)
-{
-	pci_unregister_driver(&skystar2_pci_driver);
-}
-
-module_init(skystar2_init);
-module_exit(skystar2_cleanup);
-
-MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 1339912..9bd1283 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -258,10 +258,10 @@
 	if (debug && (verbose > 4)) {
 		u8 i;
 		if (verbose > 4) {
-			dprintk("%s writing", __FUNCTION__);
+			dprintk("%s writing [ ", __FUNCTION__);
 			for (i = 0; i < len; i++)
-				dprintk(" %02x", data[i]);
-			dprintk("\n");
+				dprintk("%02x ", data[i]);
+			dprintk("]\n");
 		}
 	}
 	for (cnt = 0; cnt < 2; cnt++) {
@@ -320,10 +320,29 @@
 }
 EXPORT_SYMBOL(read_dst);
 
+static int dst_set_polarization(struct dst_state *state)
+{
+	switch (state->voltage) {
+		case SEC_VOLTAGE_13:	// vertical
+			printk("%s: Polarization=[Vertical]\n", __FUNCTION__);
+			state->tx_tuna[8] &= ~0x40;  //1
+			break;
+
+		case SEC_VOLTAGE_18:	// horizontal
+			printk("%s: Polarization=[Horizontal]\n", __FUNCTION__);
+			state->tx_tuna[8] |= 0x40;  // 0
+			break;
+
+		case SEC_VOLTAGE_OFF:
+
+			break;
+	}
+
+	return 0;
+}
+
 static int dst_set_freq(struct dst_state *state, u32 freq)
 {
-	u8 *val;
-
 	state->frequency = freq;
 	if (debug > 4)
 		dprintk("%s: set Frequency %u\n", __FUNCTION__, freq);
@@ -332,46 +351,30 @@
 		freq = freq / 1000;
 		if (freq < 950 || freq > 2150)
 			return -EINVAL;
-		val = &state->tx_tuna[0];
-		val[2] = (freq >> 8) & 0x7f;
-		val[3] = (u8) freq;
-		val[4] = 1;
-		val[8] &= ~4;
-		if (freq < 1531)
-			val[8] |= 4;
+
+		state->tx_tuna[2] = (freq >> 8);
+		state->tx_tuna[3] = (u8) freq;
+		state->tx_tuna[4] = 0x01;
+		state->tx_tuna[8] &= ~0x04;
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+			if (freq < 1531)
+				state->tx_tuna[8] |= 0x04;
+		}
+
 	} else if (state->dst_type == DST_TYPE_IS_TERR) {
 		freq = freq / 1000;
 		if (freq < 137000 || freq > 858000)
 			return -EINVAL;
-		val = &state->tx_tuna[0];
-		val[2] = (freq >> 16) & 0xff;
-		val[3] = (freq >> 8) & 0xff;
-		val[4] = (u8) freq;
-		val[5] = 0;
-		switch (state->bandwidth) {
-		case BANDWIDTH_6_MHZ:
-			val[6] = 6;
-			break;
 
-		case BANDWIDTH_7_MHZ:
-		case BANDWIDTH_AUTO:
-			val[6] = 7;
-			break;
+		state->tx_tuna[2] = (freq >> 16) & 0xff;
+		state->tx_tuna[3] = (freq >> 8) & 0xff;
+		state->tx_tuna[4] = (u8) freq;
 
-		case BANDWIDTH_8_MHZ:
-			val[6] = 8;
-			break;
-		}
-
-		val[7] = 0;
-		val[8] = 0;
 	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
-		/* guess till will get one */
-		freq = freq / 1000;
-		val = &state->tx_tuna[0];
-		val[2] = (freq >> 16) & 0xff;
-		val[3] = (freq >> 8) & 0xff;
-		val[4] = (u8) freq;
+		state->tx_tuna[2] = (freq >> 16) & 0xff;
+		state->tx_tuna[3] = (freq >> 8) & 0xff;
+		state->tx_tuna[4] = (u8) freq;
+
 	} else
 		return -EINVAL;
 	return 0;
@@ -379,51 +382,58 @@
 
 static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth)
 {
-	u8 *val;
-
 	state->bandwidth = bandwidth;
 
 	if (state->dst_type != DST_TYPE_IS_TERR)
 		return 0;
 
-	val = &state->tx_tuna[0];
 	switch (bandwidth) {
-	case BANDWIDTH_6_MHZ:
-		val[6] = 6;
-		break;
+		case BANDWIDTH_6_MHZ:
+			if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+				state->tx_tuna[7] = 0x06;
+			else {
+				state->tx_tuna[6] = 0x06;
+				state->tx_tuna[7] = 0x00;
+			}
+			break;
 
-	case BANDWIDTH_7_MHZ:
-		val[6] = 7;
-		break;
+		case BANDWIDTH_7_MHZ:
+			if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+				state->tx_tuna[7] = 0x07;
+			else {
+				state->tx_tuna[6] = 0x07;
+				state->tx_tuna[7] = 0x00;
+			}
+			break;
 
-	case BANDWIDTH_8_MHZ:
-		val[6] = 8;
-		break;
+		case BANDWIDTH_8_MHZ:
+			if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+				state->tx_tuna[7] = 0x08;
+			else {
+				state->tx_tuna[6] = 0x08;
+				state->tx_tuna[7] = 0x00;
+			}
+			break;
 
-	default:
-		return -EINVAL;
+		default:
+			return -EINVAL;
 	}
 	return 0;
 }
 
 static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion)
 {
-	u8 *val;
-
 	state->inversion = inversion;
-
-	val = &state->tx_tuna[0];
-
-	val[8] &= ~0x80;
-
 	switch (inversion) {
-	case INVERSION_OFF:
-		break;
-	case INVERSION_ON:
-		val[8] |= 0x80;
-		break;
-	default:
-		return -EINVAL;
+		case INVERSION_OFF:	// Inversion = Normal
+			state->tx_tuna[8] &= ~0x80;
+			break;
+
+		case INVERSION_ON:
+			state->tx_tuna[8] |= 0x80;
+			break;
+		default:
+			return -EINVAL;
 	}
 	return 0;
 }
@@ -478,6 +488,52 @@
 	return 0;
 }
 
+
+static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
+{
+	if (state->dst_type != DST_TYPE_IS_CABLE)
+		return 0;
+
+	state->modulation = modulation;
+	switch (modulation) {
+		case QAM_16:
+			state->tx_tuna[8] = 0x10;
+			break;
+
+		case QAM_32:
+			state->tx_tuna[8] = 0x20;
+			break;
+
+		case QAM_64:
+			state->tx_tuna[8] = 0x40;
+			break;
+
+		case QAM_128:
+			state->tx_tuna[8] = 0x80;
+			break;
+
+		case QAM_256:
+			state->tx_tuna[8] = 0x00;
+			break;
+
+		case QPSK:
+		case QAM_AUTO:
+		case VSB_8:
+		case VSB_16:
+		default:
+			return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+static fe_modulation_t dst_get_modulation(struct dst_state *state)
+{
+	return state->modulation;
+}
+
+
 u8 dst_check_sum(u8 * buf, u32 len)
 {
 	u32 i;
@@ -577,7 +633,7 @@
 		.device_id = "200103A",
 		.offset = 0,
 		.dst_type =  DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
 		.dst_feature = 0
 	},	/*	obsolete	*/
 
@@ -626,7 +682,7 @@
 		.device_id = "DSTMCI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
 		.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
 							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
 	},
@@ -872,7 +928,7 @@
 {
 	int retval;
 	u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
-
+	printk("%s: Getting Signal strength and other parameters !!!!!!!!\n", __FUNCTION__);
 	if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
 		state->decode_lock = state->decode_strength = state->decode_snr = 0;
 		return 0;
@@ -954,15 +1010,8 @@
 	state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
 
 	state->decode_lock = 1;
-	/*
-	   dst->decode_n1 = (dst->rx_tuna[4] << 8) +
-	   (dst->rx_tuna[5]);
-
-	   dst->decode_n2 = (dst->rx_tuna[8] << 8) +
-	   (dst->rx_tuna[7]);
-	 */
 	state->diseq_flags |= HAS_LOCK;
-	/* dst->cur_jiff = jiffies; */
+
 	return 1;
 }
 
@@ -1098,7 +1147,11 @@
 
 	switch (tone) {
 		case SEC_TONE_OFF:
-			state->tx_tuna[2] = 0xff;
+			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+			    state->tx_tuna[2] = 0x00;
+			else
+			    state->tx_tuna[2] = 0xff;
+
 			break;
 
 		case SEC_TONE_ON:
@@ -1145,7 +1198,8 @@
 	static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
 	static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
 	static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
-	state->inversion = INVERSION_ON;
+//	state->inversion = INVERSION_ON;
+	state->inversion = INVERSION_OFF;
 	state->voltage = SEC_VOLTAGE_13;
 	state->tone = SEC_TONE_OFF;
 	state->symbol_rate = 29473000;
@@ -1174,7 +1228,7 @@
 
 	*status = 0;
 	if (state->diseq_flags & HAS_LOCK) {
-		dst_get_signal(state);
+//		dst_get_signal(state);	// don't require(?) to ask MCU
 		if (state->decode_lock)
 			*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
 	}
@@ -1208,20 +1262,25 @@
 
 	dst_set_freq(state, p->frequency);
 	if (verbose > 4)
-		dprintk("Set Frequency = [%d]\n", p->frequency);
+		dprintk("Set Frequency=[%d]\n", p->frequency);
 
-	dst_set_inversion(state, p->inversion);
+//	dst_set_inversion(state, p->inversion);
 	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+			dst_set_inversion(state, p->inversion);
+
 		dst_set_fec(state, p->u.qpsk.fec_inner);
 		dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+		dst_set_polarization(state);
 		if (verbose > 4)
-			dprintk("Set Symbolrate = [%d]\n", p->u.qpsk.symbol_rate);
+			dprintk("Set Symbolrate=[%d]\n", p->u.qpsk.symbol_rate);
 
 	} else if (state->dst_type == DST_TYPE_IS_TERR) {
 		dst_set_bandwidth(state, p->u.ofdm.bandwidth);
 	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
 		dst_set_fec(state, p->u.qam.fec_inner);
 		dst_set_symbolrate(state, p->u.qam.symbol_rate);
+		dst_set_modulation(state, p->u.qam.modulation);
 	}
 	dst_write_tuna(fe);
 
@@ -1233,8 +1292,11 @@
 	struct dst_state* state = fe->demodulator_priv;
 
 	p->frequency = state->decode_freq;
-	p->inversion = state->inversion;
+//	p->inversion = state->inversion;
 	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+			p->inversion = state->inversion;
+
 		p->u.qpsk.symbol_rate = state->symbol_rate;
 		p->u.qpsk.fec_inner = dst_get_fec(state);
 	} else if (state->dst_type == DST_TYPE_IS_TERR) {
@@ -1242,7 +1304,8 @@
 	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
 		p->u.qam.symbol_rate = state->symbol_rate;
 		p->u.qam.fec_inner = dst_get_fec(state);
-		p->u.qam.modulation = QAM_AUTO;
+//		p->u.qam.modulation = QAM_AUTO;
+		p->u.qam.modulation = dst_get_modulation(state);
 	}
 
 	return 0;
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index d781504..bfaacd5 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -32,7 +32,7 @@
 #include "dst_ca.h"
 #include "dst_common.h"
 
-static unsigned int verbose = 1;
+static unsigned int verbose = 5;
 module_param(verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
 
@@ -295,34 +295,28 @@
 	return 0;
 }
 
-static int handle_en50221_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
+static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
 {
 	if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
 		hw_buffer->msg[2] = p_ca_message->msg[1];		/*		MSB			*/
 		hw_buffer->msg[3] = p_ca_message->msg[2];		/*		LSB			*/
 	}
 	else {
+		hw_buffer->msg[0] = (length & 0xff) + 7;
+		hw_buffer->msg[1] = 0x40;
 		hw_buffer->msg[2] = 0x03;
 		hw_buffer->msg[3] = 0x00;
+		hw_buffer->msg[4] = 0x03;
+		hw_buffer->msg[5] = length & 0xff;
+		hw_buffer->msg[6] = 0x00;
 	}
 	return 0;
 }
 
-static int debug_8820_buffer(struct ca_msg *hw_buffer)
+
+static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
 {
-	unsigned int i;
-
-	dprintk("%s:Debug=[", __FUNCTION__);
-	for (i = 0; i < (hw_buffer->msg[0] + 1); i++)
-		dprintk(" %02x", hw_buffer->msg[i]);
-	dprintk("]\n");
-
-	return 0;
-}
-
-static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply)
-{
-	if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) {
+	if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
 		dprintk("%s: DST-CI Command failed.\n", __FUNCTION__);
 		dprintk("%s: Resetting DST.\n", __FUNCTION__);
 		rdc_reset_state(state);
@@ -334,234 +328,141 @@
 	return 0;
 }
 
-
-static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+u32 asn_1_decode(u8 *asn_1_array)
 {
-	u32 hw_offset, buf_offset, i, k;
-	u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0;
-	u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0;
+	u8 length_field = 0, word_count = 0, count = 0;
+	u32 length = 0;
 
-	if (verbose > 3)
-		dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length );
-
-	handle_en50221_tag(state, p_ca_message, hw_buffer);			/*	EN50221 tag		*/
-
-	/*	Handle the length field (variable)	*/
-	if (!(p_ca_message->msg[3] & 0x80)) {				/*	Length = 1		*/
-		length = p_ca_message->msg[3] & 0x7f;
-		words = 0;						/*	domi's suggestion	*/
-	}
-	else {								/*	Length = words		*/
-		words = p_ca_message->msg[3] & 0x7f;
-		for (i = 0; i < words; i++) {
-			length = length << 8;
-			length = length | p_ca_message->msg[4 + i];
+	length_field = asn_1_array[0];
+	dprintk("%s: Length field=[%02x]\n", __FUNCTION__, length_field);
+	if (length_field < 0x80) {
+		length = length_field & 0x7f;
+		dprintk("%s: Length=[%02x]\n", __FUNCTION__, length);
+	} else {
+		word_count = length_field & 0x7f;
+		for (count = 0; count < word_count; count++) {
+			length = (length | asn_1_array[count + 1]) << 8;
+			dprintk("%s: Length=[%04x]\n", __FUNCTION__, length);
 		}
 	}
-	if (verbose > 4) {
-		dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words);
+	return length;
+}
 
-		/*	Debug Input string		*/
-		for (i = 0; i < length; i++)
-			dprintk(" %02x", p_ca_message->msg[i]);
-		dprintk("]\n");
-	}
-
-	hw_offset = 7;
-	buf_offset = words + 4;
-
-	/*		Program Header			*/
-	if (verbose > 4)
-		dprintk("\n%s:Program Header=[", __FUNCTION__);
-	for (i = 0; i < 6; i++) {
-		hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
-		if (verbose > 4)
-			dprintk(" %02x", p_ca_message->msg[buf_offset]);
-		hw_offset++, buf_offset++, hw_buffer_length++;
-	}
-	if (verbose > 4)
-		dprintk("]\n");
-
-	program_info_length = 0;
-	program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9];
-	if (verbose > 4)
-		dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n",
-			__FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset);
-
-	if (program_info_length && (program_info_length < 256)) {	/*	If program_info_length		*/
-		hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f;		/*	req only 4 bits			*/
-		hw_buffer->msg[12] = hw_buffer->msg[12] + 1;		/*	increment! ASIC bug!		*/
-
-		if (p_ca_message->msg[buf_offset + 1] == 0x09) {	/*	Check CA descriptor		*/
-			found_prog_ca_desc = 1;
-			if (verbose > 4)
-				dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__);
-		}
-
-		if (found_prog_ca_desc) {				/*	Command only if CA descriptor	*/
-			hw_buffer->msg[13] = p_ca_message->msg[buf_offset];	/*	CA PMT command ID	*/
-			hw_offset++, buf_offset++, hw_buffer_length++;
-		}
-
-		/*			Program descriptors				*/
-		if (verbose > 4) {
-			dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
-			dprintk("%s:Program descriptors=[", __FUNCTION__);
-		}
-		while (program_info_length && !error_condition) {		/*	Copy prog descriptors	*/
-			if (program_info_length > p_ca_message->length) {	/*	Error situation		*/
-				dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n",
-								__FUNCTION__, __LINE__, program_info_length);
-				dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
-				error_condition = 1;
-				break;
-			}
-
-			hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
-			dprintk(" %02x", p_ca_message->msg[buf_offset]);
-			hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--;
-		}
-		if (verbose > 4) {
-			dprintk("]\n");
-			dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
-		}
-		if (found_prog_ca_desc) {
-			if (!reply) {
-				hw_buffer->msg[13] = 0x01;		/*	OK descrambling			*/
-				if (verbose > 1)
-					dprintk("CA PMT Command = OK Descrambling\n");
-			}
-			else {
-				hw_buffer->msg[13] = 0x02;		/*	Ok MMI				*/
-				if (verbose > 1)
-					dprintk("CA PMT Command = Ok MMI\n");
-			}
-			if (query) {
-				hw_buffer->msg[13] = 0x03;		/*	Query				*/
-				if (verbose > 1)
-					dprintk("CA PMT Command = CA PMT query\n");
-			}
-		}
-	}
-	else {
-		hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0;		/*	Don't write to ASIC		*/
-		hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00;
-	}
-	if (verbose > 4)
-		dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n",
-					__FUNCTION__, p_ca_message->length, buf_offset, hw_offset);
-
-	while ((buf_offset  < p_ca_message->length)  && !error_condition) {
-		/*	Bail out in case of an indefinite loop		*/
-		if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
-			dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n",
-							__FUNCTION__, __LINE__, program_info_length, buf_offset);
-
-			dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
-			error_condition = 1;
-			break;
-		}
-
-		/*		Stream Header				*/
-
-		for (k = 0; k < 5; k++) {
-			hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k];
-		}
-
-		es_info_length = 0;
-		es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4];
-
-		if (verbose > 4) {
-			dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__,
-				p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1],
-				p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3],
-				p_ca_message->msg[buf_offset + 4]);
-
-			dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__,
-				p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length,
-				p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset);
-		}
-
-		hw_buffer->msg[hw_offset + 3] &= 0x0f;			/*	req only 4 bits			*/
-
-		if (found_prog_ca_desc) {
-			hw_buffer->msg[hw_offset + 3] = 0x00;
-			hw_buffer->msg[hw_offset + 4] = 0x00;
-		}
-
-		hw_offset += 5, buf_offset += 5, hw_buffer_length += 5;
-
-		/*		Check for CA descriptor			*/
-		if (p_ca_message->msg[buf_offset + 1] == 0x09) {
-			if (verbose > 4)
-				dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__);
-			found_stream_ca_desc = 1;
-		}
-
-		/*		ES descriptors				*/
-
-		if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) {
-//			if (!ca_pmt_done) {
-				hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];	/*	CA PMT cmd(es)	*/
-				if (verbose > 4)
-					printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]);
-//				hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1;
-				hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
-//			}
-			if (verbose > 4)
-				dprintk("%s:----->ES descriptors=[", __FUNCTION__);
-
-			while (es_info_length && !error_condition) {	/*	ES descriptors			*/
-				if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
-					if (verbose > 4) {
-						dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n",
-										__FUNCTION__, __LINE__, es_info_length, buf_offset);
-
-						dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
-					}
-					error_condition = 1;
-					break;
-				}
-
-				hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
-				if (verbose > 3)
-					dprintk("%02x ", hw_buffer->msg[hw_offset]);
-				hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
-			}
-			found_stream_ca_desc = 0;			/*	unset for new streams		*/
-			dprintk("]\n");
-		}
-	}
-
-	/*		MCU Magic words					*/
-
-	hw_buffer_length += 7;
-	hw_buffer->msg[0] = hw_buffer_length;
-	hw_buffer->msg[1] = 64;
-	hw_buffer->msg[4] = 3;
-	hw_buffer->msg[5] = hw_buffer->msg[0] - 7;
-	hw_buffer->msg[6] = 0;
-
-
-	/*      Fix length      */
-	hw_buffer->length = hw_buffer->msg[0];
-
-	put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]);
-	/*      Do the actual write     */
-	if (verbose > 4) {
-		dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__);
-		dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length);
-	}
-	/*      Only for debugging!     */
-	if (verbose > 2)
-		debug_8820_buffer(hw_buffer);
-	if (verbose > 3)
-		dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply);
-	write_to_8820(state, hw_buffer, reply);
+static int init_buffer(u8 *buffer, u32 length)
+{
+	u32 i;
+	for (i = 0; i < length; i++)
+		buffer[i] = 0;
 
 	return 0;
 }
 
+static int debug_string(u8 *msg, u32 length, u32 offset)
+{
+	u32 i;
+
+	dprintk(" String=[ ");
+	for (i = offset; i < length; i++)
+		dprintk("%02x ", msg[i]);
+	dprintk("]\n");
+
+	return 0;
+}
+
+static int copy_string(u8 *destination, u8 *source, u32 dest_offset, u32 source_offset, u32 length)
+{
+	u32 i;
+	dprintk("%s: Copying [", __FUNCTION__);
+	for (i = 0; i < length; i++) {
+		destination[i + dest_offset] = source[i + source_offset];
+		dprintk(" %02x", source[i + source_offset]);
+	}
+	dprintk("]\n");
+
+	return i;
+}
+
+static int modify_4_bits(u8 *message, u32 pos)
+{
+	message[pos] &= 0x0f;
+
+	return 0;
+}
+
+
+
+static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+{
+	u32 length = 0, count = 0;
+	u8 asn_1_words, program_header_length;
+	u16 program_info_length = 0, es_info_length = 0;
+	u32 hw_offset = 0, buf_offset = 0, i;
+	u8 dst_tag_length;
+
+	length = asn_1_decode(&p_ca_message->msg[3]);
+	dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length);
+	dprintk("%s: ASN.1 ", __FUNCTION__);
+	debug_string(&p_ca_message->msg[4], length, 0); // length does not include tag and length
+
+	init_buffer(hw_buffer->msg, length);
+	handle_dst_tag(state, p_ca_message, hw_buffer, length);
+
+	hw_offset = 7;
+	asn_1_words = 1; // just a hack to test, should compute this one
+	buf_offset = 3;
+	program_header_length = 6;
+	dst_tag_length = 7;
+
+//	debug_twinhan_ca_params(state, p_ca_message, hw_buffer, reply, query, length, hw_offset, buf_offset);
+//	dprintk("%s: Program Header(BUF)", __FUNCTION__);
+//	debug_string(&p_ca_message->msg[4], program_header_length, 0);
+//	dprintk("%s: Copying Program header\n", __FUNCTION__);
+	copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + asn_1_words), program_header_length);
+	buf_offset += program_header_length, hw_offset += program_header_length;
+	modify_4_bits(hw_buffer->msg, (hw_offset - 2));
+	if (state->type_flags & DST_TYPE_HAS_INC_COUNT) {	// workaround
+		dprintk("%s: Probably an ASIC bug !!!\n", __FUNCTION__);
+		debug_string(hw_buffer->msg, (hw_offset + program_header_length), 0);
+		hw_buffer->msg[hw_offset - 1] += 1;
+	}
+
+//	dprintk("%s: Program Header(HW), Count=[%d]", __FUNCTION__, count);
+//	debug_string(hw_buffer->msg, hw_offset, 0);
+
+	program_info_length =  ((program_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset];
+	dprintk("%s: Program info length=[%02x]\n", __FUNCTION__, program_info_length);
+	if (program_info_length) {
+		count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + 1), (program_info_length + 1) ); // copy next elem, not current
+		buf_offset += count, hw_offset += count;
+//		dprintk("%s: Program level ", __FUNCTION__);
+//		debug_string(hw_buffer->msg, hw_offset, 0);
+	}
+
+	buf_offset += 1;// hw_offset += 1;
+	for (i = buf_offset; i < length; i++) {
+//		dprintk("%s: Stream Header ", __FUNCTION__);
+		count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, buf_offset, 5);
+		modify_4_bits(hw_buffer->msg, (hw_offset + 3));
+
+		hw_offset += 5, buf_offset += 5, i += 4;
+//		debug_string(hw_buffer->msg, hw_offset, (hw_offset - 5));
+		es_info_length = ((es_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset];
+		dprintk("%s: ES info length=[%02x]\n", __FUNCTION__, es_info_length);
+		if (es_info_length) {
+			// copy descriptors @ STREAM level
+			dprintk("%s: Descriptors @ STREAM level...!!! \n", __FUNCTION__);
+		}
+
+	}
+	hw_buffer->msg[length + dst_tag_length] = dst_check_sum(hw_buffer->msg, (length + dst_tag_length));
+//	dprintk("%s: Total length=[%d], Checksum=[%02x]\n", __FUNCTION__, (length + dst_tag_length), hw_buffer->msg[length + dst_tag_length]);
+	debug_string(hw_buffer->msg, (length + dst_tag_length + 1), 0);	// dst tags also
+	write_to_8820(state, hw_buffer, (length + dst_tag_length + 1), reply);	// checksum
+
+	return 0;
+}
+
+
 /*	Board supports CA PMT reply ?		*/
 static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
 {
@@ -605,7 +506,7 @@
 	struct ca_msg *hw_buffer;
 
 	if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
-		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		dprintk("%s: Memory allocation failure\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	if (verbose > 3)
@@ -630,8 +531,10 @@
 		switch (command) {
 			case CA_PMT:
 				if (verbose > 3)
+//					dprintk("Command = SEND_CA_PMT\n");
 					dprintk("Command = SEND_CA_PMT\n");
-				if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
+//				if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
+				if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {	// code simplification started
 					dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__);
 					return -1;
 				}
@@ -664,7 +567,7 @@
 					return -1;
 				}
 				if (verbose > 3)
-					printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
+					dprintk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
 
 				break;
 		}
@@ -681,17 +584,17 @@
 	struct ca_msg *p_ca_message;
 
 	if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
-		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		dprintk("%s: Memory allocation failure\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
 	if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
-		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		dprintk("%s: Memory allocation failure\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
 	if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
-		printk("%s: Memory allocation failure\n", __FUNCTION__);
+		dprintk("%s: Memory allocation failure\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 0b3da29..ef532a6 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -47,6 +47,8 @@
 #define DST_TYPE_HAS_FW_2	16
 #define DST_TYPE_HAS_FW_3	32
 #define DST_TYPE_HAS_FW_BUILD	64
+#define DST_TYPE_HAS_OBS_REGS	128
+#define DST_TYPE_HAS_INC_COUNT	256
 
 /*	Card capability list	*/
 
@@ -110,6 +112,7 @@
 	u32 dst_hw_cap;
 	u8 dst_fw_version;
 	fe_sec_mini_cmd_t minicmd;
+	fe_modulation_t modulation;
 	u8 messages[256];
 };
 
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 96c57fd..7d8b3ca 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -699,6 +699,8 @@
 	for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) {
 		int i;
 
+/*		dprintk(1,"rc_events[%d].value = %x, type=%x\n",n,le32_to_cpu(rc_events[n].value),rc_events[n].type);*/
+
 		if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
 		    rc_events[n].value == ~0)
 		{
@@ -714,7 +716,7 @@
 			cinergyt2->rc_input_event = KEY_MAX;
 			for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) {
 				if (rc_keys[i+0] == rc_events[n].type &&
-				    rc_keys[i+1] == rc_events[n].value)
+				    rc_keys[i+1] == le32_to_cpu(rc_events[n].value))
 				{
 					cinergyt2->rc_input_event = rc_keys[i+2];
 					break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index c225de7..68050cd 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -42,12 +42,6 @@
 
 #define dprintk	if (debug) printk
 
-static inline struct dmxdev_filter *
-dvb_dmxdev_file_to_filter(struct file *file)
-{
-	return (struct dmxdev_filter *) file->private_data;
-}
-
 static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
 {
 	buffer->data=NULL;
@@ -669,8 +663,10 @@
 
 		ret = filter->feed.ts->start_filtering(filter->feed.ts);
 
-		if (ret < 0)
+		if (ret < 0) {
+			dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
 			return ret;
+		}
 
 		break;
 	}
@@ -842,7 +838,7 @@
 static ssize_t
 dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-	struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
+	struct dmxdev_filter *dmxdevfilter= file->private_data;
 	int ret=0;
 
 	if (down_interruptible(&dmxdevfilter->mutex))
@@ -863,7 +859,7 @@
 static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
 			      unsigned int cmd, void *parg)
 {
-	struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	struct dmxdev *dmxdev=dmxdevfilter->dev;
 	unsigned long arg=(unsigned long) parg;
 	int ret=0;
@@ -960,7 +956,7 @@
 
 static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
 {
-	struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	unsigned int mask = 0;
 
 	if (!dmxdevfilter)
@@ -985,7 +981,7 @@
 
 static int dvb_demux_release(struct inode *inode, struct file *file)
 {
-	struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	struct dmxdev *dmxdev = dmxdevfilter->dev;
 
 	return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
@@ -1109,7 +1105,6 @@
 		dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
 		dmxdev->dvr[i].dev=dmxdev;
 		dmxdev->dvr[i].buffer.data=NULL;
-		dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
 		dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
 	}
 
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index f11daae..a8bc842 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -42,6 +42,8 @@
 #include "dvb_frontend.h"
 #include "dvbdev.h"
 
+// #define DEBUG_LOCKLOSS 1
+
 static int dvb_frontend_debug;
 static int dvb_shutdown_timeout = 5;
 static int dvb_force_auto_inversion;
@@ -113,6 +115,7 @@
 	int exit;
 	int wakeup;
 	fe_status_t status;
+	fe_sec_tone_mode_t tone;
 };
 
 
@@ -434,9 +437,26 @@
 			/* we're tuned, and the lock is still good... */
 			if (s & FE_HAS_LOCK)
 				continue;
-			else {
-				/* if we _WERE_ tuned, but now don't have a lock,
-				 * need to zigzag */
+			else { /* if we _WERE_ tuned, but now don't have a lock */
+#ifdef DEBUG_LOCKLOSS
+				/* first of all try setting the tone again if it was on - this
+				 * sometimes works around problems with noisy power supplies */
+				if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) {
+					fe->ops->set_tone(fe, fepriv->tone);
+					mdelay(100);
+					s = 0;
+					fe->ops->read_status(fe, &s);
+					if (s & FE_HAS_LOCK) {
+						printk("DVB%i: Lock was lost, but regained by setting "
+						       "the tone. This may indicate your power supply "
+						       "is noisy/slightly incompatable with this DVB-S "
+						       "adapter\n", fe->dvb->num);
+						fepriv->state = FESTATE_TUNED;
+						continue;
+					}
+				}
+#endif
+				/* some other reason for losing the lock - start zigzagging */
 				fepriv->state = FESTATE_ZIGZAG_FAST;
 				fepriv->started_auto_step = fepriv->auto_step;
 				check_wrapped = 0;
@@ -626,11 +646,21 @@
 		break;
 	}
 
-	case FE_READ_STATUS:
-		if (fe->ops->read_status)
-			err = fe->ops->read_status(fe, (fe_status_t*) parg);
-		break;
+	case FE_READ_STATUS: {
+		fe_status_t* status = parg;
 
+		/* if retune was requested but hasn't occured yet, prevent
+		 * that user get signal state from previous tuning */
+		if(fepriv->state == FESTATE_RETUNE) {
+			err=0;
+			*status = 0;
+			break;
+		}
+
+		if (fe->ops->read_status)
+			err = fe->ops->read_status(fe, status);
+		break;
+	}
 	case FE_READ_BER:
 		if (fe->ops->read_ber)
 			err = fe->ops->read_ber(fe, (__u32*) parg);
@@ -681,6 +711,7 @@
 			err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
+			fepriv->tone = (fe_sec_tone_mode_t) parg;
 		}
 		break;
 
@@ -883,6 +914,7 @@
 	init_MUTEX (&fepriv->events.sem);
 	fe->dvb = dvb;
 	fepriv->inversion = INVERSION_OFF;
+	fepriv->tone = SEC_TONE_OFF;
 
 	printk ("DVB: registering frontend %i (%s)...\n",
 		fe->dvb->num,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index d2b0217..9c2c1d1 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -40,28 +40,6 @@
 
 #include "dvbdev.h"
 
-/* FIXME: Move to i2c-id.h */
-#define I2C_DRIVERID_DVBFE_SP8870	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX22700	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_AT76C651	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX24110	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX22702	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DIB3000MB	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DST		I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DUMMY	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_L64781	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_MT312	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_MT352	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_NXT6000	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_SP887X	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_STV0299	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA1004X	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA8083	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_VES1820	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_VES1X93	I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA80XX	I2C_DRIVERID_EXP2
-
-
 struct dvb_frontend_tune_settings {
         int min_delay_ms;
         int step_size;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 8aa32f6..612e5b0 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -3,30 +3,35 @@
 	depends on DVB_CORE && USB
 	select FW_LOADER
 	help
-	  By enabling this you will be able to choose the various USB 1.1 and
-	  USB2.0 DVB devices.
+	  By enabling this you will be able to choose the various supported
+	  USB1.1 and USB2.0 DVB devices.
 
 	  Almost every USB device needs a firmware, please look into
-	  <file:Documentation/dvb/README.dvb-usb>
+	  <file:Documentation/dvb/README.dvb-usb>.
 
-	  Say Y if you own an USB DVB device.
+	  For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+	  <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+	  Say Y if you own a USB DVB device.
 
 config DVB_USB_DEBUG
 	bool "Enable extended debug support for all DVB-USB devices"
 	depends on DVB_USB
 	help
-	  Say Y if you want to enable debuging. See modinfo dvb-usb (and the
+	  Say Y if you want to enable debugging. See modinfo dvb-usb (and the
 	  appropriate drivers) for debug levels.
 
 config DVB_USB_A800
 	tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
 	depends on DVB_USB
+	select DVB_DIB3000MC
 	help
 	  Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
 
 config DVB_USB_DIBUSB_MB
 	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
 	depends on DVB_USB
+	select DVB_DIB3000MB
 	help
 	  Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -52,6 +57,7 @@
 config DVB_USB_DIBUSB_MC
 	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
 	depends on DVB_USB
+	select DVB_DIB3000MC
 	help
 	  Support for 2.0 DVB-T receivers based on reference designs made by
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -66,12 +72,23 @@
 config DVB_USB_UMT_010
 	tristate "HanfTek UMT-010 DVB-T USB2.0 support"
 	depends on DVB_USB
+	select DVB_DIB3000MC
 	help
 	  Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
 
+config DVB_USB_CXUSB
+	tristate "Medion MD95700 hybrid USB2.0 (Conexant) support"
+	depends on DVB_USB
+	select DVB_CX22702
+	help
+	  Say Y here to support the Medion MD95700 hybrid USB2.0 device. Currently
+	  only the DVB-T part is supported.
+
 config DVB_USB_DIGITV
 	tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
 	depends on DVB_USB
+	select DVB_NXT6000
+	select DVB_MT352
 	help
 	  Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
 
@@ -87,13 +104,16 @@
 config DVB_USB_NOVA_T_USB2
 	tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
 	depends on DVB_USB
+	select DVB_DIB3000MC
 	help
 	  Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
 config DVB_USB_DTT200U
-	tristate "Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support"
+	tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
 	depends on DVB_USB
 	help
-	  Say Y here to support the Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
+	  Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
 
 	  The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
+
+	  The WT-220U and its clones are pen-sized.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index d65b50f..746d87e 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -27,4 +27,7 @@
 dvb-usb-digitv-objs = digitv.o
 obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
 
+dvb-usb-cxusb-objs = cxusb.o
+obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
+
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index a354293..f2fcc2f 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -61,6 +61,12 @@
 	{ 0x02, 0x00, KEY_LAST },        /* >>| / BLUE */
 	{ 0x02, 0x04, KEY_EPG },         /* EPG */
 	{ 0x02, 0x15, KEY_MENU },        /* MENU */
+
+	{ 0x03, 0x03, KEY_CHANNELUP },   /* CH UP */
+	{ 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
+	{ 0x03, 0x01, KEY_FIRST },       /* |<< / GREEN */
+	{ 0x03, 0x00, KEY_LAST },        /* >>| / BLUE */
+
 };
 
 int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -68,7 +74,7 @@
 	u8 key[5];
 	if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
 				0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
-				2*HZ) != 5)
+				2000) != 5)
 		return -ENODEV;
 
 	/* call the universal NEC remote processor, to find out the key's state and event */
@@ -143,7 +149,7 @@
 
 static struct usb_driver a800_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "AVerMedia AverTV DVB-T USB 2.0 (A800)",
+	.name		= "dvb_usb_a800",
 	.probe		= a800_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table	= a800_table,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
new file mode 100644
index 0000000..c3e1b66
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -0,0 +1,295 @@
+/* DVB USB compliant linux driver for Conexant USB reference design.
+ *
+ * The Conexant reference design I saw on their website was only for analogue
+ * capturing (using the cx25842). The box I took to write this driver (reverse
+ * engineered) is the one labeled Medion MD95700. In addition to the cx25842
+ * for analogue capturing it also has a cx22702 DVB-T demodulator on the main
+ * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
+ *
+ * Maybe it is a little bit premature to call this driver cxusb, but I assume
+ * the USB protocol is identical or at least inherited from the reference
+ * design, so it can be reused for the "analogue-only" device (if it will
+ * appear at all).
+ *
+ * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue
+ * part
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "cxusb.h"
+
+#include "cx22702.h"
+
+/* debug */
+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);
+
+static int cxusb_ctrl_msg(struct dvb_usb_device *d,
+		u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+	int wo = (rbuf == NULL || rlen == 0); /* write-only */
+	u8 sndbuf[1+wlen];
+	memset(sndbuf,0,1+wlen);
+
+	sndbuf[0] = cmd;
+	memcpy(&sndbuf[1],wbuf,wlen);
+	if (wo)
+		dvb_usb_generic_write(d,sndbuf,1+wlen);
+	else
+		dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
+
+	return 0;
+}
+
+/* I2C */
+static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path)
+{
+	struct cxusb_state *st = d->priv;
+	u8 o[2],i;
+
+	if (path == st->cur_i2c_path)
+		return;
+
+	o[0] = IOCTL_SET_I2C_PATH;
+	switch (path) {
+		case PATH_CX22702:
+			o[1] = 0;
+			break;
+		case PATH_TUNER_OTHER:
+			o[1] = 1;
+			break;
+		default:
+			err("unkown i2c path");
+			return;
+	}
+	cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1);
+
+	if (i != 0x01)
+		deb_info("i2c_path setting failed.\n");
+
+	st->cur_i2c_path = path;
+}
+
+static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i;
+
+	if (down_interruptible(&d->i2c_sem) < 0)
+		return -EAGAIN;
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+	for (i = 0; i < num; i++) {
+
+		switch (msg[i].addr) {
+			case 0x63:
+				cxusb_set_i2c_path(d,PATH_CX22702);
+				break;
+			default:
+				cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
+				break;
+		}
+
+		/* read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
+			obuf[0] = msg[i].len;
+			obuf[1] = msg[i+1].len;
+			obuf[2] = msg[i].addr;
+			memcpy(&obuf[3],msg[i].buf,msg[i].len);
+
+			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+						obuf, 3+msg[i].len,
+						ibuf, 1+msg[i+1].len) < 0)
+				break;
+
+			if (ibuf[0] != 0x08)
+				deb_info("i2c read could have been failed\n");
+
+			memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
+
+			i++;
+		} else { /* write */
+			u8 obuf[2+msg[i].len], ibuf;
+			obuf[0] = msg[i].addr;
+			obuf[1] = msg[i].len;
+			memcpy(&obuf[2],msg[i].buf,msg[i].len);
+
+			if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
+				break;
+			if (ibuf != 0x08)
+				deb_info("i2c write could have been failed\n");
+		}
+	}
+
+	up(&d->i2c_sem);
+	return i;
+}
+
+static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cxusb_i2c_algo = {
+	.name          = "Conexant USB I2C algorithm",
+	.id            = I2C_ALGO_BIT,
+	.master_xfer   = cxusb_i2c_xfer,
+	.functionality = cxusb_i2c_func,
+};
+
+static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	return 0;
+}
+
+static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 buf[2] = { 0x03, 0x00 };
+	if (onoff)
+		cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
+	else
+		cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0);
+
+	return 0;
+}
+
+struct cx22702_config cxusb_cx22702_config = {
+	.demod_address = 0x63,
+
+	.output_mode = CX22702_PARALLEL_OUTPUT,
+
+	.pll_init = dvb_usb_pll_init_i2c,
+	.pll_set  = dvb_usb_pll_set_i2c,
+};
+
+/* Callbacks for DVB USB */
+static int cxusb_tuner_attach(struct dvb_usb_device *d)
+{
+	u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
+	d->pll_addr = 0x61;
+	memcpy(d->pll_init,bpll,4);
+	d->pll_desc = &dvb_pll_fmd1216me;
+	return 0;
+}
+
+static int cxusb_frontend_attach(struct dvb_usb_device *d)
+{
+	u8 buf[2] = { 0x03, 0x00 };
+	u8 b = 0;
+
+	if (usb_set_interface(d->udev,0,0) < 0)
+		err("set interface to alts=0 failed");
+
+	cxusb_ctrl_msg(d,0xde,&b,0,NULL,0);
+	cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
+	cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1);
+
+	if (usb_set_interface(d->udev,0,6) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
+	cxusb_set_i2c_path(d,PATH_CX22702);
+	cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1);
+
+	if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_properties cxusb_properties;
+
+static int cxusb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE);
+}
+
+static struct usb_device_id cxusb_table [] = {
+		{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+		{}		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, cxusb_table);
+
+static struct dvb_usb_properties cxusb_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.streaming_ctrl   = cxusb_streaming_ctrl,
+	.power_ctrl       = cxusb_power_ctrl,
+	.frontend_attach  = cxusb_frontend_attach,
+	.tuner_attach     = cxusb_tuner_attach,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_ISOC,
+		.count = 5,
+		.endpoint = 0x02,
+		.u = {
+			.isoc = {
+				.framesperurb = 32,
+				.framesize = 940,
+				.interval = 5,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Medion MD95700 (MDUSBTV-HYBRID)",
+			{ NULL },
+			{ &cxusb_table[0], NULL },
+		},
+	}
+};
+
+static struct usb_driver cxusb_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "dvb_usb_cxusb",
+	.probe		= cxusb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= cxusb_table,
+};
+
+/* module stuff */
+static int __init cxusb_module_init(void)
+{
+	int result;
+	if ((result = usb_register(&cxusb_driver))) {
+		err("usb_register failed. Error number %d",result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void __exit cxusb_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&cxusb_driver);
+}
+
+module_init (cxusb_module_init);
+module_exit (cxusb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
+MODULE_VERSION("1.0-alpha");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
new file mode 100644
index 0000000..1d79016
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -0,0 +1,30 @@
+#ifndef _DVB_USB_CXUSB_H_
+#define _DVB_USB_CXUSB_H_
+
+#define DVB_USB_LOG_PREFIX "digitv"
+#include "dvb-usb.h"
+
+extern int dvb_usb_cxusb_debug;
+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
+
+/* usb commands - some of it are guesses, don't have a reference yet */
+#define CMD_I2C_WRITE    0x08
+#define CMD_I2C_READ     0x09
+
+#define CMD_IOCTL        0x0e
+#define    IOCTL_SET_I2C_PATH 0x02
+
+#define CMD_POWER_OFF    0x50
+#define CMD_POWER_ON     0x51
+
+enum cxusb_i2c_pathes {
+	PATH_UNDEF       = 0x00,
+	PATH_CX22702     = 0x01,
+	PATH_TUNER_OTHER = 0x02,
+};
+
+struct cxusb_state {
+	enum cxusb_i2c_pathes cur_i2c_path;
+};
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index a0ffbb5..828b518 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -31,10 +31,17 @@
 	return 0;
 }
 
-/* some of the dibusb 1.1 device aren't equipped with the default tuner
+static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d)
+{
+	d->pll_addr = 0x61;
+	d->pll_desc = &dvb_pll_tua6010xs;
+	return 0;
+}
+
+/* Some of the Artec 1.1 device aren't equipped with the default tuner
  * (Thomson Cable), but with a Panasonic ENV77H11D5.  This function figures
  * this out. */
-static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d)
+static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
 {
 	u8 b[2] = { 0,0 }, b2[1];
 	int ret = 0;
@@ -59,8 +66,7 @@
 
 	if (b2[0] == 0xfe) {
 		info("this device has the Thomson Cable onboard. Which is default.");
-		d->pll_addr = 0x61;
-		d->pll_desc = &dvb_pll_tua6010xs;
+		dibusb_thomson_tuner_attach(d);
 	} else {
 		u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
 		info("this device has the Panasonic ENV77H11D5 onboard.");
@@ -90,8 +96,8 @@
 
 /* do not change the order of the ID table */
 static struct usb_device_id dibusb_dib3000mb_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_AVERMEDIA_UNK,	USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */	{ USB_DEVICE(USB_VID_AVERMEDIA_UNK,	USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 00 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+/* 01 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_WARM)},
 /* 02 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
 /* 03 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_WARM) },
 /* 04 */	{ USB_DEVICE(USB_VID_COMPRO_UNK,	USB_PID_COMPRO_DVBU2000_UNK_COLD) },
@@ -114,7 +120,17 @@
 /* 21 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
 /* 22 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
 /* 23 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_COLD) },
+
+/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
 /* 24 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_WARM) },
+/* 25 */	{ USB_DEVICE(USB_VID_KYE,			USB_PID_KYE_DVB_T_COLD) },
+/* 26 */	{ USB_DEVICE(USB_VID_KYE,			USB_PID_KYE_DVB_T_WARM) },
+
+// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+/* 27 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+#endif
 			{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
@@ -134,7 +150,7 @@
 	.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
 	.power_ctrl       = dibusb_power_ctrl,
 	.frontend_attach  = dibusb_dib3000mb_frontend_attach,
-	.tuner_attach     = dibusb_dib3000mb_tuner_attach,
+	.tuner_attach     = dibusb_tuner_probe_and_attach,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
@@ -156,7 +172,7 @@
 		}
 	},
 
-	.num_device_descs = 8,
+	.num_device_descs = 9,
 	.devices = {
 		{	"AVerMedia AverTV DVBT USB1.1",
 			{ &dibusb_dib3000mb_table[0],  NULL },
@@ -190,11 +206,17 @@
 			{ &dibusb_dib3000mb_table[19], NULL },
 			{ &dibusb_dib3000mb_table[20], NULL },
 		},
+		{	"VideoWalker DVB-T USB",
+			{ &dibusb_dib3000mb_table[25], NULL },
+			{ &dibusb_dib3000mb_table[26], NULL },
+		},
 	}
 };
 
 static struct dvb_usb_properties dibusb1_1_an2235_properties = {
 	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+	.pid_filter_count = 16,
+
 	.usb_ctrl = CYPRESS_AN2235,
 
 	.firmware = "dvb-usb-dibusb-an2235-01.fw",
@@ -206,7 +228,7 @@
 	.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
 	.power_ctrl       = dibusb_power_ctrl,
 	.frontend_attach  = dibusb_dib3000mb_frontend_attach,
-	.tuner_attach     = dibusb_dib3000mb_tuner_attach,
+	.tuner_attach     = dibusb_tuner_probe_and_attach,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
@@ -228,20 +250,32 @@
 		}
 	},
 
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+	.num_device_descs = 2,
+#else
 	.num_device_descs = 1,
+#endif
 	.devices = {
 		{	"Artec T1 USB1.1 TVBOX with AN2235",
 			{ &dibusb_dib3000mb_table[20], NULL },
 			{ &dibusb_dib3000mb_table[21], NULL },
 		},
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+		{	"Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
+			{ &dibusb_dib3000mb_table[27], NULL },
+			{ NULL },
+		},
+#endif
 	}
 };
 
 static struct dvb_usb_properties dibusb2_0b_properties = {
 	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+	.pid_filter_count = 32,
+
 	.usb_ctrl = CYPRESS_FX2,
 
-	.firmware = "dvb-usb-adstech-usb2-01.fw",
+	.firmware = "dvb-usb-adstech-usb2-02.fw",
 
 	.size_of_priv     = sizeof(struct dibusb_state),
 
@@ -250,7 +284,7 @@
 	.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
 	.power_ctrl       = dibusb2_0_power_ctrl,
 	.frontend_attach  = dibusb_dib3000mb_frontend_attach,
-	.tuner_attach     = dibusb_dib3000mb_tuner_attach,
+	.tuner_attach     = dibusb_thomson_tuner_attach,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
@@ -272,18 +306,18 @@
 		}
 	},
 
-	.num_device_descs = 2,
+	.num_device_descs = 1,
 	.devices = {
 		{	"KWorld/ADSTech Instant DVB-T USB 2.0",
 			{ &dibusb_dib3000mb_table[23], NULL },
-			{ &dibusb_dib3000mb_table[24], NULL }, /* device ID with default DIBUSB2_0-firmware */
+			{ &dibusb_dib3000mb_table[24], NULL },
 		},
 	}
 };
 
 static struct usb_driver dibusb_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "DiBcom based USB DVB-T devices (DiB3000M-B based)",
+	.name		= "dvb_usb_dibusb_mb",
 	.probe		= dibusb_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table	= dibusb_dib3000mb_table,
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index aad8ed3..e9dac43 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -83,7 +83,7 @@
 
 static struct usb_driver dibusb_mc_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "DiBcom based USB2.0 DVB-T (DiB3000M-C/P based) devices",
+	.name		= "dvb_usb_dibusb_mc",
 	.probe		= dibusb_mc_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table	= dibusb_dib3000mc_table,
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 5acf3fd..9a676af 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -1,10 +1,9 @@
 /* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
  * receiver
  *
- * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) and
- *                    Allan Third (allan.third@cs.man.ac.uk)
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
  *
- * partly based on the SDK published by Nebula Electronics (TODO do we want this line ?)
+ * partly based on the SDK published by Nebula Electronics
  *
  *	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
@@ -38,7 +37,7 @@
 		dvb_usb_generic_write(d,sndbuf,7);
 	} else {
 		dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
-		memcpy(&rbuf,&rcvbuf[3],rlen);
+		memcpy(rbuf,&rcvbuf[3],rlen);
 	}
 	return 0;
 }
@@ -95,41 +94,20 @@
 
 static int digitv_mt352_demod_init(struct dvb_frontend *fe)
 {
-	static u8 mt352_clock_config[] = { 0x89, 0x38, 0x2d };
-	static u8 mt352_reset[] = { 0x50, 0x80 };
-	static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
+	static u8 reset_buf[] = { 0x89, 0x38,  0x8a, 0x2d, 0x50, 0x80 };
+	static u8 init_buf[] = { 0x68, 0xa0,  0x8e, 0x40,  0x53, 0x50,
+			0x67, 0x20,  0x7d, 0x01,  0x7c, 0x00,  0x7a, 0x00,
+			0x79, 0x20,  0x57, 0x05,  0x56, 0x31,  0x88, 0x0f,
+			0x75, 0x32 };
+	int i;
 
-	static u8 mt352_agc_cfg[] = { 0x68, 0xa0 };
-	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0xa0 };
-	static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
-	static u8 mt352_agc_target[] = { 0x67, 0x20 };
+	for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
+		mt352_write(fe, &reset_buf[i], 2);
 
-	static u8 mt352_rs_err_per[] = { 0x7c, 0x00, 0x01 };
-	static u8 mt352_snr_select[] = { 0x79, 0x00, 0x20 };
-
-	static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x05 };
-
-	static u8 mt352_scan_ctl[] = { 0x88, 0x0f };
-	static u8 mt352_capt_range[] = { 0x75, 0x32 };
-
-	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
-	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
 	msleep(1);
-	mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
 
-	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-	mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
-	mt352_write(fe, mt352_agc_target, sizeof(mt352_agc_target));
-
-
-	mt352_write(fe, mt352_rs_err_per, sizeof(mt352_rs_err_per));
-	mt352_write(fe, mt352_snr_select, sizeof(mt352_snr_select));
-
-	mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
-
-	mt352_write(fe, mt352_scan_ctl, sizeof(mt352_scan_ctl));
-	mt352_write(fe, mt352_capt_range, sizeof(mt352_capt_range));
+	for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
+		mt352_write(fe, &init_buf[i], 2);
 
 	return 0;
 }
@@ -137,7 +115,7 @@
 static struct mt352_config digitv_mt352_config = {
 	.demod_address = 0x0, /* ignored by the digitv anyway */
 	.demod_init = digitv_mt352_demod_init,
-	.pll_set = NULL, /* TODO */
+	.pll_set = dvb_usb_pll_set,
 };
 
 static struct nxt6000_config digitv_nxt6000_config = {
@@ -150,9 +128,9 @@
 
 static int digitv_frontend_attach(struct dvb_usb_device *d)
 {
-	if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) == NULL)
+	if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL)
 		return 0;
-	if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) == NULL) {
+	if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
 
 		warn("nxt6000 support is not done yet, in fact you are one of the first "
 				"person who wants to use this device in Linux. Please report to "
@@ -163,6 +141,13 @@
 	return -EIO;
 }
 
+static int digitv_tuner_attach(struct dvb_usb_device *d)
+{
+	d->pll_addr = 0x60;
+	d->pll_desc = &dvb_pll_tded4;
+	return 0;
+}
+
 static struct dvb_usb_rc_key digitv_rc_keys[] = {
 	{ 0x00, 0x16, KEY_POWER }, /* dummy key */
 };
@@ -184,7 +169,6 @@
 	return 0;
 }
 
-
 /* DVB USB Driver stuff */
 static struct dvb_usb_properties digitv_properties;
 
@@ -208,13 +192,8 @@
 
 	.size_of_priv     = 0,
 
-	.streaming_ctrl   = NULL,
-	.pid_filter       = NULL,
-	.pid_filter_ctrl  = NULL,
-	.power_ctrl       = NULL,
 	.frontend_attach  = digitv_frontend_attach,
-	.tuner_attach     = NULL, // digitv_tuner_attach,
-	.read_mac_address = NULL,
+	.tuner_attach     = digitv_tuner_attach,
 
 	.rc_interval      = 1000,
 	.rc_key_map       = digitv_rc_keys,
@@ -238,7 +217,7 @@
 		}
 	},
 
-	.num_device_descs = 2,
+	.num_device_descs = 1,
 	.devices = {
 		{   "Nebula Electronics uDigiTV DVB-T USB2.0)",
 			{ &digitv_table[0], NULL },
@@ -249,7 +228,7 @@
 
 static struct usb_driver digitv_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "Nebula Electronics uDigiTV DVB-T USB2.0 device",
+	.name		= "dvb_usb_digitv",
 	.probe		= digitv_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table	= digitv_table,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
index d17d768..b032523 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
@@ -1,5 +1,5 @@
-/* Frontend part of the Linux driver for the Yakumo/Hama/Typhoon DVB-T
- * USB2.0 receiver.
+/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
  *
  * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
  *
@@ -14,61 +14,58 @@
 struct dtt200u_fe_state {
 	struct dvb_usb_device *d;
 
+	fe_status_t stat;
+
 	struct dvb_frontend_parameters fep;
 	struct dvb_frontend frontend;
 };
 
-#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
-
 static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
 {
 	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_TUNE_STAT;
-	u8 br[3] = { 0 };
-//	u8 bdeb[5] = { 0 };
+	u8 st = GET_TUNE_STATUS, b[3];
 
-	dvb_usb_generic_rw(state->d,&bw,1,br,3,0);
-	switch (br[0]) {
+	dvb_usb_generic_rw(state->d,&st,1,b,3,0);
+
+	switch (b[0]) {
 		case 0x01:
-			*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 			break;
-		case 0x00:
-			*stat = 0;
+		case 0x00: /* pending */
+			*stat = FE_TIMEDOUT; /* during set_frontend */
 			break;
 		default:
-			moan("br[0]",GET_TUNE_STAT);
+		case 0x02: /* failed */
+			*stat = 0;
 			break;
 	}
-
-//	bw[0] = 0x88;
-//	dvb_usb_generic_rw(state->d,bw,1,bdeb,5,0);
-
-//	deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
-
 	return 0;
 }
+
 static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
 {
 	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_BER;
-	*ber = 0;
-	dvb_usb_generic_rw(state->d,&bw,1,(u8*) ber,3,0);
+	u8 bw = GET_VIT_ERR_CNT,b[3];
+	dvb_usb_generic_rw(state->d,&bw,1,b,3,0);
+	*ber = (b[0] << 16) | (b[1] << 8) | b[2];
 	return 0;
 }
 
 static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 {
 	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_UNK;
-	*unc = 0;
-	dvb_usb_generic_rw(state->d,&bw,1,(u8*) unc,3,0);
+	u8 bw = GET_RS_UNCOR_BLK_CNT,b[2];
+
+	dvb_usb_generic_rw(state->d,&bw,1,b,2,0);
+	*unc = (b[0] << 8) | b[1];
 	return 0;
 }
 
 static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 {
 	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 bw = GET_SIG_STRENGTH, b;
+	u8 bw = GET_AGC, b;
 	dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
 	*strength = (b << 8) | b;
 	return 0;
@@ -86,7 +83,7 @@
 static int dtt200u_fe_init(struct dvb_frontend* fe)
 {
 	struct dtt200u_fe_state *state = fe->demodulator_priv;
-	u8 b = RESET_DEMOD;
+	u8 b = SET_INIT;
 	return dvb_usb_generic_write(state->d,&b,1);
 }
 
@@ -98,8 +95,8 @@
 static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
 	tune->min_delay_ms = 1500;
-	tune->step_size = 166667;
-	tune->max_drift = 166667 * 2;
+	tune->step_size = 0;
+	tune->max_drift = 0;
 	return 0;
 }
 
@@ -107,27 +104,32 @@
 				  struct dvb_frontend_parameters *fep)
 {
 	struct dtt200u_fe_state *state = fe->demodulator_priv;
+	int i;
+	fe_status_t st;
 	u16 freq = fep->frequency / 250000;
-	u8 bw,bwbuf[2] = { SET_BANDWIDTH, 0 }, freqbuf[3] = { SET_FREQUENCY, 0, 0 };
+	u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
 
 	switch (fep->u.ofdm.bandwidth) {
-		case BANDWIDTH_8_MHZ: bw = 8; break;
-		case BANDWIDTH_7_MHZ: bw = 7; break;
-		case BANDWIDTH_6_MHZ: bw = 6; break;
+		case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break;
+		case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break;
+		case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break;
 		case BANDWIDTH_AUTO: return -EOPNOTSUPP;
 		default:
 			return -EINVAL;
 	}
-	deb_info("set_frontend\n");
 
-	bwbuf[1] = bw;
 	dvb_usb_generic_write(state->d,bwbuf,2);
 
 	freqbuf[1] = freq & 0xff;
 	freqbuf[2] = (freq >> 8) & 0xff;
 	dvb_usb_generic_write(state->d,freqbuf,3);
 
-	memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
+	for (i = 0; i < 30; i++) {
+		msleep(20);
+		dtt200u_fe_read_status(fe, &st);
+		if (st & FE_TIMEDOUT)
+			continue;
+	}
 
 	return 0;
 }
@@ -174,7 +176,7 @@
 
 static struct dvb_frontend_ops dtt200u_fe_ops = {
 	.info = {
-		.name			= "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
+		.name			= "WideView USB DVB-T",
 		.type			= FE_OFDM,
 		.frequency_min		= 44250000,
 		.frequency_max		= 867250000,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index fb2b5a2..47dba6e 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -1,8 +1,10 @@
-/* DVB USB library compliant Linux driver for the Yakumo/Hama/Typhoon DVB-T
- * USB2.0 receiver.
+/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
+ * Thanks to Steve Chang from WideView for providing support for the WT-220U.
+ *
  *	This program is free software; you can redistribute it and/or modify it
  *	under the terms of the GNU General Public License as published by the Free
  *	Software Foundation, version 2.
@@ -16,14 +18,24 @@
 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);
 
+static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 b = SET_INIT;
+
+	if (onoff)
+		dvb_usb_generic_write(d,&b,2);
+
+	return 0;
+}
+
 static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff)
 {
-	u8 b_streaming[2] = { SET_TS_CTRL, onoff };
+	u8 b_streaming[2] = { SET_STREAMING, onoff };
 	u8 b_rst_pid = RESET_PID_FILTER;
 
 	dvb_usb_generic_write(d,b_streaming,2);
 
-	if (!onoff)
+	if (onoff == 0)
 		dvb_usb_generic_write(d,&b_rst_pid,1);
 	return 0;
 }
@@ -36,7 +48,7 @@
 	b_pid[0] = SET_PID_FILTER;
 	b_pid[1] = index;
 	b_pid[2] = pid & 0xff;
-	b_pid[3] = (pid >> 8) & 0xff;
+	b_pid[3] = (pid >> 8) & 0x1f;
 
 	return dvb_usb_generic_write(d,b_pid,4);
 }
@@ -54,9 +66,9 @@
 	{ 0x80, 0x08, KEY_5 },
 	{ 0x80, 0x09, KEY_6 },
 	{ 0x80, 0x0a, KEY_7 },
-	{ 0x00, 0x0c, KEY_ZOOM },
+	{ 0x80, 0x0c, KEY_ZOOM },
 	{ 0x80, 0x0d, KEY_0 },
-	{ 0x00, 0x0e, KEY_SELECT },
+	{ 0x80, 0x0e, KEY_SELECT },
 	{ 0x80, 0x12, KEY_POWER },
 	{ 0x80, 0x1a, KEY_CHANNELUP },
 	{ 0x80, 0x1b, KEY_8 },
@@ -66,7 +78,7 @@
 
 static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-	u8 key[5],cmd = GET_RC_KEY;
+	u8 key[5],cmd = GET_RC_CODE;
 	dvb_usb_generic_rw(d,&cmd,1,key,5,0);
 	dvb_usb_nec_rc_key_to_event(d,key,event,state);
 	if (key[0] != 0)
@@ -81,32 +93,41 @@
 }
 
 static struct dvb_usb_properties dtt200u_properties;
+static struct dvb_usb_properties wt220u_properties;
 
 static int dtt200u_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE);
+	if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE) == 0 ||
+		dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE) == 0)
+		return 0;
+
+	return -ENODEV;
 }
 
 static struct usb_device_id dtt200u_usb_table [] = {
-	    { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_COLD) },
-	    { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_WARM) },
+//		{ USB_DEVICE(0x04b4,0x8613) },
+	    { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
+	    { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
+		{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD)  },
+		{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM)  },
 	    { 0 },
 };
 MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
 
 static struct dvb_usb_properties dtt200u_properties = {
 	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
-	.pid_filter_count = 255, /* It is a guess, but there are at least 10 */
+	.pid_filter_count = 15,
 
 	.usb_ctrl = CYPRESS_FX2,
 	.firmware = "dvb-usb-dtt200u-01.fw",
 
+	.power_ctrl      = dtt200u_power_ctrl,
 	.streaming_ctrl  = dtt200u_streaming_ctrl,
 	.pid_filter      = dtt200u_pid_filter,
 	.frontend_attach = dtt200u_frontend_attach,
 
-	.rc_interval     = 200,
+	.rc_interval     = 300,
 	.rc_key_map      = dtt200u_rc_keys,
 	.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
 	.rc_query        = dtt200u_rc_query,
@@ -127,18 +148,59 @@
 
 	.num_device_descs = 1,
 	.devices = {
-		{ .name = "Yakumo/Hama/Typhoon DVB-T USB2.0)",
-		  .cold_ids = { &dtt200u_usb_table[0], &dtt200u_usb_table[2] },
+		{ .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
+		  .cold_ids = { &dtt200u_usb_table[0], NULL },
 		  .warm_ids = { &dtt200u_usb_table[1], NULL },
 		},
 		{ 0 },
 	}
 };
 
+static struct dvb_usb_properties wt220u_properties = {
+	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+	.pid_filter_count = 15,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-01.fw",
+
+	.power_ctrl      = dtt200u_power_ctrl,
+	.streaming_ctrl  = dtt200u_streaming_ctrl,
+	.pid_filter      = dtt200u_pid_filter,
+	.frontend_attach = dtt200u_frontend_attach,
+
+	.rc_interval     = 300,
+	.rc_key_map      = dtt200u_rc_keys,
+	.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+	.rc_query        = dtt200u_rc_query,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_BULK,
+		.count = 7,
+		.endpoint = 0x02,
+		.u = {
+			.bulk = {
+				.buffersize = 4096,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (and clones)",
+		  .cold_ids = { &dtt200u_usb_table[2], NULL },
+		  .warm_ids = { &dtt200u_usb_table[3], NULL },
+		},
+		{ 0 },
+	}
+};
+
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver dtt200u_usb_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "Yakumo/Hama/Typhoon DVB-T USB2.0",
+	.name		= "dvb_usb_dtt200u",
 	.probe 		= dtt200u_usb_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table 	= dtt200u_usb_table,
@@ -166,6 +228,6 @@
 module_exit(dtt200u_usb_module_exit);
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the Yakumo/Hama/Typhoon DVB-T USB2.0 device");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices");
 MODULE_VERSION("1.0");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h
index ed41420..6f1f304 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.h
+++ b/drivers/media/dvb/dvb-usb/dtt200u.h
@@ -1,5 +1,5 @@
-/* Common header file of Linux driver for the Yakumo/Hama/Typhoon DVB-T
- * USB2.0 receiver.
+/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
@@ -22,44 +22,34 @@
 /* guessed protocol description (reverse engineered):
  * read
  *  00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
- *  81 - <TS_LOCK> <current frequency divided by 250000>
- *  82 - crash - do not touch
- *  83 - crash - do not touch
- *  84 - remote control
- *  85 - crash - do not touch (OK, stop testing here)
  *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
- *  89 - noise-to-signal
- *	8a - unkown 1 byte - signal_strength
- *  8c - ber ???
- *  8d - ber
- *  8e - unc
  */
 
-#define GET_SPEED        0x00
-#define GET_TUNE_STAT    0x81
-#define GET_RC_KEY       0x84
-#define GET_STATUS       0x88
-#define GET_SNR          0x89
-#define GET_SIG_STRENGTH 0x8a
-#define GET_UNK          0x8c
-#define GET_BER          0x8d
-#define GET_UNC          0x8e
+#define GET_SPEED            0x00
+#define GET_TUNE_STATUS      0x81
+#define GET_RC_CODE          0x84
+#define GET_CONFIGURATION    0x88
+#define GET_AGC              0x89
+#define GET_SNR              0x8a
+#define GET_VIT_ERR_CNT      0x8c
+#define GET_RS_ERR_CNT       0x8d
+#define GET_RS_UNCOR_BLK_CNT 0x8e
 
 /* write
- *  01 - reset the demod
+ *  01 - init
  *  02 - frequency (divided by 250000)
  *  03 - bandwidth
  *  04 - pid table (index pid(7:0) pid(12:8))
  *  05 - reset the pid table
- *  08 - demod transfer enabled or not (FX2 transfer is enabled by default)
+ *  08 - transfer switch
  */
 
-#define RESET_DEMOD      0x01
-#define SET_FREQUENCY    0x02
+#define SET_INIT         0x01
+#define SET_RF_FREQ      0x02
 #define SET_BANDWIDTH    0x03
 #define SET_PID_FILTER   0x04
 #define RESET_PID_FILTER 0x05
-#define SET_TS_CTRL      0x08
+#define SET_STREAMING    0x08
 
 extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
index 67e0d73..7300489 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
@@ -12,14 +12,16 @@
 #include "dvb-usb.h"
 
 extern int dvb_usb_debug;
+extern int dvb_usb_disable_rc_polling;
 
 #define deb_info(args...) dprintk(dvb_usb_debug,0x01,args)
 #define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args)
-#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args)
+#define deb_pll(args...)  dprintk(dvb_usb_debug,0x04,args)
 #define deb_ts(args...)   dprintk(dvb_usb_debug,0x08,args)
 #define deb_err(args...)  dprintk(dvb_usb_debug,0x10,args)
 #define deb_rc(args...)   dprintk(dvb_usb_debug,0x20,args)
 #define deb_fw(args...)   dprintk(dvb_usb_debug,0x40,args)
+#define deb_mem(args...)  dprintk(dvb_usb_debug,0x80,args)
 
 /* commonly used  methods */
 extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index bcb3419..794d513 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -12,7 +12,7 @@
 /* Vendor IDs */
 #define USB_VID_ADSTECH						0x06e1
 #define USB_VID_ANCHOR						0x0547
-#define USB_VID_AVERMEDIA_UNK				0x14aa
+#define USB_VID_WIDEVIEW					0x14aa
 #define USB_VID_AVERMEDIA					0x07ca
 #define USB_VID_COMPRO						0x185b
 #define USB_VID_COMPRO_UNK					0x145f
@@ -24,6 +24,8 @@
 #define USB_VID_HANFTEK						0x15f4
 #define USB_VID_HAUPPAUGE					0x2040
 #define USB_VID_HYPER_PALTEK				0x1025
+#define USB_VID_KYE							0x0458
+#define USB_VID_MEDION						0x1660
 #define USB_VID_VISIONPLUS					0x13d3
 #define USB_VID_TWINHAN						0x1822
 #define USB_VID_ULTIMA_ELECTRONIC			0x05d8
@@ -70,6 +72,8 @@
 #define USB_PID_HANFTEK_UMT_010_WARM		0x0015
 #define USB_PID_DTT200U_COLD				0x0201
 #define USB_PID_DTT200U_WARM				0x0301
+#define USB_PID_WT220U_COLD					0x0222
+#define USB_PID_WT220U_WARM					0x0221
 #define USB_PID_WINTV_NOVA_T_USB2_COLD		0x9300
 #define USB_PID_WINTV_NOVA_T_USB2_WARM		0x9301
 #define USB_PID_NEBULA_DIGITV				0x0201
@@ -78,6 +82,8 @@
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LGZ201_1		0xdb01
 #define USB_PID_DVICO_BLUEBIRD_TH7579_2		0xdb11
-
+#define USB_PID_MEDION_MD95700				0x0932
+#define USB_PID_KYE_DVB_T_COLD				0x701e
+#define USB_PID_KYE_DVB_T_WARM				0x701f
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index 3aadec9..c3b3ae4 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -18,6 +18,10 @@
 module_param_named(debug,dvb_usb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
 
+int dvb_usb_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
+
 /* general initialization functions */
 int dvb_usb_exit(struct dvb_usb_device *d)
 {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 9f1e23f..fc7800f 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -21,6 +21,10 @@
 	/* TODO: need a lock here.  We can simply skip checking for the remote control
 	   if we're busy. */
 
+	/* when the parameter has been set to 1 via sysfs while the driver was running */
+	if (dvb_usb_disable_rc_polling)
+		return;
+
 	if (d->props.rc_query(d,&event,&state)) {
 		err("error while querying for an remote control event.");
 		goto schedule;
@@ -35,7 +39,7 @@
 			d->last_event = event;
 		case REMOTE_KEY_REPEAT:
 			deb_rc("key repeated\n");
-			input_event(&d->rc_input_dev, EV_KEY, event, 1);
+			input_event(&d->rc_input_dev, EV_KEY, d->last_event, 1);
 			input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
 			input_sync(&d->rc_input_dev);
 			break;
@@ -85,7 +89,9 @@
 int dvb_usb_remote_init(struct dvb_usb_device *d)
 {
 	int i;
-	if (d->props.rc_key_map == NULL)
+	if (d->props.rc_key_map == NULL ||
+		d->props.rc_query == NULL ||
+		dvb_usb_disable_rc_polling)
 		return 0;
 
 	/* Initialise the remote-control structures.*/
@@ -154,12 +160,12 @@
 				break;
 			}
 			/* See if we can match the raw key code. */
-			for (i = 0; i < sizeof(keymap)/sizeof(struct dvb_usb_rc_key); i++)
+			for (i = 0; i < d->props.rc_key_map_size; i++)
 				if (keymap[i].custom == keybuf[1] &&
 					keymap[i].data == keybuf[3]) {
 					*event = keymap[i].event;
 					*state = REMOTE_KEY_PRESSED;
-					break;
+					return 0;
 				}
 			deb_err("key mapping failed - no appropriate key found in keymapping\n");
 			break;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index 83d476f..f5799a4 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -24,11 +24,12 @@
 	if ((ret = down_interruptible(&d->usb_sem)))
 		return ret;
 
+	deb_xfer(">>> ");
 	debug_dump(wbuf,wlen,deb_xfer);
 
 	ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
 			d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
-			2*HZ);
+			2000);
 
 	if (ret)
 		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
@@ -42,12 +43,14 @@
 
 		ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
 				d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
-				2*HZ);
+				2000);
 
 		if (ret)
 			err("recv bulk message failed: %d",ret);
-		else
+		else {
+			deb_xfer("<<< ");
 			debug_dump(rbuf,actlen,deb_xfer);
+		}
 	}
 
 	up(&d->usb_sem);
@@ -61,12 +64,19 @@
 }
 EXPORT_SYMBOL(dvb_usb_generic_write);
 
-static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+
+/* URB stuff for streaming */
+static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
 {
 	struct dvb_usb_device *d = urb->context;
+	int ptype = usb_pipetype(urb->pipe);
+	int i;
+	u8 *b;
 
-	deb_ts("bulk urb completed. feedcount: %d, status: %d, length: %d\n",d->feedcount,urb->status,
-			urb->actual_length);
+	deb_ts("'%s' urb completed. feedcount: %d, status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
+			ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", d->feedcount,
+			urb->status,urb->actual_length,urb->transfer_buffer_length,
+			urb->number_of_packets,urb->error_count);
 
 	switch (urb->status) {
 		case 0:         /* success */
@@ -81,11 +91,33 @@
 			break;
 	}
 
-	if (d->feedcount > 0 && urb->actual_length > 0) {
-		if (d->state & DVB_USB_STATE_DVB)
-			dvb_dmx_swfilter(&d->demux, (u8*) urb->transfer_buffer,urb->actual_length);
-	} else
-		deb_ts("URB dropped because of feedcount.\n");
+	if (d->feedcount > 0) {
+		if (d->state & DVB_USB_STATE_DVB) {
+			switch (ptype) {
+				case PIPE_ISOCHRONOUS:
+					b = (u8 *) urb->transfer_buffer;
+					for (i = 0; i < urb->number_of_packets; i++) {
+						if (urb->iso_frame_desc[i].status != 0)
+							deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
+						else if (urb->iso_frame_desc[i].actual_length > 0) {
+								dvb_dmx_swfilter(&d->demux,b + urb->iso_frame_desc[i].offset,
+										urb->iso_frame_desc[i].actual_length);
+							}
+						urb->iso_frame_desc[i].status = 0;
+						urb->iso_frame_desc[i].actual_length = 0;
+					}
+					debug_dump(b,20,deb_ts);
+					break;
+				case PIPE_BULK:
+					if (urb->actual_length > 0)
+						dvb_dmx_swfilter(&d->demux, (u8 *) urb->transfer_buffer,urb->actual_length);
+					break;
+				default:
+					err("unkown endpoint type in completition handler.");
+					return;
+			}
+		}
+	}
 
 	usb_submit_urb(urb,GFP_ATOMIC);
 }
@@ -94,7 +126,7 @@
 {
 	int i;
 	for (i = 0; i < d->urbs_submitted; i++) {
-		deb_info("killing URB no. %d.\n",i);
+		deb_ts("killing URB no. %d.\n",i);
 
 		/* stop the URB */
 		usb_kill_urb(d->urb_list[i]);
@@ -107,9 +139,9 @@
 {
 	int i,ret;
 	for (i = 0; i < d->urbs_initialized; i++) {
-		deb_info("submitting URB no. %d\n",i);
+		deb_ts("submitting URB no. %d\n",i);
 		if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) {
-			err("could not submit URB no. %d - get them all back\n",i);
+			err("could not submit URB no. %d - get them all back",i);
 			dvb_usb_urb_kill(d);
 			return ret;
 		}
@@ -118,32 +150,78 @@
 	return 0;
 }
 
-static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
+static int dvb_usb_free_stream_buffers(struct dvb_usb_device *d)
 {
-	int i,bufsize = d->props.urb.count * d->props.urb.u.bulk.buffersize;
+	if (d->state & DVB_USB_STATE_URB_BUF) {
+		while (d->buf_num) {
+			d->buf_num--;
+			deb_mem("freeing buffer %d\n",d->buf_num);
+			usb_buffer_free(d->udev, d->buf_size,
+					d->buf_list[d->buf_num], d->dma_addr[d->buf_num]);
+		}
+		kfree(d->buf_list);
+		kfree(d->dma_addr);
+	}
 
-	deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
-	/* allocate the actual buffer for the URBs */
-	if ((d->buffer =  usb_buffer_alloc(d->udev, bufsize, SLAB_ATOMIC, &d->dma_handle)) == NULL) {
-		deb_info("not enough memory for urb-buffer allocation.\n");
+	d->state &= ~DVB_USB_STATE_URB_BUF;
+
+	return 0;
+}
+
+static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, unsigned long size)
+{
+	d->buf_num = 0;
+	d->buf_size = size;
+
+	deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
+
+	if ((d->buf_list = kmalloc(num*sizeof(u8 *), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+	if ((d->dma_addr = kmalloc(num*sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) {
+		kfree(d->buf_list);
 		return -ENOMEM;
 	}
-	deb_info("allocation successful\n");
-	memset(d->buffer,0,bufsize);
+	memset(d->buf_list,0,num*sizeof(u8 *));
+	memset(d->dma_addr,0,num*sizeof(dma_addr_t));
 
 	d->state |= DVB_USB_STATE_URB_BUF;
 
-	/* allocate the URBs */
-	for (i = 0; i < d->props.urb.count; i++) {
-		if (!(d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
+	for (d->buf_num = 0; d->buf_num < num; d->buf_num++) {
+		deb_mem("allocating buffer %d\n",d->buf_num);
+		if (( d->buf_list[d->buf_num] =
+					usb_buffer_alloc(d->udev, size, SLAB_ATOMIC,
+					&d->dma_addr[d->buf_num]) ) == NULL) {
+			deb_mem("not enough memory for urb-buffer allocation.\n");
+			dvb_usb_free_stream_buffers(d);
 			return -ENOMEM;
 		}
+		deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]);
+		memset(d->buf_list[d->buf_num],0,size);
+	}
+	deb_mem("allocation successful\n");
+
+	return 0;
+}
+
+static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
+{
+	int i;
+
+	if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
+					d->props.urb.u.bulk.buffersize)) < 0)
+		return i;
+
+	/* allocate the URBs */
+	for (i = 0; i < d->props.urb.count; i++) {
+		if ((d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
+			return -ENOMEM;
 
 		usb_fill_bulk_urb( d->urb_list[i], d->udev,
 				usb_rcvbulkpipe(d->udev,d->props.urb.endpoint),
-				&d->buffer[i*d->props.urb.u.bulk.buffersize],
+				d->buf_list[i],
 				d->props.urb.u.bulk.buffersize,
-				dvb_usb_bulk_urb_complete, d);
+				dvb_usb_urb_complete, d);
 
 		d->urb_list[i]->transfer_flags = 0;
 		d->urbs_initialized++;
@@ -151,6 +229,47 @@
 	return 0;
 }
 
+static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d)
+{
+	int i,j;
+
+	if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
+					d->props.urb.u.isoc.framesize*d->props.urb.u.isoc.framesperurb)) < 0)
+		return i;
+
+	/* allocate the URBs */
+	for (i = 0; i < d->props.urb.count; i++) {
+		struct urb *urb;
+		int frame_offset = 0;
+		if ((d->urb_list[i] =
+					usb_alloc_urb(d->props.urb.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
+			return -ENOMEM;
+
+		urb = d->urb_list[i];
+
+		urb->dev = d->udev;
+		urb->context = d;
+		urb->complete = dvb_usb_urb_complete;
+		urb->pipe = usb_rcvisocpipe(d->udev,d->props.urb.endpoint);
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = d->props.urb.u.isoc.interval;
+		urb->number_of_packets = d->props.urb.u.isoc.framesperurb;
+		urb->transfer_buffer_length = d->buf_size;
+		urb->transfer_buffer = d->buf_list[i];
+		urb->transfer_dma = d->dma_addr[i];
+
+		for (j = 0; j < d->props.urb.u.isoc.framesperurb; j++) {
+			urb->iso_frame_desc[j].offset = frame_offset;
+			urb->iso_frame_desc[j].length = d->props.urb.u.isoc.framesize;
+			frame_offset += d->props.urb.u.isoc.framesize;
+		}
+
+		d->urbs_initialized++;
+	}
+	return 0;
+
+}
+
 int dvb_usb_urb_init(struct dvb_usb_device *d)
 {
 	/*
@@ -174,8 +293,7 @@
 		case DVB_USB_BULK:
 			return dvb_usb_bulk_urb_init(d);
 		case DVB_USB_ISOC:
-			err("isochronous transfer not yet implemented in dvb-usb.");
-			return -EINVAL;
+			return dvb_usb_isoc_urb_init(d);
 		default:
 			err("unkown URB-type for data transfer.");
 			return -EINVAL;
@@ -191,7 +309,7 @@
 	if (d->state & DVB_USB_STATE_URB_LIST) {
 		for (i = 0; i < d->urbs_initialized; i++) {
 			if (d->urb_list[i] != NULL) {
-				deb_info("freeing URB no. %d.\n",i);
+				deb_mem("freeing URB no. %d.\n",i);
 				/* free the URBs */
 				usb_free_urb(d->urb_list[i]);
 			}
@@ -202,10 +320,6 @@
 		d->state &= ~DVB_USB_STATE_URB_LIST;
 	}
 
-	if (d->state & DVB_USB_STATE_URB_BUF)
-		usb_buffer_free(d->udev, d->props.urb.u.bulk.buffersize * d->props.urb.count,
-				d->buffer, d->dma_handle);
-
-	d->state &= ~DVB_USB_STATE_URB_BUF;
+	dvb_usb_free_stream_buffers(d);
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index abcee19..a80567c 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -189,12 +189,13 @@
 			struct {
 				int framesperurb;
 				int framesize;
+				int interval;
 			} isoc;
 		} u;
 	} urb;
 
 	int num_device_descs;
-	struct dvb_usb_device_description devices[8];
+	struct dvb_usb_device_description devices[9];
 };
 
 
@@ -207,19 +208,28 @@
  * @udev: pointer to the device's struct usb_device.
  * @urb_list: array of dynamically allocated struct urb for the MPEG2-TS-
  *  streaming.
- * @buffer: buffer used to streaming.
- * @dma_handle: dma_addr_t for buffer.
+ *
+ * @buf_num: number of buffer allocated.
+ * @buf_size: size of each buffer in buf_list.
+ * @buf_list: array containing all allocate buffers for streaming.
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list.
+ *
  * @urbs_initialized: number of URBs initialized.
  * @urbs_submitted: number of URBs submitted.
+ *
  * @feedcount: number of reqested feeds (used for streaming-activation)
  * @pid_filtering: is hardware pid_filtering used or not.
+ *
  * @usb_sem: semaphore of USB control messages (reading needs two messages)
  * @i2c_sem: semaphore for i2c-transfers
+ *
  * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
  * @pll_addr: I2C address of the tuner for programming
  * @pll_init: array containing the initialization buffer
  * @pll_desc: pointer to the appropriate struct dvb_pll_desc
- * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod
+ *
+ * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
+ *
  * @dvb_adap: device's dvb_adapter.
  * @dmxdev: device's dmxdev.
  * @demux: device's software demuxer.
@@ -253,8 +263,12 @@
 	/* usb */
 	struct usb_device *udev;
 	struct urb **urb_list;
-	u8 *buffer;
-	dma_addr_t dma_handle;
+
+	int buf_num;
+	unsigned long buf_size;
+	u8 **buf_list;
+	dma_addr_t *dma_addr;
+
 	int urbs_initialized;
 	int urbs_submitted;
 
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index 9d83781..258a92b 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -203,7 +203,7 @@
 
 static struct usb_driver nova_t_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "Hauppauge WinTV-NOVA-T usb2",
+	.name		= "dvb_usb_nova_t_usb2",
 	.probe		= nova_t_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table	= nova_t_table,
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index aa56042..2112ac3 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -129,7 +129,7 @@
 
 static struct usb_driver umt_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "HanfTek UMT-010 USB2.0 DVB-T devices",
+	.name		= "dvb_usb_umt_010",
 	.probe		= umt_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table	= umt_table,
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 02ecc9a..5adc5d6 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -44,7 +44,7 @@
 	if (usb_control_msg(d->udev,
 			usb_sndctrlpipe(d->udev,0),
 			TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
-			outbuf, 20, 2*HZ) != 20) {
+			outbuf, 20, 2000) != 20) {
 		err("USB control message 'out' went wrong.");
 		ret = -EIO;
 		goto unlock;
@@ -55,7 +55,7 @@
 	if (usb_control_msg(d->udev,
 			usb_rcvctrlpipe(d->udev,0),
 			TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-			inbuf, 12, 2*HZ) != 12) {
+			inbuf, 12, 2000) != 12) {
 		err("USB control message 'in' went wrong.");
 		ret = -EIO;
 		goto unlock;
@@ -94,13 +94,38 @@
 /* The keymapping struct. Somehow this should be loaded to the driver, but
  * currently it is hardcoded. */
 static struct dvb_usb_rc_key vp7045_rc_keys[] = {
-	/* insert the keys like this. to make the raw keys visible, enable
-	 * debug=0x04 when loading dvb-usb-vp7045. */
-
-	/* these keys are probably wrong. I don't have a working IR-receiver on my
-	 * vp7045, so I can't test it.  Patches are welcome. */
-	{ 0x00, 0x01, KEY_1 },
-	{ 0x00, 0x02, KEY_2 },
+	{ 0x00, 0x16, KEY_POWER },
+	{ 0x00, 0x10, KEY_MUTE },
+	{ 0x00, 0x03, KEY_1 },
+	{ 0x00, 0x01, KEY_2 },
+	{ 0x00, 0x06, KEY_3 },
+	{ 0x00, 0x09, KEY_4 },
+	{ 0x00, 0x1d, KEY_5 },
+	{ 0x00, 0x1f, KEY_6 },
+	{ 0x00, 0x0d, KEY_7 },
+	{ 0x00, 0x19, KEY_8 },
+	{ 0x00, 0x1b, KEY_9 },
+	{ 0x00, 0x15, KEY_0 },
+	{ 0x00, 0x05, KEY_CHANNELUP },
+	{ 0x00, 0x02, KEY_CHANNELDOWN },
+	{ 0x00, 0x1e, KEY_VOLUMEUP },
+	{ 0x00, 0x0a, KEY_VOLUMEDOWN },
+	{ 0x00, 0x11, KEY_RECORD },
+	{ 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+	{ 0x00, 0x14, KEY_PLAY },
+	{ 0x00, 0x1a, KEY_STOP },
+	{ 0x00, 0x40, KEY_REWIND },
+	{ 0x00, 0x12, KEY_FASTFORWARD },
+	{ 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+	{ 0x00, 0x4c, KEY_PAUSE },
+	{ 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
+	{ 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+	{ 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
+	{ 0x00, 0x1c, KEY_EPG }, /* EPG */
+	{ 0x00, 0x00, KEY_TAB }, /* Tab */
+	{ 0x00, 0x48, KEY_INFO }, /* Preview */
+	{ 0x00, 0x04, KEY_LIST }, /* RecordList */
+	{ 0x00, 0x0f, KEY_TEXT } /* Teletext */
 };
 
 static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state)
@@ -230,7 +255,7 @@
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver vp7045_usb_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "dvb-usb-vp7045",
+	.name		= "dvb_usb_vp7045",
 	.probe 		= vp7045_usb_probe,
 	.disconnect = dvb_usb_device_exit,
 	.id_table 	= vp7045_usb_table,
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index b4fddf5..d847c62 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -40,6 +40,12 @@
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_S5H1420
+	tristate "Samsung S5H1420 based"
+	depends on DVB_CORE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
 comment "DVB-T (terrestrial) frontends"
 	depends on DVB_CORE
 
@@ -181,4 +187,11 @@
 	  An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
 	  support this frontend.
 
+config DVB_LGDT3302
+	tristate "LGDT3302 based (DViCO FusionHDTV3 Gold)"
+	depends on DVB_CORE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
 endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 91d6d35..de5e240 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -29,3 +29,5 @@
 obj-$(CONFIG_DVB_OR51211) += or51211.o
 obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
+obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
+obj-$(CONFIG_DVB_LGDT3302) += lgdt3302.o
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index f4aa441..9f63929 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -76,7 +76,6 @@
 	0x49, 0x56,
 	0x6b, 0x1e,
 	0xc8, 0x02,
-	0xf8, 0x02,
 	0xf9, 0x00,
 	0xfa, 0x00,
 	0xfb, 0x00,
@@ -203,7 +202,7 @@
 	struct cx22702_state* state = fe->demodulator_priv;
 
 	/* set PLL */
-        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+	cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
 	if (state->config->pll_set) {
 		state->config->pll_set(fe, p);
 	} else if (state->config->pll_desc) {
@@ -217,7 +216,7 @@
 	} else {
 		BUG();
 	}
-        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+	cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
 
 	/* set inversion */
 	cx22702_set_inversion (state, p->inversion);
@@ -256,7 +255,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 */
-		printk("%s: Autodetecting\n",__FUNCTION__);
+		dprintk("%s: Autodetecting\n",__FUNCTION__);
 		return 0;
 	}
 
@@ -347,10 +346,11 @@
 	for (i=0; i<sizeof(init_tab); i+=2)
 		cx22702_writereg (state, init_tab[i], init_tab[i+1]);
 
+	cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
 
 	/* init PLL */
 	if (state->config->pll_init) {
-	        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+		cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
 		state->config->pll_init(fe);
 		cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
 	}
@@ -440,8 +440,10 @@
 
 	/* RS Uncorrectable Packet Count then reset */
 	_ucblocks = cx22702_readreg (state, 0xE3);
-	if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks);
-	else *ucblocks = state->prevUCBlocks - _ucblocks;
+	if (state->prevUCBlocks < _ucblocks)
+		*ucblocks = (_ucblocks - state->prevUCBlocks);
+	else
+		*ucblocks = state->prevUCBlocks - _ucblocks;
 	state->prevUCBlocks = _ucblocks;
 
 	return 0;
@@ -457,6 +459,12 @@
 	return cx22702_get_tps (state, &p->u.ofdm);
 }
 
+static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
 static void cx22702_release(struct dvb_frontend* fe)
 {
 	struct cx22702_state* state = fe->demodulator_priv;
@@ -472,7 +480,8 @@
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
-	if (state == NULL) goto error;
+	if (state == NULL)
+		goto error;
 
 	/* setup the state */
 	state->config = config;
@@ -481,7 +490,8 @@
 	state->prevUCBlocks = 0;
 
 	/* check if the demod is there */
-	if (cx22702_readreg(state, 0x1f) != 0x3) goto error;
+	if (cx22702_readreg(state, 0x1f) != 0x3)
+		goto error;
 
 	/* create dvb_frontend */
 	state->frontend.ops = &state->ops;
@@ -514,6 +524,7 @@
 
 	.set_frontend = cx22702_set_tps,
 	.get_frontend = cx22702_get_frontend,
+	.get_tune_settings = cx22702_get_tune_settings,
 
 	.read_status = cx22702_read_status,
 	.read_ber = cx22702_read_ber,
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 559fdb9..11f8680 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -35,6 +35,11 @@
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
+	/* serial/parallel output */
+#define CX22702_PARALLEL_OUTPUT 0
+#define CX22702_SERIAL_OUTPUT   1
+	u8 output_mode;
+
 	/* PLL maintenance */
 	u8 pll_address;
 	struct dvb_pll_desc *pll_desc;
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index f73b5f4..5afeaa9 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -55,7 +55,7 @@
 };
 EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
 
-static void thomson_dtt759x_bw(u8 *buf, int bandwidth)
+static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
 {
 	if (BANDWIDTH_7_MHZ == bandwidth)
 		buf[3] |= 0x10;
@@ -93,6 +93,32 @@
 };
 EXPORT_SYMBOL(dvb_pll_lg_z201);
 
+struct dvb_pll_desc dvb_pll_microtune_4042 = {
+	.name  = "Microtune 4042 FI5",
+	.min   =  57000000,
+	.max   = 858000000,
+	.count = 3,
+	.entries = {
+		{ 162000000, 44000000, 62500, 0x8e, 0xa1 },
+		{ 457000000, 44000000, 62500, 0x8e, 0x91 },
+		{ 999999999, 44000000, 62500, 0x8e, 0x31 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_microtune_4042);
+
+struct dvb_pll_desc dvb_pll_thomson_dtt7611 = {
+	.name  = "Thomson dtt7611",
+	.min   =  44000000,
+	.max   = 958000000,
+	.count = 3,
+	.entries = {
+		{ 157250000, 44000000, 62500, 0x8e, 0x39 },
+		{ 454000000, 44000000, 62500, 0x8e, 0x3a },
+		{ 999999999, 44000000, 62500, 0x8e, 0x3c },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt7611);
+
 struct dvb_pll_desc dvb_pll_unknown_1 = {
 	.name  = "unknown 1", /* used by dntv live dvb-t */
 	.min   = 174000000,
@@ -146,7 +172,7 @@
 /* Philips TDA6650/TDA6651
  * used in Panasonic ENV77H11D5
  */
-static void tda665x_bw(u8 *buf, int bandwidth)
+static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
 {
 	if (bandwidth == BANDWIDTH_8_MHZ)
 		buf[3] |= 0x08;
@@ -178,7 +204,7 @@
 /* Infineon TUA6034
  * used in LG TDTP E102P
  */
-static void tua6034_bw(u8 *buf, int bandwidth)
+static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
 {
 	if (BANDWIDTH_7_MHZ != bandwidth)
 		buf[3] |= 0x08;
@@ -198,6 +224,57 @@
 };
 EXPORT_SYMBOL(dvb_pll_tua6034);
 
+/* Philips FMD1216ME
+ * used in Medion Hybrid PCMCIA card and USB Box
+ */
+static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+{
+	if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+		buf[3] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_fmd1216me = {
+	.name = "Philips FMD1216ME",
+	.min = 50870000,
+	.max = 858000000,
+	.setbw = fmd1216me_bw,
+	.count = 7,
+	.entries = {
+		{ 143870000, 36213333, 166667, 0xbc, 0x41 },
+		{ 158870000, 36213333, 166667, 0xf4, 0x41 },
+		{ 329870000, 36213333, 166667, 0xbc, 0x42 },
+		{ 441870000, 36213333, 166667, 0xf4, 0x42 },
+		{ 625870000, 36213333, 166667, 0xbc, 0x44 },
+		{ 803870000, 36213333, 166667, 0xf4, 0x44 },
+		{ 999999999, 36213333, 166667, 0xfc, 0x44 },
+	}
+};
+EXPORT_SYMBOL(dvb_pll_fmd1216me);
+
+/* ALPS TDED4
+ * used in Nebula-Cards and USB boxes
+ */
+static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+{
+	if (bandwidth == BANDWIDTH_8_MHZ)
+		buf[3] |= 0x04;
+}
+
+struct dvb_pll_desc dvb_pll_tded4 = {
+	.name = "ALPS TDED4",
+	.min = 47000000,
+	.max = 863000000,
+	.setbw = tded4_bw,
+	.count = 4,
+	.entries = {
+		{ 153000000, 36166667, 166667, 0x85, 0x01 },
+		{ 470000000, 36166667, 166667, 0x85, 0x02 },
+		{ 823000000, 36166667, 166667, 0x85, 0x08 },
+		{ 999999999, 36166667, 166667, 0x85, 0x88 },
+	}
+};
+EXPORT_SYMBOL(dvb_pll_tded4);
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
@@ -231,7 +308,7 @@
 	buf[3] = desc->entries[i].cb2;
 
 	if (desc->setbw)
-		desc->setbw(buf, bandwidth);
+		desc->setbw(buf, freq, bandwidth);
 
 	if (debug)
 		printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index b796778..cb79475 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -9,7 +9,7 @@
 	char *name;
 	u32  min;
 	u32  max;
-	void (*setbw)(u8 *buf, int bandwidth);
+	void (*setbw)(u8 *buf, u32 freq, int bandwidth);
 	int  count;
 	struct {
 		u32 limit;
@@ -24,12 +24,16 @@
 extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
 extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
 extern struct dvb_pll_desc dvb_pll_lg_z201;
+extern struct dvb_pll_desc dvb_pll_microtune_4042;
+extern struct dvb_pll_desc dvb_pll_thomson_dtt7611;
 extern struct dvb_pll_desc dvb_pll_unknown_1;
 
 extern struct dvb_pll_desc dvb_pll_tua6010xs;
 extern struct dvb_pll_desc dvb_pll_env57h1xd5;
 extern struct dvb_pll_desc dvb_pll_tua6034;
 extern struct dvb_pll_desc dvb_pll_tda665x;
+extern struct dvb_pll_desc dvb_pll_fmd1216me;
+extern struct dvb_pll_desc dvb_pll_tded4;
 
 int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 		      u32 freq, int bandwidth);
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 031a1dd..faaad1a 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -474,11 +474,12 @@
 	return 0;
 }
 
-static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+static int l64781_get_tune_settings(struct dvb_frontend* fe,
+				    struct dvb_frontend_tune_settings* fesettings)
 {
-        fesettings->min_delay_ms = 200;
-        fesettings->step_size = 166667;
-        fesettings->max_drift = 166667*2;
+        fesettings->min_delay_ms = 4000;
+        fesettings->step_size = 0;
+        fesettings->max_drift = 0;
         return 0;
 }
 
diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c
new file mode 100644
index 0000000..09c9142
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.c
@@ -0,0 +1,611 @@
+/*
+ * $Id: lgdt3302.c,v 1.5 2005/07/07 03:47:15 mkrufky Exp $
+ *
+ *    Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
+ *
+ *    Based on code from  Kirk Lapray <kirk_lapray@bigfoot.com>
+ *                           Copyright (C) 2005
+ *
+ *    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.
+ *
+ */
+
+/*
+ *                      NOTES ABOUT THIS DRIVER
+ *
+ * This driver supports DViCO FusionHDTV 3 Gold under Linux.
+ *
+ * TODO:
+ * BER and signal strength always return 0.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "lgdt3302_priv.h"
+#include "lgdt3302.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"Turn on/off lgdt3302 frontend debugging (default:off).");
+#define dprintk(args...) \
+do { \
+if (debug) printk(KERN_DEBUG "lgdt3302: " args); \
+} while (0)
+
+struct lgdt3302_state
+{
+	struct i2c_adapter* i2c;
+	struct dvb_frontend_ops ops;
+
+	/* Configuration settings */
+	const struct lgdt3302_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* Demodulator private data */
+	fe_modulation_t current_modulation;
+
+	/* Tuner private data */
+	u32 current_frequency;
+};
+
+static int i2c_writebytes (struct lgdt3302_state* state,
+			   u8 addr, /* demod_address or pll_address */
+			   u8 *buf, /* data bytes to send */
+			   int len  /* number of bytes to send */ )
+{
+	if (addr == state->config->pll_address) {
+		struct i2c_msg msg =
+			{ .addr = addr, .flags = 0, .buf = buf,  .len = len };
+		int err;
+
+		if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+			printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
+			return -EREMOTEIO;
+		}
+	} else {
+		u8 tmp[] = { buf[0], buf[1] };
+		struct i2c_msg msg =
+			{ .addr = addr, .flags = 0, .buf = tmp,  .len = 2 };
+		int err;
+		int i;
+
+		for (i=1; i<len; i++) {
+			tmp[1] = buf[i];
+			if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+				printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
+				return -EREMOTEIO;
+			}
+			tmp[0]++;
+		}
+	}
+	return 0;
+}
+static int i2c_readbytes (struct lgdt3302_state* state,
+			  u8 addr, /* demod_address or pll_address */
+			  u8 *buf, /* holds data bytes read */
+			  int len  /* number of bytes to read */ )
+{
+	struct i2c_msg msg =
+		{ .addr = addr, .flags = I2C_M_RD, .buf = buf,  .len = len };
+	int err;
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk(KERN_WARNING "lgdt3302: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/*
+ * This routine writes the register (reg) to the demod bus
+ * then reads the data returned for (len) bytes.
+ */
+
+static u8 i2c_selectreadbytes (struct lgdt3302_state* state,
+			       enum I2C_REG reg, u8* buf, int len)
+{
+	u8 wr [] = { reg };
+	struct i2c_msg msg [] = {
+		{ .addr = state->config->demod_address,
+		  .flags = 0, .buf = wr,  .len = 1 },
+		{ .addr = state->config->demod_address,
+		  .flags = I2C_M_RD, .buf = buf, .len = len },
+	};
+	int ret;
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2) {
+		printk(KERN_WARNING "lgdt3302: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret);
+	} else {
+		ret = 0;
+	}
+	return ret;
+}
+
+/* Software reset */
+int lgdt3302_SwReset(struct lgdt3302_state* state)
+{
+	u8 ret;
+	u8 reset[] = {
+		IRQ_MASK,
+		0x00 /* bit 6 is active low software reset
+		      *	bits 5-0 are 1 to mask interrupts */
+	};
+
+	ret = i2c_writebytes(state,
+			     state->config->demod_address,
+			     reset, sizeof(reset));
+	if (ret == 0) {
+		/* spec says reset takes 100 ns why wait */
+		/* mdelay(100);    */ /* keep low for 100mS */
+		reset[1] = 0x7f;      /* force reset high (inactive)
+				       * and unmask interrupts */
+		ret = i2c_writebytes(state,
+				     state->config->demod_address,
+				     reset, sizeof(reset));
+	}
+	/* Spec does not indicate a need for this either */
+	/*mdelay(5); */               /* wait 5 msec before doing more */
+	return ret;
+}
+
+static int lgdt3302_init(struct dvb_frontend* fe)
+{
+	/* Hardware reset is done using gpio[0] of cx23880x chip.
+	 * I'd like to do it here, but don't know how to find chip address.
+	 * cx88-cards.c arranges for the reset bit to be inactive (high).
+	 * Maybe there needs to be a callable function in cx88-core or
+	 * the caller of this function needs to do it. */
+
+	dprintk("%s entered\n", __FUNCTION__);
+	return lgdt3302_SwReset((struct lgdt3302_state*) fe->demodulator_priv);
+}
+
+static int lgdt3302_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	*ber = 0; /* Dummy out for now */
+	return 0;
+}
+
+static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+	u8 buf[2];
+
+	i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf));
+
+	*ucblocks = (buf[0] << 8) | buf[1];
+	return 0;
+}
+
+static int lgdt3302_set_parameters(struct dvb_frontend* fe,
+				   struct dvb_frontend_parameters *param)
+{
+	u8 buf[4];
+	struct lgdt3302_state* state =
+		(struct lgdt3302_state*) fe->demodulator_priv;
+
+	/* Use 50MHz parameter values from spec sheet since xtal is 50 */
+	static u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
+	static u8 vsb_freq_cfg[]   = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 };
+	static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb };
+	static u8 agc_rf_cfg[]     = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 };
+	static u8 agc_ctrl_cfg[]   = { AGC_FUNC_CTRL2, 0xc6, 0x40 };
+	static u8 agc_delay_cfg[]  = { AGC_DELAY0, 0x00, 0x00, 0x00 };
+	static u8 agc_loop_cfg[]   = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a };
+
+	/* Change only if we are actually changing the modulation */
+	if (state->current_modulation != param->u.vsb.modulation) {
+		switch(param->u.vsb.modulation) {
+		case VSB_8:
+			dprintk("%s: VSB_8 MODE\n", __FUNCTION__);
+
+			/* Select VSB mode and serial MPEG interface */
+			top_ctrl_cfg[1] = 0x07;
+			break;
+
+		case QAM_64:
+			dprintk("%s: QAM_64 MODE\n", __FUNCTION__);
+
+			/* Select QAM_64 mode and serial MPEG interface */
+			top_ctrl_cfg[1] = 0x04;
+			break;
+
+		case QAM_256:
+			dprintk("%s: QAM_256 MODE\n", __FUNCTION__);
+
+			/* Select QAM_256 mode and serial MPEG interface */
+			top_ctrl_cfg[1] = 0x05;
+			break;
+		default:
+			printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation);
+			return -1;
+		}
+		/* Initializations common to all modes */
+
+		/* Select the requested mode */
+		i2c_writebytes(state, state->config->demod_address,
+			       top_ctrl_cfg, sizeof(top_ctrl_cfg));
+
+		/* Change the value of IFBW[11:0]
+		   of AGC IF/RF loop filter bandwidth register */
+		i2c_writebytes(state, state->config->demod_address,
+			       agc_rf_cfg, sizeof(agc_rf_cfg));
+
+		/* Change the value of bit 6, 'nINAGCBY' and
+		   'NSSEL[1:0] of ACG function control register 2 */
+		/* Change the value of bit 6 'RFFIX'
+		   of AGC function control register 3 */
+		i2c_writebytes(state, state->config->demod_address,
+			       agc_ctrl_cfg, sizeof(agc_ctrl_cfg));
+
+		/* Change the TPCLK pin polarity
+		   data is valid on falling clock */
+		i2c_writebytes(state, state->config->demod_address,
+			       demux_ctrl_cfg, sizeof(demux_ctrl_cfg));
+
+		if (param->u.vsb.modulation == VSB_8) {
+			/* Initialization for VSB modes only */
+			/* Change the value of NCOCTFV[25:0]of carrier
+			   recovery center frequency register for VSB */
+			i2c_writebytes(state, state->config->demod_address,
+				       vsb_freq_cfg, sizeof(vsb_freq_cfg));
+		} else {
+			/* Initialization for QAM modes only */
+			/* Set the value of 'INLVTHD' register 0x2a/0x2c
+			   to value from 'IFACC' register 0x39/0x3b -1 */
+			int value;
+			i2c_selectreadbytes(state, AGC_RFIF_ACC0,
+					    &agc_delay_cfg[1], 3);
+			value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3];
+			value = value -1;
+			dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value);
+			agc_delay_cfg[1] = (value >> 8) & 0x0f;
+			agc_delay_cfg[2] = 0x00;
+			agc_delay_cfg[3] = value & 0xff;
+			i2c_writebytes(state, state->config->demod_address,
+				       agc_delay_cfg, sizeof(agc_delay_cfg));
+
+			/* Change the value of IAGCBW[15:8]
+			   of inner AGC loop filter bandwith */
+			i2c_writebytes(state, state->config->demod_address,
+				       agc_loop_cfg, sizeof(agc_loop_cfg));
+		}
+
+		state->config->set_ts_params(fe, 0);
+		lgdt3302_SwReset(state);
+		state->current_modulation = param->u.vsb.modulation;
+	}
+
+	/* Change only if we are actually changing the channel */
+	if (state->current_frequency != param->frequency) {
+		dvb_pll_configure(state->config->pll_desc, buf,
+				  param->frequency, 0);
+		dprintk("%s: tuner bytes: 0x%02x 0x%02x "
+			"0x%02x 0x%02x\n", __FUNCTION__, buf[0],buf[1],buf[2],buf[3]);
+		i2c_writebytes(state, state->config->pll_address ,buf, 4);
+
+		/* Check the status of the tuner pll */
+		i2c_readbytes(state, state->config->pll_address, buf, 1);
+		dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
+
+		lgdt3302_SwReset(state);
+
+		/* Update current frequency */
+		state->current_frequency = param->frequency;
+	}
+	return 0;
+}
+
+static int lgdt3302_get_frontend(struct dvb_frontend* fe,
+				 struct dvb_frontend_parameters* param)
+{
+	struct lgdt3302_state *state = fe->demodulator_priv;
+	param->frequency = state->current_frequency;
+	return 0;
+}
+
+static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+	u8 buf[3];
+
+	*status = 0; /* Reset status result */
+
+	/* Check the status of the tuner pll */
+	i2c_readbytes(state, state->config->pll_address, buf, 1);
+	dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
+	if ((buf[0] & 0xc0) != 0x40)
+		return 0; /* Tuner PLL not locked or not powered on */
+
+	/*
+	 * You must set the Mask bits to 1 in the IRQ_MASK in order
+	 * to see that status bit in the IRQ_STATUS register.
+	 * This is done in SwReset();
+	 */
+
+	/* AGC status register */
+	i2c_selectreadbytes(state, AGC_STATUS, buf, 1);
+	dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]);
+	if ((buf[0] & 0x0c) == 0x8){
+		/* Test signal does not exist flag */
+		/* as well as the AGC lock flag.   */
+		*status |= FE_HAS_SIGNAL;
+	} else {
+		/* Without a signal all other status bits are meaningless */
+		return 0;
+	}
+
+	/* signal status */
+	i2c_selectreadbytes(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]);
+
+#if 0
+	/* Alternative method to check for a signal */
+	/* using the SNR good/bad interrupts.   */
+	if ((buf[2] & 0x30) == 0x10)
+		*status |= FE_HAS_SIGNAL;
+#endif
+
+	/* sync status */
+	if ((buf[2] & 0x03) == 0x01) {
+		*status |= FE_HAS_SYNC;
+	}
+
+	/* FEC error status */
+	if ((buf[2] & 0x0c) == 0x08) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI;
+	}
+
+	/* Carrier Recovery Lock Status Register */
+	i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1);
+	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]);
+	switch (state->current_modulation) {
+	case QAM_256:
+	case QAM_64:
+		/* Need to undestand why there are 3 lock levels here */
+		if ((buf[0] & 0x07) == 0x07)
+			*status |= FE_HAS_CARRIER;
+		break;
+	case VSB_8:
+		if ((buf[0] & 0x80) == 0x80)
+			*status |= FE_HAS_CARRIER;
+		break;
+	default:
+		printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__);
+	}
+
+	return 0;
+}
+
+static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	/* not directly available. */
+	return 0;
+}
+
+static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+#ifdef SNR_IN_DB
+	/*
+	 * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
+	 * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
+	 * respectively. The following tables are built on these formulas.
+	 * The usual definition is SNR = 20 log10(signal/noise)
+	 * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
+	 *
+	 * This table is a an ordered list of noise values computed by the
+	 * formula from the spec sheet such that the index into the table
+	 * starting at 43 or 45 is the SNR value in db. There are duplicate noise
+	 * value entries at the beginning because the SNR varies more than
+	 * 1 db for a change of 1 digit in noise at very small values of noise.
+	 *
+	 * Examples from SNR_EQ table:
+	 * noise SNR
+	 *   0    43
+	 *   1    42
+	 *   2    39
+	 *   3    37
+	 *   4    36
+	 *   5    35
+	 *   6    34
+	 *   7    33
+	 *   8    33
+	 *   9    32
+	 *   10   32
+	 *   11   31
+	 *   12   31
+	 *   13   30
+	 */
+
+	static const u32 SNR_EQ[] =
+		{ 1,     2,      2,      2, 3,      3,      4,     4,     5,     7,
+		  9,     11,     13,     17, 21,     26,     33,    41,    52,    65,
+		  81,    102,    129,    162, 204,    257,    323,   406,   511,   644,
+		  810,   1020,   1284,   1616, 2035,   2561,   3224,  4059,  5110,  6433,
+		  8098,  10195,  12835,  16158, 20341,  25608,  32238, 40585, 51094, 64323,
+		  80978, 101945, 128341, 161571, 203406, 256073, 0x40000
+		};
+
+	static const u32 SNR_PH[] =
+		{ 1,     2,      2,      2,      3,      3,     4,     5,     6,     8,
+		  10,    12,     15,     19,     23,     29, 37,    46,    58,    73,
+		  91,    115,    144,    182,    229,    288, 362,   456,   574,   722,
+		  909,   1144,   1440,   1813,   2282,   2873, 3617,  4553,  5732,  7216,
+		  9084,  11436,  14396,  18124,  22817,  28724,  36161, 45524, 57312, 72151,
+		  90833, 114351, 143960, 181235, 228161, 0x040000
+		};
+
+	static u8 buf[5];/* read data buffer */
+	static u32 noise;   /* noise value */
+	static u32 snr_db;  /* index into SNR_EQ[] */
+	struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+
+	/* read both equalizer and pase tracker noise data */
+	i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
+
+	if (state->current_modulation == VSB_8) {
+		/* Equalizer Mean-Square Error Register for VSB */
+		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+
+		/*
+		 * Look up noise value in table.
+		 * A better search algorithm could be used...
+		 * watch out there are duplicate entries.
+		 */
+		for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
+			if (noise < SNR_EQ[snr_db]) {
+				*snr = 43 - snr_db;
+				break;
+			}
+		}
+	} else {
+		/* Phase Tracker Mean-Square Error Register for QAM */
+		noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+
+		/* Look up noise value in table. */
+		for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
+			if (noise < SNR_PH[snr_db]) {
+				*snr = 45 - snr_db;
+				break;
+			}
+		}
+	}
+#else
+	/* Return the raw noise value */
+	static u8 buf[5];/* read data buffer */
+	static u32 noise;   /* noise value */
+	struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+
+	/* read both equalizer and pase tracker noise data */
+	i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
+
+	if (state->current_modulation == VSB_8) {
+		/* Equalizer Mean-Square Error Register for VSB */
+		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+	} else {
+		/* Phase Tracker Mean-Square Error Register for QAM */
+		noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+	}
+
+	/* Small values for noise mean signal is better so invert noise */
+	/* Noise is 19 bit value so discard 3 LSB*/
+	*snr = ~noise>>3;
+#endif
+
+	dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
+
+	return 0;
+}
+
+static int lgdt3302_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+	/* I have no idea about this - it may not be needed */
+	fe_tune_settings->min_delay_ms = 500;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+	return 0;
+}
+
+static void lgdt3302_release(struct dvb_frontend* fe)
+{
+	struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops lgdt3302_ops;
+
+struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct lgdt3302_state* state = NULL;
+	u8 buf[1];
+
+	/* Allocate memory for the internal state */
+	state = (struct lgdt3302_state*) kmalloc(sizeof(struct lgdt3302_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+	memset(state,0,sizeof(*state));
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+	/* Verify communication with demod chip */
+	if (i2c_selectreadbytes(state, 2, buf, 1))
+		goto error;
+
+	state->current_frequency = -1;
+	state->current_modulation = -1;
+
+	/* Create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	if (state)
+		kfree(state);
+	dprintk("%s: ERROR\n",__FUNCTION__);
+	return NULL;
+}
+
+static struct dvb_frontend_ops lgdt3302_ops = {
+	.info = {
+		.name= "LG Electronics LGDT3302 VSB/QAM Frontend",
+		.type = FE_ATSC,
+		.frequency_min= 54000000,
+		.frequency_max= 858000000,
+		.frequency_stepsize= 62500,
+		/* Symbol rate is for all VSB modes need to check QAM */
+		.symbol_rate_min    = 10762000,
+		.symbol_rate_max    = 10762000,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+	.init                 = lgdt3302_init,
+	.set_frontend         = lgdt3302_set_parameters,
+	.get_frontend         = lgdt3302_get_frontend,
+	.get_tune_settings    = lgdt3302_get_tune_settings,
+	.read_status          = lgdt3302_read_status,
+	.read_ber             = lgdt3302_read_ber,
+	.read_signal_strength = lgdt3302_read_signal_strength,
+	.read_snr             = lgdt3302_read_snr,
+	.read_ucblocks        = lgdt3302_read_ucblocks,
+	.release              = lgdt3302_release,
+};
+
+MODULE_DESCRIPTION("LGDT3302 [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Wilson Michaels");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(lgdt3302_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h
new file mode 100644
index 0000000..81587a4
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.h
@@ -0,0 +1,49 @@
+/*
+ * $Id: lgdt3302.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
+ *
+ *    Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
+ *
+ */
+
+#ifndef LGDT3302_H
+#define LGDT3302_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgdt3302_config
+{
+	/* The demodulator's i2c address */
+	u8 demod_address;
+	u8 pll_address;
+	struct dvb_pll_desc *pll_desc;
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+extern struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
+					    struct i2c_adapter* i2c);
+
+#endif /* LGDT3302_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgdt3302_priv.h b/drivers/media/dvb/frontends/lgdt3302_priv.h
new file mode 100644
index 0000000..6193fa7
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302_priv.h
@@ -0,0 +1,72 @@
+/*
+ * $Id: lgdt3302_priv.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
+ *
+ *    Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ *    Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.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.
+ *
+ */
+
+#ifndef _LGDT3302_PRIV_
+#define _LGDT3302_PRIV_
+
+/* i2c control register addresses */
+enum I2C_REG {
+	TOP_CONTROL= 0x00,
+	IRQ_MASK= 0x01,
+	IRQ_STATUS= 0x02,
+	VSB_CARRIER_FREQ0= 0x16,
+	VSB_CARRIER_FREQ1= 0x17,
+	VSB_CARRIER_FREQ2= 0x18,
+	VSB_CARRIER_FREQ3= 0x19,
+	CARRIER_MSEQAM1= 0x1a,
+	CARRIER_MSEQAM2= 0x1b,
+	CARRIER_LOCK= 0x1c,
+	TIMING_RECOVERY= 0x1d,
+	AGC_DELAY0= 0x2a,
+	AGC_DELAY1= 0x2b,
+	AGC_DELAY2= 0x2c,
+	AGC_RF_BANDWIDTH0= 0x2d,
+	AGC_RF_BANDWIDTH1= 0x2e,
+	AGC_RF_BANDWIDTH2= 0x2f,
+	AGC_LOOP_BANDWIDTH0= 0x30,
+	AGC_LOOP_BANDWIDTH1= 0x31,
+	AGC_FUNC_CTRL1= 0x32,
+	AGC_FUNC_CTRL2= 0x33,
+	AGC_FUNC_CTRL3= 0x34,
+	AGC_RFIF_ACC0= 0x39,
+	AGC_RFIF_ACC1= 0x3a,
+	AGC_RFIF_ACC2= 0x3b,
+	AGC_STATUS= 0x3f,
+	SYNC_STATUS_VSB= 0x43,
+	EQPH_ERR0= 0x47,
+	EQ_ERR1= 0x48,
+	EQ_ERR2= 0x49,
+	PH_ERR1= 0x4a,
+	PH_ERR2= 0x4b,
+	DEMUX_CONTROL= 0x66,
+	PACKET_ERR_COUNTER1= 0x6a,
+	PACKET_ERR_COUNTER2= 0x6b,
+};
+
+#endif /* _LGDT3302_PRIV_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
new file mode 100644
index 0000000..4f396ac
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -0,0 +1,800 @@
+/*
+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.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "s5h1420.h"
+
+
+
+#define TONE_FREQ 22000
+
+struct s5h1420_state {
+	struct i2c_adapter* i2c;
+	struct dvb_frontend_ops ops;
+	const struct s5h1420_config* config;
+	struct dvb_frontend frontend;
+
+	u8 postlocked:1;
+	u32 fclk;
+	u32 tunedfreq;
+	fe_code_rate_t fec_inner;
+	u32 symbol_rate;
+};
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings);
+
+
+static int debug = 0;
+#define dprintk if (debug) printk
+
+static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 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);
+		return -EREMOTEIO;
+	}
+
+	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;
+
+	switch(voltage) {
+	case SEC_VOLTAGE_13:
+		s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02);
+		break;
+
+	case SEC_VOLTAGE_18:
+		s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03);
+		break;
+
+	case SEC_VOLTAGE_OFF:
+		s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd);
+		break;
+	}
+
+	return 0;
+}
+
+static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	switch(tone) {
+	case SEC_TONE_ON:
+		s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08);
+		break;
+
+	case SEC_TONE_OFF:
+		s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
+		break;
+	}
+
+	return 0;
+}
+
+static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+	int i;
+	unsigned long timeout;
+	int result = 0;
+
+	/* setup for DISEQC */
+	val = s5h1420_readreg(state, 0x3b);
+	s5h1420_writereg(state, 0x3b, 0x02);
+	msleep(15);
+
+	/* write the DISEQC command bytes */
+	for(i=0; i< cmd->msg_len; i++) {
+		s5h1420_writereg(state, 0x3c + i, cmd->msg[i]);
+	}
+
+	/* kick off transmission */
+	s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08);
+
+	/* wait for transmission to complete */
+	timeout = jiffies + ((100*HZ) / 1000);
+	while(time_before(jiffies, timeout)) {
+		if (s5h1420_readreg(state, 0x3b) & 0x08)
+			break;
+
+		msleep(5);
+	}
+	if (time_after(jiffies, timeout))
+		result = -ETIMEDOUT;
+
+	/* restore original settings */
+	s5h1420_writereg(state, 0x3b, val);
+	msleep(15);
+	return result;
+}
+
+static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+	int i;
+	int length;
+	unsigned long timeout;
+	int result = 0;
+
+	/* setup for DISEQC recieve */
+	val = s5h1420_readreg(state, 0x3b);
+	s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
+	msleep(15);
+
+	/* wait for reception to complete */
+	timeout = jiffies + ((reply->timeout*HZ) / 1000);
+	while(time_before(jiffies, timeout)) {
+		if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
+			break;
+
+		msleep(5);
+	}
+	if (time_after(jiffies, timeout)) {
+		result = -ETIMEDOUT;
+		goto exit;
+	}
+
+	/* check error flag - FIXME: not sure what this does - docs do not describe
+	 * beyond "error flag for diseqc receive data :( */
+	if (s5h1420_readreg(state, 0x49)) {
+		result = -EIO;
+		goto exit;
+	}
+
+	/* check length */
+	length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
+	if (length > sizeof(reply->msg)) {
+		result = -EOVERFLOW;
+		goto exit;
+	}
+	reply->msg_len = length;
+
+	/* extract data */
+	for(i=0; i< length; i++) {
+		reply->msg[i] = s5h1420_readreg(state, 0x3c + i);
+	}
+
+exit:
+	/* restore original settings */
+	s5h1420_writereg(state, 0x3b, val);
+	msleep(15);
+	return result;
+}
+
+static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+	int result = 0;
+	unsigned long timeout;
+
+	/* setup for tone burst */
+	val = s5h1420_readreg(state, 0x3b);
+	s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01);
+
+	/* set value for B position if requested */
+	if (minicmd == SEC_MINI_B) {
+		s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04);
+	}
+	msleep(15);
+
+	/* start transmission */
+	s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08);
+
+	/* wait for transmission to complete */
+	timeout = jiffies + ((20*HZ) / 1000);
+	while(time_before(jiffies, timeout)) {
+		if (!(s5h1420_readreg(state, 0x3b) & 0x08))
+			break;
+
+		msleep(5);
+	}
+	if (time_after(jiffies, timeout))
+		result = -ETIMEDOUT;
+
+	/* restore original settings */
+	s5h1420_writereg(state, 0x3b, val);
+	msleep(15);
+	return result;
+}
+
+static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state)
+{
+	u8 val;
+	fe_status_t status = 0;
+
+	val = s5h1420_readreg(state, 0x14);
+	if (val & 0x02)
+		status |=  FE_HAS_SIGNAL; // FIXME: not sure if this is right
+	if (val & 0x01)
+		status |=  FE_HAS_CARRIER; // FIXME: not sure if this is right
+	val = s5h1420_readreg(state, 0x36);
+	if (val & 0x01)
+		status |=  FE_HAS_VITERBI;
+	if (val & 0x20)
+		status |=  FE_HAS_SYNC;
+	if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC))
+		status |=  FE_HAS_LOCK;
+
+	return status;
+}
+
+static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u8 val;
+
+	if (status == NULL)
+		return -EINVAL;
+
+	/* determine lock state */
+	*status = s5h1420_get_status_bits(state);
+
+	/* 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 ((val & 0x07) == 0x03) {
+			if (val & 0x08)
+				s5h1420_writereg(state, 0x31, 0x13);
+			else
+				s5h1420_writereg(state, 0x31, 0x1b);
+
+			/* wait a bit then update lock status */
+			mdelay(200);
+			*status = s5h1420_get_status_bits(state);
+		}
+	}
+
+	/* perform post lock setup */
+	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;
+		}
+		tmp = state->fclk / tmp;
+
+		/* set the MPEG_CLK_INTL for the calculated data rate */
+		if (tmp < 4)
+			val = 0x00;
+		else if (tmp < 8)
+			val = 0x01;
+		else if (tmp < 12)
+			val = 0x02;
+		else if (tmp < 16)
+			val = 0x03;
+		else if (tmp < 24)
+			val = 0x04;
+		else if (tmp < 32)
+			val = 0x05;
+		else
+			val = 0x06;
+		s5h1420_writereg(state, 0x22, val);
+
+		/* DC freeze */
+		s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01);
+
+		/* kicker disable + remove DC offset */
+		s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f);
+
+		/* post-lock processing has been done! */
+		state->postlocked = 1;
+	}
+
+	return 0;
+}
+
+static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	s5h1420_writereg(state, 0x46, 0x1d);
+	mdelay(25);
+	return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+}
+
+static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	u8 val = 0xff - s5h1420_readreg(state, 0x15);
+
+	return (int) ((val << 8) | val);
+}
+
+static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	s5h1420_writereg(state, 0x46, 0x1f);
+	mdelay(25);
+	return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+}
+
+static void s5h1420_reset(struct s5h1420_state* state)
+{
+	s5h1420_writereg (state, 0x01, 0x08);
+	s5h1420_writereg (state, 0x01, 0x00);
+	udelay(10);
+}
+
+static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+	u64 val;
+
+	val = (p->u.qpsk.symbol_rate / 1000) * (1<<24);
+	if (p->u.qpsk.symbol_rate <= 21000000) {
+		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);
+}
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
+{
+	u64 val;
+	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 / 1000);
+	do_div(val, ((1<<24) * sampling));
+
+	return (u32) (val * 1000);
+}
+
+static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
+{
+	int val;
+
+	/* 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);
+}
+
+static int s5h1420_getfreqoffset(struct s5h1420_state* state)
+{
+	int val;
+
+	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
+	val  = s5h1420_readreg(state, 0x0e) << 16;
+	val |= s5h1420_readreg(state, 0x0f) << 8;
+	val |= s5h1420_readreg(state, 0x10);
+	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
+
+	if (val & 0x800000)
+		val |= 0xff000000;
+
+	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
+	 * divide fclk by 1000000 to get the correct value. */
+	val = - ((val * (state->fclk/1000000)) / (1<<24));
+
+	return val;
+}
+
+static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+	if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+		s5h1420_writereg(state, 0x31, 0x00);
+		s5h1420_writereg(state, 0x30, 0x3f);
+	} else {
+		switch(p->u.qpsk.fec_inner) {
+		case FEC_1_2:
+			s5h1420_writereg(state, 0x31, 0x10);
+			s5h1420_writereg(state, 0x30, 0x01);
+			break;
+
+		case FEC_2_3:
+			s5h1420_writereg(state, 0x31, 0x11);
+			s5h1420_writereg(state, 0x30, 0x02);
+			break;
+
+		case FEC_3_4:
+			s5h1420_writereg(state, 0x31, 0x12);
+			s5h1420_writereg(state, 0x30, 0x04);
+			break;
+
+		case FEC_5_6:
+			s5h1420_writereg(state, 0x31, 0x13);
+			s5h1420_writereg(state, 0x30, 0x08);
+			break;
+
+		case FEC_6_7:
+			s5h1420_writereg(state, 0x31, 0x14);
+			s5h1420_writereg(state, 0x30, 0x10);
+			break;
+
+		case FEC_7_8:
+			s5h1420_writereg(state, 0x31, 0x15);
+			s5h1420_writereg(state, 0x30, 0x20);
+			break;
+
+		default:
+			return;
+		}
+	}
+}
+
+static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
+{
+	switch(s5h1420_readreg(state, 0x32) & 0x07) {
+	case 0:
+		return FEC_1_2;
+
+	case 1:
+		return FEC_2_3;
+
+	case 2:
+		return FEC_3_4;
+
+	case 3:
+		return FEC_5_6;
+
+	case 4:
+		return FEC_6_7;
+
+	case 5:
+		return FEC_7_8;
+	}
+
+	return FEC_NONE;
+}
+
+static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+	if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+		s5h1420_writereg(state, 0x31, 0x00);
+		s5h1420_writereg(state, 0x30, 0x3f);
+	} else {
+		u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7;
+			tmp |= 0x10;
+
+		if (p->inversion == INVERSION_ON)
+			tmp |= 0x80;
+
+		s5h1420_writereg(state, 0x31, tmp);
+	}
+}
+
+static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
+{
+	if (s5h1420_readreg(state, 0x32) & 0x08)
+		return INVERSION_ON;
+
+	return INVERSION_OFF;
+}
+
+static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	u32 frequency_delta;
+	struct dvb_frontend_tune_settings fesettings;
+
+	/* 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)) {
+
+		s5h1420_setfreqoffset(state, frequency_delta);
+		return 0;
+	}
+
+	/* first of all, software reset */
+	s5h1420_reset(state);
+
+	/* set tuner PLL */
+	if (state->config->pll_set) {
+		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+		state->config->pll_set(fe, p, &state->tunedfreq);
+		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+	}
+
+	/* 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) {
+		state->fclk = 59000000;
+		s5h1420_writereg(state, 0x03, 0x33);
+		s5h1420_writereg(state, 0x04, 0x40);
+		s5h1420_writereg(state, 0x05, 0xae);
+	} else {
+		state->fclk = 88000000;
+		s5h1420_writereg(state, 0x03, 0x50);
+		s5h1420_writereg(state, 0x04, 0x40);
+		s5h1420_writereg(state, 0x05, 0xac);
+	}
+
+	/* set misc registers */
+	s5h1420_writereg(state, 0x02, 0x00);
+	s5h1420_writereg(state, 0x07, 0xb0);
+	s5h1420_writereg(state, 0x0a, 0x67);
+	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);
+
+	/* start QPSK */
+	s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
+
+	/* set the frequency offset to adjust for PLL inaccuracy */
+	s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq);
+
+	/* set the reset of the parameters */
+	s5h1420_setsymbolrate(state, p);
+	s5h1420_setinversion(state, p);
+	s5h1420_setfec(state, p);
+
+	state->fec_inner = p->u.qpsk.fec_inner;
+	state->symbol_rate = p->u.qpsk.symbol_rate;
+	state->postlocked = 0;
+	return 0;
+}
+
+static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
+	p->inversion = s5h1420_getinversion(state);
+	p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);
+	p->u.qpsk.fec_inner = s5h1420_getfec(state);
+
+	return 0;
+}
+
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+		fesettings->min_delay_ms = 50;
+		fesettings->step_size = 2000;
+		fesettings->max_drift = 8000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1500;
+		fesettings->max_drift = 9000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1000;
+		fesettings->max_drift = 8000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 500;
+		fesettings->max_drift = 7000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+		fesettings->max_drift = 14 * fesettings->step_size;
+	} else {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+		fesettings->max_drift = 18 * fesettings->step_size;
+	}
+
+	return 0;
+}
+
+static int s5h1420_init (struct dvb_frontend* fe)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	/* disable power down and do reset */
+	s5h1420_writereg(state, 0x02, 0x10);
+	msleep(10);
+	s5h1420_reset(state);
+
+	/* init PLL */
+	if (state->config->pll_init) {
+		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+		state->config->pll_init(fe);
+		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+	}
+
+	return 0;
+}
+
+static int s5h1420_sleep(struct dvb_frontend* fe)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	return s5h1420_writereg(state, 0x02, 0x12);
+}
+
+static void s5h1420_release(struct dvb_frontend* fe)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1420_ops;
+
+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);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
+	state->postlocked = 0;
+	state->fclk = 88000000;
+	state->tunedfreq = 0;
+	state->fec_inner = FEC_NONE;
+	state->symbol_rate = 0;
+
+	/* check if the demod is there + identify it */
+	identity = s5h1420_readreg(state, 0x00);
+	if (identity != 0x03)
+		goto error;
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops s5h1420_ops = {
+
+	.info = {
+		.name     = "Samsung S5H1420 DVB-S",
+		.type     = FE_QPSK,
+		.frequency_min    = 950000,
+		.frequency_max    = 2150000,
+		.frequency_stepsize = 125,     /* kHz for QPSK frontends */
+		.frequency_tolerance  = 29500,
+		.symbol_rate_min  = 1000000,
+		.symbol_rate_max  = 45000000,
+		/*  .symbol_rate_tolerance  = ???,*/
+		.caps = FE_CAN_INVERSION_AUTO |
+		FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		FE_CAN_QPSK
+	},
+
+	.release = s5h1420_release,
+
+	.init = s5h1420_init,
+	.sleep = s5h1420_sleep,
+
+	.set_frontend = s5h1420_set_frontend,
+	.get_frontend = s5h1420_get_frontend,
+	.get_tune_settings = s5h1420_get_tune_settings,
+
+	.read_status = s5h1420_read_status,
+	.read_ber = s5h1420_read_ber,
+	.read_signal_strength = s5h1420_read_signal_strength,
+	.read_ucblocks = s5h1420_read_ucblocks,
+
+	.diseqc_send_master_cmd = s5h1420_send_master_cmd,
+	.diseqc_recv_slave_reply = s5h1420_recv_slave_reply,
+	.diseqc_send_burst = s5h1420_send_burst,
+	.set_tone = s5h1420_set_tone,
+	.set_voltage = s5h1420_set_voltage,
+};
+
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(s5h1420_attach);
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
new file mode 100644
index 0000000..b687fc7
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -0,0 +1,41 @@
+/*
+    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.
+
+*/
+
+#ifndef S5H1420_H
+#define S5H1420_H
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1420_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* PLL maintenance */
+	int (*pll_init)(struct dvb_frontend* fe);
+	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
+};
+
+extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
+             struct i2c_adapter* i2c);
+
+#endif // S5H1420_H
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index e681263..928aca0 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -617,7 +617,7 @@
 
 	/* wait for WGAGC lock */
 	starttime = jiffies;
-	timeout = jiffies + (200 * HZ) / 1000;
+	timeout = jiffies + msecs_to_jiffies(2000);
 	while (time_before(jiffies, timeout)) {
 		msleep(10);
 		if (stv0297_readreg(state, 0x43) & 0x08)
@@ -629,7 +629,7 @@
 	msleep(20);
 
 	/* wait for equaliser partial convergence */
-	timeout = jiffies + (50 * HZ) / 1000;
+	timeout = jiffies + msecs_to_jiffies(500);
 	while (time_before(jiffies, timeout)) {
 		msleep(10);
 
@@ -642,7 +642,7 @@
 	}
 
 	/* wait for equaliser full convergence */
-	timeout = jiffies + (delay * HZ) / 1000;
+	timeout = jiffies + msecs_to_jiffies(delay);
 	while (time_before(jiffies, timeout)) {
 		msleep(10);
 
@@ -659,7 +659,7 @@
 	stv0297_writereg_mask(state, 0x88, 8, 0);
 
 	/* wait for main lock */
-	timeout = jiffies + (20 * HZ) / 1000;
+	timeout = jiffies + msecs_to_jiffies(20);
 	while (time_before(jiffies, timeout)) {
 		msleep(10);
 
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 0beb370..ab0c032 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -49,10 +49,8 @@
 	/* private demod data */
 	u8 initialised;
 	enum tda1004x_demod demod_type;
-	u8 fw_version;
 };
 
-
 static int debug;
 #define dprintk(args...) \
 	do { \
@@ -122,6 +120,8 @@
 #define TDA10046H_GPIO_OUT_SEL	 0x41
 #define TDA10046H_GPIO_SELECT	 0x42
 #define TDA10046H_AGC_CONF	 0x43
+#define TDA10046H_AGC_THR	 0x44
+#define TDA10046H_AGC_RENORM	 0x45
 #define TDA10046H_AGC_GAINS	 0x46
 #define TDA10046H_AGC_TUN_MIN	 0x47
 #define TDA10046H_AGC_TUN_MAX	 0x48
@@ -274,14 +274,26 @@
 	switch (bandwidth) {
 	case BANDWIDTH_6_MHZ:
 		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+		if (state->config->if_freq == TDA10046_FREQ_045) {
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f);
+		}
 		break;
 
 	case BANDWIDTH_7_MHZ:
 		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+		if (state->config->if_freq == TDA10046_FREQ_045) {
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79);
+		}
 		break;
 
 	case BANDWIDTH_8_MHZ:
 		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+		if (state->config->if_freq == TDA10046_FREQ_045) {
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+		}
 		break;
 
 	default:
@@ -315,20 +327,35 @@
 		memcpy(buf + 1, mem + pos, tx_size);
 		fw_msg.len = tx_size + 1;
 		if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
-			printk("tda1004x: Error during firmware upload\n");
+			printk(KERN_ERR "tda1004x: Error during firmware upload\n");
 			return -EIO;
 		}
 		pos += tx_size;
 
 		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
 	}
+	// give the DSP a chance to settle 03/10/05 Hac
+	msleep(100);
 
 	return 0;
 }
 
-static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion)
+static int tda1004x_check_upload_ok(struct tda1004x_state *state)
 {
 	u8 data1, data2;
+	unsigned long timeout;
+
+	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
+		timeout = jiffies + 2 * HZ;
+		while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
+			if (time_after(jiffies, timeout)) {
+				printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
+				break;
+			}
+			msleep(1);
+		}
+	} else
+		msleep(100);
 
 	// check upload was OK
 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
@@ -336,9 +363,11 @@
 
 	data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
 	data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
-	if ((data1 != 0x67) || (data2 != dspVersion))
+	if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
+		printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
 		return -EIO;
-
+	}
+	printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
 	return 0;
 }
 
@@ -349,14 +378,14 @@
 	const struct firmware *fw;
 
 	/* don't re-upload unless necessary */
-	if (tda1004x_check_upload_ok(state, 0x2c) == 0)
+	if (tda1004x_check_upload_ok(state) == 0)
 		return 0;
 
 	/* request the firmware, this will block until someone uploads it */
-	printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
+	printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
 	ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
 	if (ret) {
-		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+		printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
 		return ret;
 	}
 
@@ -370,95 +399,93 @@
 	tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
 
 	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
+	release_firmware(fw);
 	if (ret)
 		return ret;
-	printk("tda1004x: firmware upload complete\n");
+	printk(KERN_INFO "tda1004x: firmware upload complete\n");
 
 	/* wait for DSP to initialise */
 	/* DSPREADY doesn't seem to work on the TDA10045H */
 	msleep(100);
 
-	return tda1004x_check_upload_ok(state, 0x2c);
+	return tda1004x_check_upload_ok(state);
 }
 
-static int tda10046_get_fw_version(struct tda1004x_state *state,
-				   const struct firmware *fw)
+static void tda10046_init_plls(struct dvb_frontend* fe)
 {
-	const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 };
-	unsigned int i;
+	struct tda1004x_state* state = fe->demodulator_priv;
 
-	/* area guessed from firmware v20, v21 and v25 */
-	for (i = 0x660; i < 0x700; i++) {
-		if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) {
-			state->fw_version = fw->data[i + sizeof(pattern)];
-			printk(KERN_INFO "tda1004x: using firmware v%02x\n",
-					state->fw_version);
-			return 0;
-		}
+	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
+	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
+		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+	} else {
+		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
 	}
-
-	return -EINVAL;
+	tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
+	switch (state->config->if_freq) {
+	case TDA10046_FREQ_3617:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
+		break;
+	case TDA10046_FREQ_3613:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13);
+		break;
+	case TDA10046_FREQ_045:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+		break;
+	case TDA10046_FREQ_052:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06);
+		break;
+	}
+	tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
 }
 
 static int tda10046_fwupload(struct dvb_frontend* fe)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
-	unsigned long timeout;
 	int ret;
 	const struct firmware *fw;
 
 	/* reset + wake up chip */
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0);
+	tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
 	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
-	msleep(100);
+	/* let the clocks recover from sleep */
+	msleep(5);
 
 	/* don't re-upload unless necessary */
-	if (tda1004x_check_upload_ok(state, state->fw_version) == 0)
+	if (tda1004x_check_upload_ok(state) == 0)
 		return 0;
 
-	/* request the firmware, this will block until someone uploads it */
-	printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE);
-	ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
-	if (ret) {
-		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
-		return ret;
-	}
-
-	if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */
-		printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size);
-		return -EINVAL;
-	}
-
-	ret = tda10046_get_fw_version(state, fw);
-	if (ret < 0) {
-		printk("tda1004x: unable to find firmware version\n");
-		return ret;
-	}
-
 	/* set parameters */
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10);
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c);
-	tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
-	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+	tda10046_init_plls(fe);
 
-	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
-	if (ret)
-		return ret;
-	printk("tda1004x: firmware upload complete\n");
-
-	/* wait for DSP to initialise */
-	timeout = jiffies + HZ;
-	while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
-		if (time_after(jiffies, timeout)) {
-			printk("tda1004x: DSP failed to initialised.\n");
-			return -EIO;
+	if (state->config->request_firmware != NULL) {
+		/* request the firmware, this will block until someone uploads it */
+		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
+		ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
+		if (ret) {
+			printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
+   	   		return ret;
 		}
-		msleep(1);
+		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+		ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
+		release_firmware(fw);
+		if (ret)
+			return ret;
+	} else {
+		/* boot from firmware eeprom */
+		/* Hac Note: we might need to do some GPIO Magic here */
+		printk(KERN_INFO "tda1004x: booting from eeprom\n");
+		tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
+		msleep(300);
 	}
-
-	return tda1004x_check_upload_ok(state, state->fw_version);
+	return tda1004x_check_upload_ok(state);
 }
 
 static int tda1004x_encode_fec(int fec)
@@ -560,12 +587,10 @@
 
 	if (tda10046_fwupload(fe)) {
 		printk("tda1004x: firmware upload failed\n");
-		return -EIO;
+			return -EIO;
 	}
 
-	tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip
-
-	// Init the PLL
+	// Init the tuner PLL
 	if (state->config->pll_init) {
 		tda1004x_enable_tuner_i2c(state);
 		state->config->pll_init(fe);
@@ -574,32 +599,44 @@
 
 	// tda setup
 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
-	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40);
-	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
-	tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0
-	tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
-	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
-	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
-	tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup
-	tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities
+	tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream
+	tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+
+	tda10046_init_plls(fe);
+	switch (state->config->agc_config) {
+	case TDA10046_AGC_DEFAULT:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
+		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		break;
+	case TDA10046_AGC_IFO_AUTO_NEG:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		break;
+	case TDA10046_AGC_IFO_AUTO_POS:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities
+		break;
+	case TDA10046_AGC_TDA827X:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
+		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
+		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize
+		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		break;
+	}
+	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
 	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
 	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
-	tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits
 	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
-	tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm
+	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
 	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
-	tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config
-	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN
+	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
+	tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+
 	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
 	tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
-	tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
-	tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
-
-	tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+	tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
 
 	state->initialised = 1;
 	return 0;
@@ -629,9 +666,6 @@
 	state->config->pll_set(fe, fe_params);
 	tda1004x_disable_tuner_i2c(state);
 
-	if (state->demod_type == TDA1004X_DEMOD_TDA10046)
-		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4);
-
 	// Hardcoded to use auto as much as possible on the TDA10045 as it
 	// is very unreliable if AUTO mode is _not_ used.
 	if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
@@ -1089,6 +1123,11 @@
 		break;
 
 	case TDA1004X_DEMOD_TDA10046:
+		if (state->config->pll_sleep != NULL) {
+			tda1004x_enable_tuner_i2c(state);
+			state->config->pll_sleep(fe);
+			tda1004x_disable_tuner_i2c(state);
+		}
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
 		break;
 	}
@@ -1100,8 +1139,9 @@
 static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
 	fesettings->min_delay_ms = 800;
-	fesettings->step_size = 166667;
-	fesettings->max_drift = 166667*2;
+	/* Drift compensation makes no sense for DVB-T */
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
 	return 0;
 }
 
@@ -1216,7 +1256,6 @@
 	memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
 	state->initialised = 0;
 	state->demod_type = TDA1004X_DEMOD_TDA10046;
-	state->fw_version = 0x20;	/* dummy default value */
 
 	/* check if the demod is there */
 	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index c8e1d54..8659c52 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -26,6 +26,25 @@
 #include <linux/dvb/frontend.h>
 #include <linux/firmware.h>
 
+enum tda10046_xtal {
+	TDA10046_XTAL_4M,
+	TDA10046_XTAL_16M,
+};
+
+enum tda10046_agc {
+	TDA10046_AGC_DEFAULT,		/* original configuration */
+	TDA10046_AGC_IFO_AUTO_NEG,	/* IF AGC only, automatic, negtive */
+	TDA10046_AGC_IFO_AUTO_POS,	/* IF AGC only, automatic, positive */
+	TDA10046_AGC_TDA827X,	    /* IF AGC only, special setup for tda827x */
+};
+
+enum tda10046_if {
+	TDA10046_FREQ_3617,		/* original config, 36,166 MHZ */
+	TDA10046_FREQ_3613,		/* 36,13 MHZ */
+	TDA10046_FREQ_045,		/* low IF, 4.0, 4.5, or 5.0 MHZ */
+	TDA10046_FREQ_052,		/* low IF, 5.1667 MHZ for tda9889 */
+};
+
 struct tda1004x_config
 {
 	/* the demodulator's i2c address */
@@ -37,14 +56,22 @@
 	/* Does the OCLK signal need inverted? */
 	u8 invert_oclk;
 
-	/* value of N_I2C of the CONF_PLL3 register */
-	u8 n_i2c;
+	/* Xtal frequency, 4 or 16MHz*/
+	enum tda10046_xtal xtal_freq;
+
+	/* IF frequency */
+	enum tda10046_if if_freq;
+
+	/* AGC configuration */
+	enum tda10046_agc agc_config;
 
 	/* PLL maintenance */
 	int (*pll_init)(struct dvb_frontend* fe);
+	void (*pll_sleep)(struct dvb_frontend* fe);
 	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 
 	/* request firmware for device */
+	/* set this to NULL if the card has a firmware EEPROM */
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
 
diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c
index 032d348..88e1250 100644
--- a/drivers/media/dvb/frontends/tda80xx.c
+++ b/drivers/media/dvb/frontends/tda80xx.c
@@ -27,7 +27,6 @@
 #include <linux/spinlock.h>
 #include <linux/threads.h>
 #include <linux/interrupt.h>
-#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
new file mode 100644
index 0000000..f02842b
--- /dev/null
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -0,0 +1,16 @@
+config DVB_PLUTO2
+	tristate "Pluto2 cards"
+	depends on DVB_CORE && PCI
+	select I2C
+	select I2C_ALGOBIT
+	select DVB_TDA1004X
+	help
+	  Support for PCI cards based on the Pluto2 FPGA like the Satelco
+	  Easywatch Mobile Terrestrial DVB-T Receiver.
+
+          Since these cards have no MPEG decoder onboard, they transmit
+	  only compressed MPEG data over the PCI bus, so you need
+	  an external software decoder to watch TV on your computer.
+
+	  Say Y or M if you own such a device and want to use it.
+
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
new file mode 100644
index 0000000..86ca84b
--- /dev/null
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_PLUTO2) = pluto2.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
new file mode 100644
index 0000000..706e0bc
--- /dev/null
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -0,0 +1,809 @@
+/*
+ * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T]
+ *
+ * Copyright (C) 2005 Andreas Oberritter <obi@linuxtv.org>
+ *
+ * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/
+ * 	by Dany Salman <salmandany@yahoo.fr>
+ *	Copyright (c) 2004 TDF
+ *
+ * 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/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "tda1004x.h"
+
+#define DRIVER_NAME		"pluto2"
+
+#define REG_PIDn(n)		((n) << 2)	/* PID n pattern registers */
+#define REG_PCAR		0x0020		/* PC address register */
+#define REG_TSCR		0x0024		/* TS ctrl & status */
+#define REG_MISC		0x0028		/* miscellaneous */
+#define REG_MMAC		0x002c		/* MSB MAC address */
+#define REG_IMAC		0x0030		/* ISB MAC address */
+#define REG_LMAC		0x0034		/* LSB MAC address */
+#define REG_SPID		0x0038		/* SPI data */
+#define REG_SLCS		0x003c		/* serial links ctrl/status */
+
+#define PID0_NOFIL		(0x0001 << 16)
+#define PIDn_ENP		(0x0001 << 15)
+#define PID0_END		(0x0001 << 14)
+#define PID0_AFIL		(0x0001 << 13)
+#define PIDn_PID		(0x1fff <<  0)
+
+#define TSCR_NBPACKETS		(0x00ff << 24)
+#define TSCR_DEM		(0x0001 << 17)
+#define TSCR_DE			(0x0001 << 16)
+#define TSCR_RSTN		(0x0001 << 15)
+#define TSCR_MSKO		(0x0001 << 14)
+#define TSCR_MSKA		(0x0001 << 13)
+#define TSCR_MSKL		(0x0001 << 12)
+#define TSCR_OVR		(0x0001 << 11)
+#define TSCR_AFUL		(0x0001 << 10)
+#define TSCR_LOCK		(0x0001 <<  9)
+#define TSCR_IACK		(0x0001 <<  8)
+#define TSCR_ADEF		(0x007f <<  0)
+
+#define MISC_DVR		(0x0fff <<  4)
+#define MISC_ALED		(0x0001 <<  3)
+#define MISC_FRST		(0x0001 <<  2)
+#define MISC_LED1		(0x0001 <<  1)
+#define MISC_LED0		(0x0001 <<  0)
+
+#define SPID_SPIDR		(0x00ff <<  0)
+
+#define SLCS_SCL		(0x0001 <<  7)
+#define SLCS_SDA		(0x0001 <<  6)
+#define SLCS_CSN		(0x0001 <<  2)
+#define SLCS_OVR		(0x0001 <<  1)
+#define SLCS_SWC		(0x0001 <<  0)
+
+#define TS_DMA_PACKETS		(8)
+#define TS_DMA_BYTES		(188 * TS_DMA_PACKETS)
+
+#define I2C_ADDR_TDA10046	0x10
+#define I2C_ADDR_TUA6034	0xc2
+#define NHWFILTERS		8
+
+struct pluto {
+	/* pci */
+	struct pci_dev *pdev;
+	u8 __iomem *io_mem;
+
+	/* dvb */
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	struct dmxdev dmxdev;
+	struct dvb_adapter dvb_adapter;
+	struct dvb_demux demux;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+	unsigned int full_ts_users;
+	unsigned int users;
+
+	/* i2c */
+	struct i2c_algo_bit_data i2c_bit;
+	struct i2c_adapter i2c_adap;
+	unsigned int i2cbug;
+
+	/* irq */
+	unsigned int overflow;
+
+	/* dma */
+	dma_addr_t dma_addr;
+	u8 dma_buf[TS_DMA_BYTES];
+	u8 dummy[4096];
+};
+
+static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed)
+{
+	return container_of(feed->demux, struct pluto, demux);
+}
+
+static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe)
+{
+	return container_of(fe->dvb, struct pluto, dvb_adapter);
+}
+
+static inline u32 pluto_readreg(struct pluto *pluto, u32 reg)
+{
+	return readl(&pluto->io_mem[reg]);
+}
+
+static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val)
+{
+	writel(val, &pluto->io_mem[reg]);
+}
+
+static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits)
+{
+	u32 val = readl(&pluto->io_mem[reg]);
+	val &= ~mask;
+	val |= bits;
+	writel(val, &pluto->io_mem[reg]);
+}
+
+static void pluto_setsda(void *data, int state)
+{
+	struct pluto *pluto = data;
+
+	if (state)
+		pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA);
+	else
+		pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0);
+}
+
+static void pluto_setscl(void *data, int state)
+{
+	struct pluto *pluto = data;
+
+	if (state)
+		pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL);
+	else
+		pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0);
+
+	/* try to detect i2c_inb() to workaround hardware bug:
+	 * reset SDA to high after SCL has been set to low */
+	if ((state) && (pluto->i2cbug == 0)) {
+		pluto->i2cbug = 1;
+	} else {
+		if ((!state) && (pluto->i2cbug == 1))
+			pluto_setsda(pluto, 1);
+		pluto->i2cbug = 0;
+	}
+}
+
+static int pluto_getsda(void *data)
+{
+	struct pluto *pluto = data;
+
+	return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA;
+}
+
+static int pluto_getscl(void *data)
+{
+	struct pluto *pluto = data;
+
+	return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL;
+}
+
+static void pluto_reset_frontend(struct pluto *pluto, int reenable)
+{
+	u32 val = pluto_readreg(pluto, REG_MISC);
+
+	if (val & MISC_FRST) {
+		val &= ~MISC_FRST;
+		pluto_writereg(pluto, REG_MISC, val);
+	}
+	if (reenable) {
+		val |= MISC_FRST;
+		pluto_writereg(pluto, REG_MISC, val);
+	}
+}
+
+static void pluto_reset_ts(struct pluto *pluto, int reenable)
+{
+	u32 val = pluto_readreg(pluto, REG_TSCR);
+
+	if (val & TSCR_RSTN) {
+		val &= ~TSCR_RSTN;
+		pluto_writereg(pluto, REG_TSCR, val);
+	}
+	if (reenable) {
+		val |= TSCR_RSTN;
+		pluto_writereg(pluto, REG_TSCR, val);
+	}
+}
+
+static void pluto_set_dma_addr(struct pluto *pluto)
+{
+	pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr));
+}
+
+static int __devinit pluto_dma_map(struct pluto *pluto)
+{
+	pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+	return pci_dma_mapping_error(pluto->dma_addr);
+}
+
+static void pluto_dma_unmap(struct pluto *pluto)
+{
+	pci_unmap_single(pluto->pdev, pluto->dma_addr,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static int pluto_start_feed(struct dvb_demux_feed *f)
+{
+	struct pluto *pluto = feed_to_pluto(f);
+
+	/* enable PID filtering */
+	if (pluto->users++ == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0);
+
+	if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+		pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid);
+	else if (pluto->full_ts_users++ == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL);
+
+	return 0;
+}
+
+static int pluto_stop_feed(struct dvb_demux_feed *f)
+{
+	struct pluto *pluto = feed_to_pluto(f);
+
+	/* disable PID filtering */
+	if (--pluto->users == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL);
+
+	if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+		pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff);
+	else if (--pluto->full_ts_users == 0)
+		pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0);
+
+	return 0;
+}
+
+static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
+{
+	/* synchronize the DMA transfer with the CPU
+	 * first so that we see updated contents. */
+	pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+	/* Workaround for broken hardware:
+	 * [1] On startup NBPACKETS seems to contain an uninitialized value,
+	 *     but no packets have been transfered.
+	 * [2] Sometimes (actually very often) NBPACKETS stays at zero
+	 *     although one packet has been transfered.
+	 */
+	if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
+		unsigned int i = 0, valid;
+		while (pluto->dma_buf[i] == 0x47)
+			i += 188;
+		valid = i / 188;
+		if (nbpackets != valid) {
+			dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n",
+					nbpackets, valid);
+			nbpackets = valid;
+		}
+	}
+
+	dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
+
+	/* clear the dma buffer. this is needed to be able to identify
+	 * new valid ts packets above */
+	memset(pluto->dma_buf, 0, nbpackets * 188);
+
+	/* reset the dma address */
+	pluto_set_dma_addr(pluto);
+
+	/* sync the buffer and give it back to the card */
+	pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr,
+			TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pluto *pluto = dev_id;
+	u32 tscr;
+
+	/* check whether an interrupt occured on this device */
+	tscr = pluto_readreg(pluto, REG_TSCR);
+	if (!(tscr & (TSCR_DE | TSCR_OVR)))
+		return IRQ_NONE;
+
+	if (tscr == 0xffffffff) {
+		// FIXME: maybe recover somehow
+		dev_err(&pluto->pdev->dev, "card hung up :(\n");
+		return IRQ_HANDLED;
+	}
+
+	/* dma end interrupt */
+	if (tscr & TSCR_DE) {
+		pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24);
+		/* overflow interrupt */
+		if (tscr & TSCR_OVR)
+			pluto->overflow++;
+		if (pluto->overflow) {
+			dev_err(&pluto->pdev->dev, "overflow irq (%d)\n",
+					pluto->overflow);
+			pluto_reset_ts(pluto, 1);
+			pluto->overflow = 0;
+		}
+	} else if (tscr & TSCR_OVR) {
+		pluto->overflow++;
+	}
+
+	/* ACK the interrupt */
+	pluto_writereg(pluto, REG_TSCR, tscr | TSCR_IACK);
+
+	return IRQ_HANDLED;
+}
+
+static void __devinit pluto_enable_irqs(struct pluto *pluto)
+{
+	u32 val = pluto_readreg(pluto, REG_TSCR);
+
+	/* set the number of packets */
+	val &= ~TSCR_ADEF;
+	val |= TS_DMA_PACKETS / 2;
+	/* disable AFUL and LOCK interrupts */
+	val |= (TSCR_MSKA | TSCR_MSKL);
+	/* enable DMA and OVERFLOW interrupts */
+	val &= ~(TSCR_DEM | TSCR_MSKO);
+	/* clear pending interrupts */
+	val |= TSCR_IACK;
+
+	pluto_writereg(pluto, REG_TSCR, val);
+}
+
+static void pluto_disable_irqs(struct pluto *pluto)
+{
+	u32 val = pluto_readreg(pluto, REG_TSCR);
+
+	/* disable all interrupts */
+	val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL);
+	/* clear pending interrupts */
+	val |= TSCR_IACK;
+
+	pluto_writereg(pluto, REG_TSCR, val);
+}
+
+static int __devinit pluto_hw_init(struct pluto *pluto)
+{
+	pluto_reset_frontend(pluto, 1);
+
+	/* set automatic LED control by FPGA */
+	pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED);
+
+	/* set data endianess */
+#ifdef __LITTLE_ENDIAN
+	pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END);
+#else
+	pluto_rw(pluto, REG_PIDn(0), PID0_END, 0);
+#endif
+	/* map DMA and set address */
+	pluto_dma_map(pluto);
+	pluto_set_dma_addr(pluto);
+
+	/* enable interrupts */
+	pluto_enable_irqs(pluto);
+
+	/* reset TS logic */
+	pluto_reset_ts(pluto, 1);
+
+	return 0;
+}
+
+static void pluto_hw_exit(struct pluto *pluto)
+{
+	/* disable interrupts */
+	pluto_disable_irqs(pluto);
+
+	pluto_reset_ts(pluto, 0);
+
+	/* LED: disable automatic control, enable yellow, disable green */
+	pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1);
+
+	/* unmap DMA */
+	pluto_dma_unmap(pluto);
+
+	pluto_reset_frontend(pluto, 0);
+}
+
+static inline u32 divide(u32 numerator, u32 denominator)
+{
+	if (denominator == 0)
+		return ~0;
+
+	return (numerator + denominator / 2) / denominator;
+}
+
+/* LG Innotek TDTE-E001P (Infineon TUA6034) */
+static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct pluto *pluto = frontend_to_pluto(fe);
+	struct i2c_msg msg;
+	int ret;
+	u8 buf[4];
+	u32 div;
+
+	// Fref = 166.667 Hz
+	// Fref * 3 = 500.000 Hz
+	// IF = 36166667
+	// IF / Fref = 217
+	//div = divide(p->frequency + 36166667, 166667);
+	div = divide(p->frequency * 3, 500000) + 217;
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+
+	if (p->frequency < 611000000)
+		buf[2] = 0xb4;
+	else if (p->frequency < 811000000)
+		buf[2] = 0xbc;
+	else
+		buf[2] = 0xf4;
+
+	// VHF: 174-230 MHz
+	// center: 350 MHz
+	// UHF: 470-862 MHz
+	if (p->frequency < 350000000)
+		buf[3] = 0x02;
+	else
+		buf[3] = 0x04;
+
+	if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+		buf[3] |= 0x08;
+
+	if (sizeof(buf) == 6) {
+		buf[4] = buf[2];
+		buf[4] &= ~0x1c;
+		buf[4] |=  0x18;
+
+		buf[5] = (0 << 7) | (2 << 4);
+	}
+
+	msg.addr = I2C_ADDR_TUA6034 >> 1;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = sizeof(buf);
+
+	ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
+	if (ret < 0)
+		return ret;
+	else if (ret == 0)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static int pluto2_request_firmware(struct dvb_frontend *fe,
+				   const struct firmware **fw, char *name)
+{
+	struct pluto *pluto = frontend_to_pluto(fe);
+
+	return request_firmware(fw, name, &pluto->pdev->dev);
+}
+
+static struct tda1004x_config pluto2_fe_config __devinitdata = {
+	.demod_address = I2C_ADDR_TDA10046 >> 1,
+	.invert = 1,
+	.invert_oclk = 0,
+	.xtal_freq = TDA10046_XTAL_16M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
+	.pll_set = lg_tdtpe001p_pll_set,
+	.pll_sleep = NULL,
+	.request_firmware = pluto2_request_firmware,
+};
+
+static int __devinit frontend_init(struct pluto *pluto)
+{
+	int ret;
+
+	pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap);
+	if (!pluto->fe) {
+		dev_err(&pluto->pdev->dev, "could not attach frontend\n");
+		return -ENODEV;
+	}
+
+	ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
+	if (ret < 0) {
+		if (pluto->fe->ops->release)
+			pluto->fe->ops->release(pluto->fe);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __devinit pluto_read_rev(struct pluto *pluto)
+{
+	u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR;
+	dev_info(&pluto->pdev->dev, "board revision %d.%d\n",
+			(val >> 12) & 0x0f, (val >> 4) & 0xff);
+}
+
+static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
+{
+	u32 val = pluto_readreg(pluto, REG_MMAC);
+	mac[0] = (val >> 8) & 0xff;
+	mac[1] = (val >> 0) & 0xff;
+
+	val = pluto_readreg(pluto, REG_IMAC);
+	mac[2] = (val >> 8) & 0xff;
+	mac[3] = (val >> 0) & 0xff;
+
+	val = pluto_readreg(pluto, REG_LMAC);
+	mac[4] = (val >> 8) & 0xff;
+	mac[5] = (val >> 0) & 0xff;
+
+	dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int __devinit pluto_read_serial(struct pluto *pluto)
+{
+	struct pci_dev *pdev = pluto->pdev;
+	unsigned int i, j;
+	u8 __iomem *cis;
+
+	cis = pci_iomap(pdev, 1, 0);
+	if (!cis)
+		return -EIO;
+
+	dev_info(&pdev->dev, "S/N ");
+
+	for (i = 0xe0; i < 0x100; i += 4) {
+		u32 val = readl(&cis[i]);
+		for (j = 0; j < 32; j += 8) {
+			if ((val & 0xff) == 0xff)
+				goto out;
+			printk("%c", val & 0xff);
+			val >>= 8;
+		}
+	}
+out:
+	printk("\n");
+	pci_iounmap(pdev, cis);
+
+	return 0;
+}
+
+static int __devinit pluto2_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct pluto *pluto;
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+	int ret = -ENOMEM;
+
+	pluto = kmalloc(sizeof(struct pluto), GFP_KERNEL);
+	if (!pluto)
+		goto out;
+
+	memset(pluto, 0, sizeof(struct pluto));
+	pluto->pdev = pdev;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err_kfree;
+
+	/* enable interrupts */
+	pci_write_config_dword(pdev, 0x6c, 0x8000);
+
+	ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRIVER_NAME);
+	if (ret < 0)
+		goto err_pci_disable_device;
+
+	pluto->io_mem = pci_iomap(pdev, 0, 0x40);
+	if (!pluto->io_mem) {
+		ret = -EIO;
+		goto err_pci_release_regions;
+	}
+
+	pci_set_drvdata(pdev, pluto);
+
+	ret = request_irq(pdev->irq, pluto_irq, SA_SHIRQ, DRIVER_NAME, pluto);
+	if (ret < 0)
+		goto err_pci_iounmap;
+
+	ret = pluto_hw_init(pluto);
+	if (ret < 0)
+		goto err_free_irq;
+
+	/* i2c */
+	i2c_set_adapdata(&pluto->i2c_adap, pluto);
+	strcpy(pluto->i2c_adap.name, DRIVER_NAME);
+	pluto->i2c_adap.owner = THIS_MODULE;
+	pluto->i2c_adap.id = I2C_ALGO_BIT;
+	pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+	pluto->i2c_adap.dev.parent = &pdev->dev;
+	pluto->i2c_adap.algo_data = &pluto->i2c_bit;
+	pluto->i2c_bit.data = pluto;
+	pluto->i2c_bit.setsda = pluto_setsda;
+	pluto->i2c_bit.setscl = pluto_setscl;
+	pluto->i2c_bit.getsda = pluto_getsda;
+	pluto->i2c_bit.getscl = pluto_getscl;
+	pluto->i2c_bit.udelay = 10;
+	pluto->i2c_bit.timeout = 10;
+
+	/* Raise SCL and SDA */
+	pluto_setsda(pluto, 1);
+	pluto_setscl(pluto, 1);
+
+	ret = i2c_bit_add_bus(&pluto->i2c_adap);
+	if (ret < 0)
+		goto err_pluto_hw_exit;
+
+	/* dvb */
+	ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+	if (ret < 0)
+		goto err_i2c_bit_del_bus;
+
+	dvb_adapter = &pluto->dvb_adapter;
+
+	pluto_read_rev(pluto);
+	pluto_read_serial(pluto);
+	pluto_read_mac(pluto, dvb_adapter->proposed_mac);
+
+	dvbdemux = &pluto->demux;
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = pluto_start_feed;
+	dvbdemux->stop_feed = pluto_stop_feed;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+	ret = dvb_dmx_init(dvbdemux);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter;
+
+	dmx = &dvbdemux->dmx;
+
+	pluto->hw_frontend.source = DMX_FRONTEND_0;
+	pluto->mem_frontend.source = DMX_MEMORY_FE;
+	pluto->dmxdev.filternum = NHWFILTERS;
+	pluto->dmxdev.demux = dmx;
+
+	ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter);
+	if (ret < 0)
+		goto err_dvb_dmx_release;
+
+	ret = dmx->add_frontend(dmx, &pluto->hw_frontend);
+	if (ret < 0)
+		goto err_dvb_dmxdev_release;
+
+	ret = dmx->add_frontend(dmx, &pluto->mem_frontend);
+	if (ret < 0)
+		goto err_remove_hw_frontend;
+
+	ret = dmx->connect_frontend(dmx, &pluto->hw_frontend);
+	if (ret < 0)
+		goto err_remove_mem_frontend;
+
+	ret = frontend_init(pluto);
+	if (ret < 0)
+		goto err_disconnect_frontend;
+
+	dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx);
+out:
+	return ret;
+
+err_disconnect_frontend:
+	dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+	dmx->remove_frontend(dmx, &pluto->mem_frontend);
+err_remove_hw_frontend:
+	dmx->remove_frontend(dmx, &pluto->hw_frontend);
+err_dvb_dmxdev_release:
+	dvb_dmxdev_release(&pluto->dmxdev);
+err_dvb_dmx_release:
+	dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+	dvb_unregister_adapter(dvb_adapter);
+err_i2c_bit_del_bus:
+	i2c_bit_del_bus(&pluto->i2c_adap);
+err_pluto_hw_exit:
+	pluto_hw_exit(pluto);
+err_free_irq:
+	free_irq(pdev->irq, pluto);
+err_pci_iounmap:
+	pci_iounmap(pdev, pluto->io_mem);
+err_pci_release_regions:
+	pci_release_regions(pdev);
+err_pci_disable_device:
+	pci_disable_device(pdev);
+err_kfree:
+	pci_set_drvdata(pdev, NULL);
+	kfree(pluto);
+	goto out;
+}
+
+static void __devexit pluto2_remove(struct pci_dev *pdev)
+{
+	struct pluto *pluto = pci_get_drvdata(pdev);
+	struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter;
+	struct dvb_demux *dvbdemux = &pluto->demux;
+	struct dmx_demux *dmx = &dvbdemux->dmx;
+
+	dmx->close(dmx);
+	dvb_net_release(&pluto->dvbnet);
+	if (pluto->fe)
+		dvb_unregister_frontend(pluto->fe);
+
+	dmx->disconnect_frontend(dmx);
+	dmx->remove_frontend(dmx, &pluto->mem_frontend);
+	dmx->remove_frontend(dmx, &pluto->hw_frontend);
+	dvb_dmxdev_release(&pluto->dmxdev);
+	dvb_dmx_release(dvbdemux);
+	dvb_unregister_adapter(dvb_adapter);
+	i2c_bit_del_bus(&pluto->i2c_adap);
+	pluto_hw_exit(pluto);
+	free_irq(pdev->irq, pluto);
+	pci_iounmap(pdev, pluto->io_mem);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	kfree(pluto);
+}
+
+#ifndef PCI_VENDOR_ID_SCM
+#define PCI_VENDOR_ID_SCM	0x0432
+#endif
+#ifndef PCI_DEVICE_ID_PLUTO2
+#define PCI_DEVICE_ID_PLUTO2	0x0001
+#endif
+
+static struct pci_device_id pluto2_id_table[] __devinitdata = {
+	{
+		.vendor = PCI_VENDOR_ID_SCM,
+		.device = PCI_DEVICE_ID_PLUTO2,
+		.subvendor = PCI_ANY_ID,
+		.subdevice = PCI_ANY_ID,
+	}, {
+		/* empty */
+	},
+};
+
+MODULE_DEVICE_TABLE(pci, pluto2_id_table);
+
+static struct pci_driver pluto2_driver = {
+	.name = DRIVER_NAME,
+	.id_table = pluto2_id_table,
+	.probe = pluto2_probe,
+	.remove = __devexit_p(pluto2_remove),
+};
+
+static int __init pluto2_init(void)
+{
+	return pci_register_driver(&pluto2_driver);
+}
+
+static void __exit pluto2_exit(void)
+{
+	pci_unregister_driver(&pluto2_driver);
+}
+
+module_init(pluto2_init);
+module_exit(pluto2_exit);
+
+MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
+MODULE_DESCRIPTION("Pluto2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7ffa2c7..bf3c011 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -12,7 +12,7 @@
 	select DVB_STV0297
 	select DVB_L64781
 	help
-	  Support for SAA7146 and AV7110 based DVB cards as produced 
+	  Support for SAA7146 and AV7110 based DVB cards as produced
 	  by Fujitsu-Siemens, Technotrend, Hauppauge and others.
 
 	  This driver only supports the fullfeatured cards with
@@ -33,7 +33,7 @@
 	  If you want to compile the firmware into the driver you need to say
 	  Y here and provide the correct path of the firmware. You need this
 	  option if you want to compile the whole driver statically into the
-	  kernel. 
+	  kernel.
 
 	  All other people say N.
 
@@ -66,6 +66,7 @@
 	select DVB_L64781
 	select DVB_TDA8083
 	select DVB_TDA10021
+	select DVB_S5H1420
 	help
 	  Support for simple SAA7146 based DVB cards
 	  (so called Budget- or Nova-PCI cards) without onboard
@@ -119,9 +120,9 @@
 	select DVB_VES1X93
 	select DVB_TDA8083
 	help
-	  Support for Budget Patch (full TS) modification on 
+	  Support for Budget Patch (full TS) modification on
 	  SAA7146+AV7110 based cards (DVB-S cards). This
-	  driver doesn't use onboard MPEG2 decoder. The 
+	  driver doesn't use onboard MPEG2 decoder. The
 	  card is driven in Budget-only mode. Card is
 	  required to have loaded firmware to tune properly.
 	  Firmware can be loaded by insertion and removal of
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 8e33a85..e4c6e87 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -116,13 +116,18 @@
 
 static void init_av7110_av(struct av7110 *av7110)
 {
+	int ret;
 	struct saa7146_dev *dev = av7110->dev;
 
 	/* set internal volume control to maximum */
 	av7110->adac_type = DVB_ADAC_TI;
-	av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+	if (ret < 0)
+		printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
 
-	av7710_set_video_mode(av7110, vidmode);
+	ret = av7710_set_video_mode(av7110, vidmode);
+	if (ret < 0)
+		printk("dvb-ttpci:cannot set video mode:%d\n",ret);
 
 	/* handle different card types */
 	/* remaining inits according to card and frontend type */
@@ -156,8 +161,12 @@
 
 	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
 		// switch DVB SCART on
-		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
-		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
+		if (ret < 0)
+			printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret);
+		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+		if (ret < 0)
+			printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret);
 		if (rgb_on &&
 		    (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
 			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
@@ -165,8 +174,12 @@
 		}
 	}
 
-	av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
-	av7110_setup_irc_config(av7110, 0);
+	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+	if (ret < 0)
+		printk("dvb-ttpci:cannot set volume :%d\n",ret);
+	ret = av7110_setup_irc_config(av7110, 0);
+	if (ret < 0)
+		printk("dvb-ttpci:cannot setup irc config :%d\n",ret);
 }
 
 static void recover_arm(struct av7110 *av7110)
@@ -258,8 +271,9 @@
  *
  *  If we want to support multiple controls we would have to do much more...
  */
-void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
+int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
 {
+	int ret = 0;
 	static struct av7110 *last;
 
 	dprintk(4, "%p\n", av7110);
@@ -270,9 +284,10 @@
 		last = av7110;
 
 	if (av7110) {
-		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
+		ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
 		av7110->ir_config = ir_config;
 	}
+	return ret;
 }
 
 static void (*irc_handler)(u32);
@@ -765,13 +780,14 @@
 			     pcrpid, vpid, apid, ttpid, subpid);
 }
 
-void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
 		u16 subpid, u16 pcrpid)
 {
+	int ret = 0;
 	dprintk(4, "%p\n", av7110);
 
 	if (down_interruptible(&av7110->pid_mutex))
-		return;
+		return -ERESTARTSYS;
 
 	if (!(vpid & 0x8000))
 		av7110->pids[DMX_PES_VIDEO] = vpid;
@@ -786,10 +802,11 @@
 
 	if (av7110->fe_synced) {
 		pcrpid = av7110->pids[DMX_PES_PCR];
-		SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
+		ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
 	}
 
 	up(&av7110->pid_mutex);
+	return ret;
 }
 
 
@@ -832,11 +849,13 @@
 	ret = av7110_fw_request(av7110, buf, 20, &handle, 1);
 	if (ret != 0 || handle >= 32) {
 		printk("dvb-ttpci: %s error  buf %04x %04x %04x %04x  "
-				"ret %x  handle %04x\n",
+				"ret %d  handle %04x\n",
 				__FUNCTION__, buf[0], buf[1], buf[2], buf[3],
 				ret, handle);
 		dvbdmxfilter->hw_handle = 0xffff;
-		return -1;
+		if (!ret)
+			ret = -1;
+		return ret;
 	}
 
 	av7110->handle2filter[handle] = dvbdmxfilter;
@@ -859,7 +878,7 @@
 	if (handle >= 32) {
 		printk("%s tried to stop invalid filter %04x, filter type = %x\n",
 				__FUNCTION__, handle, dvbdmxfilter->type);
-		return 0;
+		return -EINVAL;
 	}
 
 	av7110->handle2filter[handle] = NULL;
@@ -873,18 +892,20 @@
 				"resp %04x %04x  pid %d\n",
 				__FUNCTION__, buf[0], buf[1], buf[2], ret,
 				answ[0], answ[1], dvbdmxfilter->feed->pid);
-		ret = -1;
+		if (!ret)
+			ret = -1;
 	}
 	return ret;
 }
 
 
-static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
+static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
 {
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
 	u16 *pid = dvbdmx->pids, npids[5];
 	int i;
+	int ret = 0;
 
 	dprintk(4, "%p\n", av7110);
 
@@ -893,36 +914,49 @@
 	npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
 	if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) {
 		npids[i] = 0;
-		ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
-		StartHWFilter(dvbdmxfeed->filter);
-		return;
+		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+		if (!ret)
+			ret = StartHWFilter(dvbdmxfeed->filter);
+		return ret;
 	}
-	if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4)
-		ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+	if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) {
+		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+		if (ret)
+			return ret;
+	}
 
 	if (dvbdmxfeed->pes_type < 2 && npids[0])
 		if (av7110->fe_synced)
-			av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+		{
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+			if (ret)
+				return ret;
+		}
 
 	if ((dvbdmxfeed->ts_type & TS_PACKET)) {
 		if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
-			av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
+			ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
 		if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
-			av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
+			ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
 	}
+	return ret;
 }
 
-static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
+static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
 {
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
 	u16 *pid = dvbdmx->pids, npids[5];
 	int i;
 
+	int ret = 0;
+
 	dprintk(4, "%p\n", av7110);
 
 	if (dvbdmxfeed->pes_type <= 1) {
-		av7110_av_stop(av7110, dvbdmxfeed->pes_type ?  RP_VIDEO : RP_AUDIO);
+		ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ?  RP_VIDEO : RP_AUDIO);
+		if (ret)
+			return ret;
 		if (!av7110->rec_mode)
 			dvbdmx->recording = 0;
 		if (!av7110->playing)
@@ -933,24 +967,27 @@
 	switch (i) {
 	case 2: //teletext
 		if (dvbdmxfeed->ts_type & TS_PACKET)
-			StopHWFilter(dvbdmxfeed->filter);
+			ret = StopHWFilter(dvbdmxfeed->filter);
 		npids[2] = 0;
 		break;
 	case 0:
 	case 1:
 	case 4:
 		if (!pids_off)
-			return;
+			return 0;
 		npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
 		break;
 	}
-	ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+	if (!ret)
+		ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+	return ret;
 }
 
 static int av7110_start_feed(struct dvb_demux_feed *feed)
 {
 	struct dvb_demux *demux = feed->demux;
 	struct av7110 *av7110 = demux->priv;
+	int ret = 0;
 
 	dprintk(4, "%p\n", av7110);
 
@@ -971,21 +1008,22 @@
 					   !(demux->pids[1] & 0x8000)) {
 					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
 					       dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
-					       av7110_av_start_play(av7110,RP_AV);
-					       demux->playing = 1;
+					       ret = av7110_av_start_play(av7110,RP_AV);
+					       if (!ret)
+						       demux->playing = 1;
 					}
 				break;
 			default:
-				dvb_feed_start_pid(feed);
+				ret = dvb_feed_start_pid(feed);
 				break;
 			}
 		} else if ((feed->ts_type & TS_PACKET) &&
 			   (demux->dmx.frontend->source != DMX_MEMORY_FE)) {
-			StartHWFilter(feed->filter);
+			ret = StartHWFilter(feed->filter);
 		}
 	}
 
-	if (feed->type == DMX_TYPE_SEC) {
+	else if (feed->type == DMX_TYPE_SEC) {
 		int i;
 
 		for (i = 0; i < demux->filternum; i++) {
@@ -996,12 +1034,15 @@
 			if (demux->filter[i].filter.parent != &feed->feed.sec)
 				continue;
 			demux->filter[i].state = DMX_STATE_GO;
-			if (demux->dmx.frontend->source != DMX_MEMORY_FE)
-				StartHWFilter(&demux->filter[i]);
+			if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+				ret = StartHWFilter(&demux->filter[i]);
+				if (ret)
+					break;
+			}
 		}
 	}
 
-	return 0;
+	return ret;
 }
 
 
@@ -1009,7 +1050,7 @@
 {
 	struct dvb_demux *demux = feed->demux;
 	struct av7110 *av7110 = demux->priv;
-
+	int i, rc, ret = 0;
 	dprintk(4, "%p\n", av7110);
 
 	if (feed->type == DMX_TYPE_TS) {
@@ -1022,26 +1063,29 @@
 		}
 		if (feed->ts_type & TS_DECODER &&
 		    feed->pes_type < DMX_TS_PES_OTHER) {
-			dvb_feed_stop_pid(feed);
+			ret = dvb_feed_stop_pid(feed);
 		} else
 			if ((feed->ts_type & TS_PACKET) &&
 			    (demux->dmx.frontend->source != DMX_MEMORY_FE))
-				StopHWFilter(feed->filter);
+				ret = StopHWFilter(feed->filter);
 	}
 
-	if (feed->type == DMX_TYPE_SEC) {
-		int i;
-
-		for (i = 0; i<demux->filternum; i++)
+	if (!ret && feed->type == DMX_TYPE_SEC) {
+		for (i = 0; i<demux->filternum; i++) {
 			if (demux->filter[i].state == DMX_STATE_GO &&
 			    demux->filter[i].filter.parent == &feed->feed.sec) {
 				demux->filter[i].state = DMX_STATE_READY;
-				if (demux->dmx.frontend->source != DMX_MEMORY_FE)
-					StopHWFilter(&demux->filter[i]);
+				if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+					rc = StopHWFilter(&demux->filter[i]);
+					if (!ret)
+						ret = rc;
+					/* keep going, stop as many filters as possible */
+				}
+			}
 		}
 	}
 
-	return 0;
+	return ret;
 }
 
 
@@ -1093,7 +1137,7 @@
 	ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);
 	if (ret) {
 		printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__);
-		return -EIO;
+		return ret;
 	}
 	dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
 		fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
@@ -1119,18 +1163,14 @@
 
 	switch (tone) {
 	case SEC_TONE_ON:
-		Set22K(av7110, 1);
-		break;
+		return Set22K(av7110, 1);
 
 	case SEC_TONE_OFF:
-		Set22K(av7110, 0);
-		break;
+		return Set22K(av7110, 0);
 
 	default:
 		return -EINVAL;
 	}
-
-	return 0;
 }
 
 static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
@@ -1138,9 +1178,7 @@
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
-
-	return 0;
+	return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
 }
 
 static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
@@ -1148,9 +1186,7 @@
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_diseqc_send(av7110, 0, NULL, minicmd);
-
-	return 0;
+	return av7110_diseqc_send(av7110, 0, NULL, minicmd);
 }
 
 /* simplified code from budget-core.c */
@@ -1992,76 +2028,85 @@
 
 
 
-static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
+static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
 {
+	int ret = 0;
 	int synced = (status & FE_HAS_LOCK) ? 1 : 0;
 
 	av7110->fe_status = status;
 
 	if (av7110->fe_synced == synced)
-		return;
-
-	av7110->fe_synced = synced;
+		return 0;
 
 	if (av7110->playing)
-		return;
+		return 0;
 
 	if (down_interruptible(&av7110->pid_mutex))
-		return;
+		return -ERESTARTSYS;
 
-	if (av7110->fe_synced) {
-		SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+	if (synced) {
+		ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
 			av7110->pids[DMX_PES_AUDIO],
 			av7110->pids[DMX_PES_TELETEXT], 0,
 			av7110->pids[DMX_PES_PCR]);
-		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+		if (!ret)
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
 	} else {
-		SetPIDs(av7110, 0, 0, 0, 0, 0);
-		av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
-		av7110_wait_msgstate(av7110, GPMQBusy);
+		ret = SetPIDs(av7110, 0, 0, 0, 0, 0);
+		if (!ret) {
+			ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
+			if (!ret)
+				ret = av7110_wait_msgstate(av7110, GPMQBusy);
+		}
 	}
 
+	if (!ret)
+		av7110->fe_synced = synced;
+
 	up(&av7110->pid_mutex);
+	return ret;
 }
 
 static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct av7110* av7110 = fe->dvb->priv;
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_set_frontend(fe, params);
+
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_set_frontend(fe, params);
+	return ret;
 }
 
 static int av7110_fe_init(struct dvb_frontend* fe)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_init(fe);
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_init(fe);
+	return ret;
 }
 
 static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
 	struct av7110* av7110 = fe->dvb->priv;
-	int ret;
 
 	/* call the real implementation */
-	ret = av7110->fe_read_status(fe, status);
-	if (ret)
-		return ret;
-
-	if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) {
-		av7110_fe_lock_fix(av7110, *status);
-	}
-
-	return 0;
+	int ret = av7110->fe_read_status(fe, status);
+	if (!ret)
+		if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK))
+			ret = av7110_fe_lock_fix(av7110, *status);
+	return ret;
 }
 
 static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_diseqc_reset_overload(fe);
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_diseqc_reset_overload(fe);
+	return ret;
 }
 
 static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
@@ -2069,40 +2114,50 @@
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_diseqc_send_master_cmd(fe, cmd);
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+	return ret;
 }
 
 static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_diseqc_send_burst(fe, minicmd);
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+	return ret;
 }
 
 static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_set_tone(fe, tone);
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_set_tone(fe, tone);
+	return ret;
 }
 
 static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_set_voltage(fe, voltage);
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_set_voltage(fe, voltage);
+	return ret;
 }
 
 static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
-	av7110_fe_lock_fix(av7110, 0);
-	return av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+	int ret = av7110_fe_lock_fix(av7110, 0);
+	if (!ret)
+		ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+	return ret;
 }
 
 static u8 read_pwm(struct av7110* av7110)
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 4f69b4d..508b773 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -119,8 +119,7 @@
 	volatile int		bmp_state;
 #define BMP_NONE     0
 #define BMP_LOADING  1
-#define BMP_LOADINGS 2
-#define BMP_LOADED   3
+#define BMP_LOADED   2
 	wait_queue_head_t	bmpq;
 
 
@@ -255,12 +254,12 @@
 };
 
 
-extern void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
 		       u16 subpid, u16 pcrpid);
 
 extern void av7110_register_irc_handler(void (*func)(u32));
 extern void av7110_unregister_irc_handler(void (*func)(u32));
-extern void av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config);
+extern int av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config);
 
 extern int av7110_ir_init (void);
 extern void av7110_ir_exit (void);
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index ccf9461..0696a5a 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -121,6 +121,7 @@
 int av7110_av_start_record(struct av7110 *av7110, int av,
 			   struct dvb_demux_feed *dvbdmxfeed)
 {
+	int ret = 0;
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 
 	dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed);
@@ -137,7 +138,7 @@
 				       dvbdmx->pesfilter[0]->pid,
 				       dvb_filter_pes2ts_cb,
 				       (void *) dvbdmx->pesfilter[0]);
-		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
 		break;
 
 	case RP_VIDEO:
@@ -145,7 +146,7 @@
 				       dvbdmx->pesfilter[1]->pid,
 				       dvb_filter_pes2ts_cb,
 				       (void *) dvbdmx->pesfilter[1]);
-		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
 		break;
 
 	case RP_AV:
@@ -157,14 +158,15 @@
 				       dvbdmx->pesfilter[1]->pid,
 				       dvb_filter_pes2ts_cb,
 				       (void *) dvbdmx->pesfilter[1]);
-		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
 		break;
 	}
-	return 0;
+	return ret;
 }
 
 int av7110_av_start_play(struct av7110 *av7110, int av)
 {
+	int ret = 0;
 	dprintk(2, "av7110:%p, \n", av7110);
 
 	if (av7110->rec_mode)
@@ -182,54 +184,57 @@
 	av7110->playing |= av;
 	switch (av7110->playing) {
 	case RP_AUDIO:
-		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
 		break;
 	case RP_VIDEO:
-		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
 		av7110->sinfo = 0;
 		break;
 	case RP_AV:
 		av7110->sinfo = 0;
-		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
+		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
 		break;
 	}
-	return av7110->playing;
+	if (!ret)
+		ret = av7110->playing;
+	return ret;
 }
 
-void av7110_av_stop(struct av7110 *av7110, int av)
+int av7110_av_stop(struct av7110 *av7110, int av)
 {
+	int ret = 0;
 	dprintk(2, "av7110:%p, \n", av7110);
 
 	if (!(av7110->playing & av) && !(av7110->rec_mode & av))
-		return;
-
+		return 0;
 	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
 	if (av7110->playing) {
 		av7110->playing &= ~av;
 		switch (av7110->playing) {
 		case RP_AUDIO:
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
 			break;
 		case RP_VIDEO:
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
 			break;
 		case RP_NONE:
-			av7110_set_vidmode(av7110, av7110->vidmode);
+			ret = av7110_set_vidmode(av7110, av7110->vidmode);
 			break;
 		}
 	} else {
 		av7110->rec_mode &= ~av;
 		switch (av7110->rec_mode) {
 		case RP_AUDIO:
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
 			break;
 		case RP_VIDEO:
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
 			break;
 		case RP_NONE:
 			break;
 		}
 	}
+	return ret;
 }
 
 
@@ -317,19 +322,22 @@
 	return 0;
 }
 
-void av7110_set_vidmode(struct av7110 *av7110, int mode)
+int av7110_set_vidmode(struct av7110 *av7110, int mode)
 {
+	int ret;
 	dprintk(2, "av7110:%p, \n", av7110);
 
-	av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
 
-	if (!av7110->playing) {
-		ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+	if (!ret && !av7110->playing) {
+		ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
 			   av7110->pids[DMX_PES_AUDIO],
 			   av7110->pids[DMX_PES_TELETEXT],
 			   0, av7110->pids[DMX_PES_PCR]);
-		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+		if (!ret)
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
 	}
+	return ret;
 }
 
 
@@ -340,17 +348,18 @@
 	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
 };
 
-static void get_video_format(struct av7110 *av7110, u8 *buf, int count)
+static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
 {
 	int i;
 	int hsize, vsize;
 	int sw;
 	u8 *p;
+	int ret = 0;
 
 	dprintk(2, "av7110:%p, \n", av7110);
 
 	if (av7110->sinfo)
-		return;
+		return 0;
 	for (i = 7; i < count - 10; i++) {
 		p = buf + i;
 		if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)
@@ -359,11 +368,14 @@
 		hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);
 		vsize = ((p[1] &0x0F) << 8) | (p[2]);
 		sw = (p[3] & 0x0F);
-		av7110_set_vidmode(av7110, sw2mode[sw]);
-		dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
-		av7110->sinfo = 1;
+		ret = av7110_set_vidmode(av7110, sw2mode[sw]);
+		if (!ret) {
+			dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
+			av7110->sinfo = 1;
+		}
 		break;
 	}
+	return ret;
 }
 
 
@@ -974,7 +986,7 @@
 	unsigned long arg = (unsigned long) parg;
 	int ret = 0;
 
-	dprintk(2, "av7110:%p, \n", av7110);
+	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
 		if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
@@ -987,49 +999,57 @@
 	case VIDEO_STOP:
 		av7110->videostate.play_state = VIDEO_STOPPED;
 		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
-			av7110_av_stop(av7110, RP_VIDEO);
+			ret = av7110_av_stop(av7110, RP_VIDEO);
 		else
-			vidcom(av7110, VIDEO_CMD_STOP,
+			ret = vidcom(av7110, VIDEO_CMD_STOP,
 			       av7110->videostate.video_blank ? 0 : 1);
-		av7110->trickmode = TRICK_NONE;
+		if (!ret)
+			av7110->trickmode = TRICK_NONE;
 		break;
 
 	case VIDEO_PLAY:
 		av7110->trickmode = TRICK_NONE;
 		if (av7110->videostate.play_state == VIDEO_FREEZED) {
 			av7110->videostate.play_state = VIDEO_PLAYING;
-			vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			if (ret)
+				break;
 		}
 
 		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
 			if (av7110->playing == RP_AV) {
-				av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+				if (ret)
+					break;
 				av7110->playing &= ~RP_VIDEO;
 			}
-			av7110_av_start_play(av7110, RP_VIDEO);
-			vidcom(av7110, VIDEO_CMD_PLAY, 0);
-		} else {
-			//av7110_av_stop(av7110, RP_VIDEO);
-			vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			ret = av7110_av_start_play(av7110, RP_VIDEO);
 		}
-		av7110->videostate.play_state = VIDEO_PLAYING;
+		if (!ret)
+			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+		if (!ret)
+			av7110->videostate.play_state = VIDEO_PLAYING;
 		break;
 
 	case VIDEO_FREEZE:
 		av7110->videostate.play_state = VIDEO_FREEZED;
 		if (av7110->playing & RP_VIDEO)
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
 		else
-			vidcom(av7110, VIDEO_CMD_FREEZE, 1);
-		av7110->trickmode = TRICK_FREEZE;
+			ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1);
+		if (!ret)
+			av7110->trickmode = TRICK_FREEZE;
 		break;
 
 	case VIDEO_CONTINUE:
 		if (av7110->playing & RP_VIDEO)
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
-		vidcom(av7110, VIDEO_CMD_PLAY, 0);
-		av7110->videostate.play_state = VIDEO_PLAYING;
-		av7110->trickmode = TRICK_NONE;
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
+		if (!ret)
+			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+		if (!ret) {
+			av7110->videostate.play_state = VIDEO_PLAYING;
+			av7110->trickmode = TRICK_NONE;
+		}
 		break;
 
 	case VIDEO_SELECT_SOURCE:
@@ -1045,7 +1065,7 @@
 		break;
 
 	case VIDEO_GET_EVENT:
-		ret=dvb_video_get_event(av7110, parg, file->f_flags);
+		ret = dvb_video_get_event(av7110, parg, file->f_flags);
 		break;
 
 	case VIDEO_GET_SIZE:
@@ -1105,25 +1125,32 @@
 	case VIDEO_FAST_FORWARD:
 		//note: arg is ignored by firmware
 		if (av7110->playing & RP_VIDEO)
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-				      __Scan_I, 2, AV_PES, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+					    __Scan_I, 2, AV_PES, 0);
 		else
-			vidcom(av7110, VIDEO_CMD_FFWD, arg);
-		av7110->trickmode = TRICK_FAST;
-		av7110->videostate.play_state = VIDEO_PLAYING;
+			ret = vidcom(av7110, VIDEO_CMD_FFWD, arg);
+		if (!ret) {
+			av7110->trickmode = TRICK_FAST;
+			av7110->videostate.play_state = VIDEO_PLAYING;
+		}
 		break;
 
 	case VIDEO_SLOWMOTION:
 		if (av7110->playing&RP_VIDEO) {
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
-			vidcom(av7110, VIDEO_CMD_SLOW, arg);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
+			if (!ret)
+				ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
 		} else {
-			vidcom(av7110, VIDEO_CMD_PLAY, 0);
-			vidcom(av7110, VIDEO_CMD_STOP, 0);
-			vidcom(av7110, VIDEO_CMD_SLOW, arg);
+			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			if (!ret)
+				ret = vidcom(av7110, VIDEO_CMD_STOP, 0);
+			if (!ret)
+				ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
 		}
-		av7110->trickmode = TRICK_SLOW;
-		av7110->videostate.play_state = VIDEO_PLAYING;
+		if (!ret) {
+			av7110->trickmode = TRICK_SLOW;
+			av7110->videostate.play_state = VIDEO_PLAYING;
+		}
 		break;
 
 	case VIDEO_GET_CAPABILITIES:
@@ -1136,18 +1163,21 @@
 		av7110_ipack_reset(&av7110->ipack[1]);
 
 		if (av7110->playing == RP_AV) {
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-				      __Play, 2, AV_PES, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+					    __Play, 2, AV_PES, 0);
+			if (ret)
+				break;
 			if (av7110->trickmode == TRICK_FAST)
-				av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-					      __Scan_I, 2, AV_PES, 0);
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+						    __Scan_I, 2, AV_PES, 0);
 			if (av7110->trickmode == TRICK_SLOW) {
-				av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-					      __Slow, 2, 0, 0);
-				vidcom(av7110, VIDEO_CMD_SLOW, arg);
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+						    __Slow, 2, 0, 0);
+				if (!ret)
+					ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
 			}
 			if (av7110->trickmode == TRICK_FREEZE)
-				vidcom(av7110, VIDEO_CMD_STOP, 1);
+				ret = vidcom(av7110, VIDEO_CMD_STOP, 1);
 		}
 		break;
 
@@ -1170,7 +1200,7 @@
 	unsigned long arg = (unsigned long) parg;
 	int ret = 0;
 
-	dprintk(2, "av7110:%p, \n", av7110);
+	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
 
 	if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&
 	    (cmd != AUDIO_GET_STATUS))
@@ -1179,28 +1209,32 @@
 	switch (cmd) {
 	case AUDIO_STOP:
 		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
-			av7110_av_stop(av7110, RP_AUDIO);
+			ret = av7110_av_stop(av7110, RP_AUDIO);
 		else
-			audcom(av7110, AUDIO_CMD_MUTE);
-		av7110->audiostate.play_state = AUDIO_STOPPED;
+			ret = audcom(av7110, AUDIO_CMD_MUTE);
+		if (!ret)
+			av7110->audiostate.play_state = AUDIO_STOPPED;
 		break;
 
 	case AUDIO_PLAY:
 		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
-			av7110_av_start_play(av7110, RP_AUDIO);
-		audcom(av7110, AUDIO_CMD_UNMUTE);
-		av7110->audiostate.play_state = AUDIO_PLAYING;
+			ret = av7110_av_start_play(av7110, RP_AUDIO);
+		if (!ret)
+			ret = audcom(av7110, AUDIO_CMD_UNMUTE);
+		if (!ret)
+			av7110->audiostate.play_state = AUDIO_PLAYING;
 		break;
 
 	case AUDIO_PAUSE:
-		audcom(av7110, AUDIO_CMD_MUTE);
-		av7110->audiostate.play_state = AUDIO_PAUSED;
+		ret = audcom(av7110, AUDIO_CMD_MUTE);
+		if (!ret)
+			av7110->audiostate.play_state = AUDIO_PAUSED;
 		break;
 
 	case AUDIO_CONTINUE:
 		if (av7110->audiostate.play_state == AUDIO_PAUSED) {
 			av7110->audiostate.play_state = AUDIO_PLAYING;
-			audcom(av7110, AUDIO_CMD_MUTE | AUDIO_CMD_PCM16);
+			ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16);
 		}
 		break;
 
@@ -1210,14 +1244,15 @@
 
 	case AUDIO_SET_MUTE:
 	{
-		audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
-		av7110->audiostate.mute_state = (int) arg;
+		ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
+		if (!ret)
+			av7110->audiostate.mute_state = (int) arg;
 		break;
 	}
 
 	case AUDIO_SET_AV_SYNC:
 		av7110->audiostate.AV_sync_state = (int) arg;
-		audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
+		ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
 		break;
 
 	case AUDIO_SET_BYPASS_MODE:
@@ -1229,21 +1264,24 @@
 
 		switch(av7110->audiostate.channel_select) {
 		case AUDIO_STEREO:
-			audcom(av7110, AUDIO_CMD_STEREO);
-			if (av7110->adac_type == DVB_ADAC_CRYSTAL)
-				i2c_writereg(av7110, 0x20, 0x02, 0x49);
+			ret = audcom(av7110, AUDIO_CMD_STEREO);
+			if (!ret)
+				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+					i2c_writereg(av7110, 0x20, 0x02, 0x49);
 			break;
 
 		case AUDIO_MONO_LEFT:
-			audcom(av7110, AUDIO_CMD_MONO_L);
-			if (av7110->adac_type == DVB_ADAC_CRYSTAL)
-				i2c_writereg(av7110, 0x20, 0x02, 0x4a);
+			ret = audcom(av7110, AUDIO_CMD_MONO_L);
+			if (!ret)
+				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+					i2c_writereg(av7110, 0x20, 0x02, 0x4a);
 			break;
 
 		case AUDIO_MONO_RIGHT:
-			audcom(av7110, AUDIO_CMD_MONO_R);
-			if (av7110->adac_type == DVB_ADAC_CRYSTAL)
-				i2c_writereg(av7110, 0x20, 0x02, 0x45);
+			ret = audcom(av7110, AUDIO_CMD_MONO_R);
+			if (!ret)
+				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+					i2c_writereg(av7110, 0x20, 0x02, 0x45);
 			break;
 
 		default:
@@ -1264,8 +1302,8 @@
 		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
 		av7110_ipack_reset(&av7110->ipack[0]);
 		if (av7110->playing == RP_AV)
-			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
-			       __Play, 2, AV_PES, 0);
+			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+					    __Play, 2, AV_PES, 0);
 		break;
 	case AUDIO_SET_ID:
 
@@ -1274,7 +1312,7 @@
 	{
 		struct audio_mixer *amix = (struct audio_mixer *)parg;
 
-		av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
+		ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
 		break;
 	}
 	case AUDIO_SET_STREAMTYPE:
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
index cc5e7a7..45dc144 100644
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ b/drivers/media/dvb/ttpci/av7110_av.h
@@ -3,14 +3,14 @@
 
 struct av7110;
 
-extern void av7110_set_vidmode(struct av7110 *av7110, int mode);
+extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
 
 extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
 extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
 extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
 
 extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright);
-extern void av7110_av_stop(struct av7110 *av7110, int av);
+extern int av7110_av_stop(struct av7110 *av7110, int av);
 extern int av7110_av_start_record(struct av7110 *av7110, int av,
 			  struct dvb_demux_feed *dvbdmxfeed);
 extern int av7110_av_start_play(struct av7110 *av7110, int av);
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 7fa4a0e..1220826 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -137,7 +137,7 @@
 			return 0;
 		udelay(5);
 	}
-	return -1;
+	return -ETIMEDOUT;
 }
 
 static int load_dram(struct av7110 *av7110, u32 *data, int len)
@@ -155,7 +155,7 @@
 	for (i = 0; i < blocks; i++) {
 		if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
-			return -1;
+			return -ETIMEDOUT;
 		}
 		dprintk(4, "writing DRAM block %d\n", i);
 		mwdebi(av7110, DEBISWAB, bootblock,
@@ -170,7 +170,7 @@
 	if (rest > 0) {
 		if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
-			return -1;
+			return -ETIMEDOUT;
 		}
 		if (rest > 4)
 			mwdebi(av7110, DEBISWAB, bootblock,
@@ -185,13 +185,13 @@
 	}
 	if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 		printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
-		return -1;
+		return -ETIMEDOUT;
 	}
 	iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
 	iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 	if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) {
 		printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
-		return -1;
+		return -ETIMEDOUT;
 	}
 	return 0;
 }
@@ -263,7 +263,7 @@
 	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
 		       "saa7146_wait_for_debi_done() timed out\n");
-		return -1;
+		return -ETIMEDOUT;
 	}
 	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 	mdelay(1);
@@ -284,7 +284,7 @@
 	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
 		       "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
-		return -1;
+		return -ETIMEDOUT;
 	}
 	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 	msleep(30);	/* the firmware needs some time to initialize */
@@ -308,6 +308,7 @@
 {
 	unsigned long start;
 	u32 stat;
+	int err;
 
 	if (FW_VERSION(av7110->arm_app) <= 0x261c) {
 		/* not supported by old firmware */
@@ -318,17 +319,17 @@
 	/* new firmware */
 	start = jiffies;
 	for (;;) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
 		if (down_interruptible(&av7110->dcomlock))
 			return -ERESTARTSYS;
 		stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 		up(&av7110->dcomlock);
-		if ((stat & flags) == 0) {
+		if ((stat & flags) == 0)
 			break;
-		}
-		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+		if (err) {
 			printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
 				__FUNCTION__, stat & flags);
-			return -1;
+			return -ETIMEDOUT;
 		}
 		msleep(1);
 	}
@@ -342,6 +343,7 @@
 	char *type = NULL;
 	u16 flags[2] = {0, 0};
 	u32 stat;
+	int err;
 
 //	dprintk(4, "%p\n", av7110);
 
@@ -351,24 +353,30 @@
 	}
 
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
-		msleep(1);
-		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
+		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+			break;
+		if (err) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
 			return -ETIMEDOUT;
 		}
+		msleep(1);
 	}
 
 	wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
 
 #ifndef _NOHANDSHAKE
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
-		msleep(1);
-		if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+		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__);
 			return -ETIMEDOUT;
 		}
+		msleep(1);
 	}
 #endif
 
@@ -401,6 +409,7 @@
 		/* non-immediate COMMAND type */
 		start = jiffies;
 		for (;;) {
+			err = time_after(jiffies, start + ARM_WAIT_FREE);
 			stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 			if (stat & flags[0]) {
 				printk(KERN_ERR "%s: %s QUEUE overflow\n",
@@ -409,10 +418,10 @@
 			}
 			if ((stat & flags[1]) == 0)
 				break;
-			if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+			if (err) {
 				printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
 					__FUNCTION__, type);
-				return -1;
+				return -ETIMEDOUT;
 			}
 			msleep(1);
 		}
@@ -432,13 +441,16 @@
 
 #ifdef COM_DEBUG
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
-		msleep(1);
-		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
-			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
-			       __FUNCTION__);
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
+		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
+			       __FUNCTION__, (buf[0] >> 8) & 0xff);
 			return -ETIMEDOUT;
 		}
+		msleep(1);
 	}
 
 	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
@@ -470,7 +482,7 @@
 
 	ret = __av7110_send_fw_cmd(av7110, buf, length);
 	up(&av7110->dcomlock);
-	if (ret)
+	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
 		       __FUNCTION__, ret);
 	return ret;
@@ -495,7 +507,7 @@
 	}
 
 	ret = av7110_send_fw_cmd(av7110, buf, num + 2);
-	if (ret)
+	if (ret && ret != -ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
 	return ret;
 }
@@ -518,7 +530,7 @@
 	}
 
 	ret = av7110_send_fw_cmd(av7110, cmd, 18);
-	if (ret)
+	if (ret && ret != -ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
 	return ret;
 }
@@ -551,26 +563,32 @@
 	}
 
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_FREE);
+		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+			break;
+		if (err) {
+			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
+			up(&av7110->dcomlock);
+			return -ETIMEDOUT;
+		}
 #ifdef _NOHANDSHAKE
 		msleep(1);
 #endif
-		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
-			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
-			up(&av7110->dcomlock);
-			return -1;
-		}
 	}
 
 #ifndef _NOHANDSHAKE
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
-		msleep(1);
-		if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+			break;
+		if (err) {
 			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
 			up(&av7110->dcomlock);
-			return -1;
+			return -ETIMEDOUT;
 		}
+		msleep(1);
 	}
 #endif
 
@@ -667,10 +685,10 @@
 	for (i = 0; i < len; i++)
 		buf[i + 4] = msg[i];
 
-	if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
+	ret = av7110_send_fw_cmd(av7110, buf, 18);
+	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
-
-	return 0;
+	return ret;
 }
 
 
@@ -705,18 +723,22 @@
 static int FlushText(struct av7110 *av7110)
 {
 	unsigned long start;
+	int err;
 
 	if (down_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
-		msleep(1);
-		if (time_after(jiffies, start + ARM_WAIT_OSD)) {
+	while (1) {
+		err = time_after(jiffies, start + ARM_WAIT_OSD);
+		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+			break;
+		if (err) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
 			up(&av7110->dcomlock);
-			return -1;
+			return -ETIMEDOUT;
 		}
+		msleep(1);
 	}
 	up(&av7110->dcomlock);
 	return 0;
@@ -733,25 +755,31 @@
 		return -ERESTARTSYS;
 
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
-		msleep(1);
-		if (time_after(jiffies, start + ARM_WAIT_OSD)) {
+	while (1) {
+		ret = time_after(jiffies, start + ARM_WAIT_OSD);
+		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+			break;
+		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
 			up(&av7110->dcomlock);
-			return -1;
+			return -ETIMEDOUT;
 		}
+		msleep(1);
 	}
 #ifndef _NOHANDSHAKE
 	start = jiffies;
-	while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
-		msleep(1);
-		if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+	while (1) {
+		ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
+		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+			break;
+		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
 			       __FUNCTION__);
 			up(&av7110->dcomlock);
-			return -1;
+			return -ETIMEDOUT;
 		}
+		msleep(1);
 	}
 #endif
 	for (i = 0; i < length / 2; i++)
@@ -761,7 +789,7 @@
 		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
 	ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
 	up(&av7110->dcomlock);
-	if (ret)
+	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
 	return ret;
 }
@@ -816,9 +844,25 @@
 	OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
 };
 
-static inline int LoadBitmap(struct av7110 *av7110, u16 format,
+static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
+{
+	int ret = wait_event_interruptible_timeout(av7110->bmpq,
+				av7110->bmp_state != BMP_LOADING, 10*HZ);
+	if (ret == -ERESTARTSYS)
+		return ret;
+	if (ret == 0) {
+		printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
+		       ret, av7110->bmp_state);
+		av7110->bmp_state = BMP_NONE;
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static inline int LoadBitmap(struct av7110 *av7110,
 			     u16 dx, u16 dy, int inc, u8 __user * data)
 {
+	u16 format;
 	int bpp;
 	int i;
 	int d, delta;
@@ -827,14 +871,7 @@
 
 	dprintk(4, "%p\n", av7110);
 
-	ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
-	if (ret == -ERESTARTSYS || ret == 0) {
-		printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
-		       ret, av7110->bmp_state);
-		av7110->bmp_state = BMP_NONE;
-		return -1;
-	}
-	BUG_ON (av7110->bmp_state == BMP_LOADING);
+	format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
 
 	av7110->bmp_state = BMP_LOADING;
 	if	(format == OSD_BITMAP8) {
@@ -847,18 +884,18 @@
 		bpp=1; delta = 8;
 	} else {
 		av7110->bmp_state = BMP_NONE;
-		return -1;
+		return -EINVAL;
 	}
 	av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
 	av7110->bmpp = 0;
 	if (av7110->bmplen > 32768) {
 		av7110->bmp_state = BMP_NONE;
-		return -1;
+		return -EINVAL;
 	}
 	for (i = 0; i < dy; i++) {
 		if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
 			av7110->bmp_state = BMP_NONE;
-			return -1;
+			return -EINVAL;
 		}
 	}
 	if (format != OSD_BITMAP8) {
@@ -873,37 +910,27 @@
 	}
 	av7110->bmplen += 1024;
 	dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+	ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+	if (!ret)
+		ret = WaitUntilBmpLoaded(av7110);
+	return ret;
 }
 
-static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
+static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
 {
-	int ret;
-
 	dprintk(4, "%p\n", av7110);
 
-	BUG_ON (av7110->bmp_state == BMP_NONE);
-
-	ret = wait_event_interruptible_timeout(av7110->bmpq,
-				av7110->bmp_state != BMP_LOADING, 10*HZ);
-	if (ret == -ERESTARTSYS || ret == 0) {
-		printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
-		       ret, av7110->bmp_state);
-		av7110->bmp_state = BMP_NONE;
-		return (ret == 0) ? -ETIMEDOUT : ret;
-	}
-
-	BUG_ON (av7110->bmp_state != BMP_LOADED);
-
-	return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
 }
 
 static inline int ReleaseBitmap(struct av7110 *av7110)
 {
 	dprintk(4, "%p\n", av7110);
 
-	if (av7110->bmp_state != BMP_LOADED)
+	if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
 		return -1;
+	if (av7110->bmp_state == BMP_LOADING)
+		dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
 	av7110->bmp_state = BMP_NONE;
 	return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
 }
@@ -924,18 +951,22 @@
 	return Cr | (Cb << 16) | (Y << 8);
 }
 
-static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
+static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
 {
+	int ret;
+
 	u16 ch, cl;
 	u32 yuv;
 
 	yuv = blend ? RGB2YUV(r,g,b) : 0;
 	cl = (yuv & 0xffff);
 	ch = ((yuv >> 16) & 0xffff);
-	SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
-		  color, ch, cl);
-	SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
-		  color, ((blend >> 4) & 0x0f));
+	ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+			color, ch, cl);
+	if (!ret)
+		ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+				color, ((blend >> 4) & 0x0f));
+	return ret;
 }
 
 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
@@ -968,14 +999,14 @@
 {
 	uint w, h, bpp, bpl, size, lpb, bnum, brest;
 	int i;
-	int rc;
+	int rc,release_rc;
 
 	w = x1 - x0 + 1;
 	h = y1 - y0 + 1;
 	if (inc <= 0)
 		inc = w;
 	if (w <= 0 || w > 720 || h <= 0 || h > 576)
-		return -1;
+		return -EINVAL;
 	bpp = av7110->osdbpp[av7110->osdwin] + 1;
 	bpl = ((w * bpp + 7) & ~7) / 8;
 	size = h * bpl;
@@ -983,176 +1014,186 @@
 	bnum = size / (lpb * bpl);
 	brest = size - bnum * lpb * bpl;
 
+	if (av7110->bmp_state == BMP_LOADING) {
+		/* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
+		BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
+		rc = WaitUntilBmpLoaded(av7110);
+		if (rc)
+			return rc;
+		/* just continue. This should work for all fw versions
+		 * if bnum==1 && !brest && LoadBitmap was successful
+		 */
+	}
+
+	rc = 0;
 	for (i = 0; i < bnum; i++) {
-		rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
-			   w, lpb, inc, data);
+		rc = LoadBitmap(av7110, w, lpb, inc, data);
 		if (rc)
-			return rc;
-		rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
+			break;
+		rc = BlitBitmap(av7110, x0, y0 + i * lpb);
 		if (rc)
-			return rc;
+			break;
 		data += lpb * inc;
 	}
-	if (brest) {
-		rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
-			   w, brest / bpl, inc, data);
-		if (rc)
-			return rc;
-		rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
-		if (rc)
-			return rc;
+	if (!rc && brest) {
+		rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
+		if (!rc)
+			rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
 	}
-	ReleaseBitmap(av7110);
-	return 0;
+	release_rc = ReleaseBitmap(av7110);
+	if (!rc)
+		rc = release_rc;
+	if (rc)
+		dprintk(1,"returns %d\n",rc);
+	return rc;
 }
 
 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
 {
 	int ret;
 
-	ret = down_interruptible(&av7110->osd_sema);
-	if (ret)
+	if (down_interruptible(&av7110->osd_sema))
 		return -ERESTARTSYS;
 
-	/* stupid, but OSD functions don't provide a return code anyway */
-	ret = 0;
-
 	switch (dc->cmd) {
 	case OSD_Close:
-		DestroyOSDWindow(av7110, av7110->osdwin);
-		goto out;
+		ret = DestroyOSDWindow(av7110, av7110->osdwin);
+		break;
 	case OSD_Open:
 		av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
-		CreateOSDWindow(av7110, av7110->osdwin,
+		ret = CreateOSDWindow(av7110, av7110->osdwin,
 				bpp2bit[av7110->osdbpp[av7110->osdwin]],
 				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+		if (ret)
+			break;
 		if (!dc->data) {
-			MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-			SetColorBlend(av7110, av7110->osdwin);
+			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+			if (ret)
+				break;
+			ret = SetColorBlend(av7110, av7110->osdwin);
 		}
-		goto out;
+		break;
 	case OSD_Show:
-		MoveWindowRel(av7110, av7110->osdwin, 0, 0);
-		goto out;
+		ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
+		break;
 	case OSD_Hide:
-		HideWindow(av7110, av7110->osdwin);
-		goto out;
+		ret = HideWindow(av7110, av7110->osdwin);
+		break;
 	case OSD_Clear:
-		DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
-		goto out;
+		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
+		break;
 	case OSD_Fill:
-		DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
-		goto out;
+		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
+		break;
 	case OSD_SetColor:
-		OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
-		goto out;
+		ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
+		break;
 	case OSD_SetPalette:
-	{
-		if (FW_VERSION(av7110->arm_app) >= 0x2618) {
+		if (FW_VERSION(av7110->arm_app) >= 0x2618)
 			ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
-			goto out;
-		} else {
+		else {
 			int i, len = dc->x0-dc->color+1;
 			u8 __user *colors = (u8 __user *)dc->data;
 			u8 r, g, b, blend;
-
+			ret = 0;
 			for (i = 0; i<len; i++) {
 				if (get_user(r, colors + i * 4) ||
 				    get_user(g, colors + i * 4 + 1) ||
 				    get_user(b, colors + i * 4 + 2) ||
 				    get_user(blend, colors + i * 4 + 3)) {
 					ret = -EFAULT;
-					goto out;
+					break;
 				    }
-				OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+				ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+				if (ret)
+					break;
 			}
 		}
-		ret = 0;
-		goto out;
-	}
-	case OSD_SetTrans:
-		goto out;
+		break;
 	case OSD_SetPixel:
-		DrawLine(av7110, av7110->osdwin,
+		ret = DrawLine(av7110, av7110->osdwin,
 			 dc->x0, dc->y0, 0, 0, dc->color);
-		goto out;
-	case OSD_GetPixel:
-		goto out;
+		break;
 	case OSD_SetRow:
 		dc->y1 = dc->y0;
 		/* fall through */
 	case OSD_SetBlock:
 		ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
-		goto out;
+		break;
 	case OSD_FillRow:
-		DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
 			  dc->x1-dc->x0+1, dc->y1, dc->color);
-		goto out;
+		break;
 	case OSD_FillBlock:
-		DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
 			  dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
-		goto out;
+		break;
 	case OSD_Line:
-		DrawLine(av7110, av7110->osdwin,
+		ret = DrawLine(av7110, av7110->osdwin,
 			 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
-		goto out;
-	case OSD_Query:
-		goto out;
-	case OSD_Test:
-		goto out;
+		break;
 	case OSD_Text:
 	{
 		char textbuf[240];
 
 		if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
 			ret = -EFAULT;
-			goto out;
+			break;
 		}
 		textbuf[239] = 0;
 		if (dc->x1 > 3)
 			dc->x1 = 3;
-		SetFont(av7110, av7110->osdwin, dc->x1,
+		ret = SetFont(av7110, av7110->osdwin, dc->x1,
 			(u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
-		FlushText(av7110);
-		WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
-		goto out;
+		if (!ret)
+			ret = FlushText(av7110);
+		if (!ret)
+			ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
+		break;
 	}
 	case OSD_SetWindow:
-		if (dc->x0 < 1 || dc->x0 > 7) {
+		if (dc->x0 < 1 || dc->x0 > 7)
 			ret = -EINVAL;
-			goto out;
+		else {
+			av7110->osdwin = dc->x0;
+			ret = 0;
 		}
-		av7110->osdwin = dc->x0;
-		goto out;
+		break;
 	case OSD_MoveWindow:
-		MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-		SetColorBlend(av7110, av7110->osdwin);
-		goto out;
+		ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+		if (!ret)
+			ret = SetColorBlend(av7110, av7110->osdwin);
+		break;
 	case OSD_OpenRaw:
 		if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
 			ret = -EINVAL;
-			goto out;
+			break;
 		}
-		if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) {
+		if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
 			av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
-		}
-		else {
+		else
 			av7110->osdbpp[av7110->osdwin] = 0;
-		}
-		CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
+		ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
 				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+		if (ret)
+			break;
 		if (!dc->data) {
-			MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-			SetColorBlend(av7110, av7110->osdwin);
+			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+			if (!ret)
+				ret = SetColorBlend(av7110, av7110->osdwin);
 		}
-		goto out;
+		break;
 	default:
 		ret = -EINVAL;
-		goto out;
+		break;
 	}
 
-out:
 	up(&av7110->osd_sema);
+	if (ret==-ERESTARTSYS)
+		dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
+	else if (ret)
+		dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
+
 	return ret;
 }
 
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 52061e1..fedd20f 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -458,27 +458,27 @@
 	return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data);
 }
 
-static inline void av7710_set_video_mode(struct av7110 *av7110, int mode)
+static inline int av7710_set_video_mode(struct av7110 *av7110, int mode)
 {
-	av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
+	return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
 }
 
-static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg)
+static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg)
 {
 	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4,
 			     (com>>16), (com&0xffff),
 			     (arg>>16), (arg&0xffff));
 }
 
-static int inline audcom(struct av7110 *av7110, u32 com)
+static inline int audcom(struct av7110 *av7110, u32 com)
 {
 	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
 			     (com>>16), (com&0xffff));
 }
 
-static inline void Set22K(struct av7110 *av7110, int state)
+static inline int Set22K(struct av7110 *av7110, int state)
 {
-	av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
+	return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
 }
 
 
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c
index 2466407..699ef8b 100644
--- a/drivers/media/dvb/ttpci/av7110_ipack.c
+++ b/drivers/media/dvb/ttpci/av7110_ipack.c
@@ -24,7 +24,7 @@
 		      void (*func)(u8 *buf, int size, void *priv))
 {
 	if (!(p->buf = vmalloc(size*sizeof(u8)))) {
-		printk ("Couldn't allocate memory for ipack\n");
+		printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
 		return -ENOMEM;
 	}
 	p->size = size;
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 6e0f5d3..b65f4b0 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -570,9 +570,9 @@
 
 	buf[0] = (div >> 8) & 0x7f;
 	buf[1] = div & 0xff;
-	buf[2] = 0x8e;
-	buf[3] = (params->frequency < 174500000 ? 0xa1 :
-		  params->frequency < 454000000 ? 0x92 : 0x34);
+	buf[2] = 0x86;
+	buf[3] = (params->frequency < 150000000 ? 0x01 :
+		  params->frequency < 445000000 ? 0x02 : 0x04);
 
 	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
 		return -EIO;
@@ -695,8 +695,12 @@
 	.demod_address = 0x8,
 	.invert = 1,
 	.invert_oclk = 1,
+	.xtal_freq = TDA10046_XTAL_4M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
 	.pll_init = philips_tu1216_pll_init,
 	.pll_set = philips_tu1216_pll_set,
+	.pll_sleep = NULL,
 	.request_firmware = philips_tu1216_request_firmware,
 };
 
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index dce1161..a126705 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -69,6 +69,7 @@
 	int slot_status;
 	struct dvb_ca_en50221 ca;
 	char ir_dev_name[50];
+	u8 tuner_pll_address; /* used for philips_tdm1316l configs */
 };
 
 /* from reading the following remotes:
@@ -723,7 +724,7 @@
 	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
 	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
 	static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
-	struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = td1316_init,.len =
+	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
 			sizeof(td1316_init) };
 
 	// setup PLL configuration
@@ -746,7 +747,7 @@
 {
 	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
 	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
+	struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
 	int tuner_frequency = 0;
 	u8 band, cp, filter;
 
@@ -838,8 +839,12 @@
 	.demod_address = 0x8,
 	.invert = 0,
 	.invert_oclk = 0,
+	.xtal_freq = TDA10046_XTAL_4M,
+	.agc_config = TDA10046_AGC_DEFAULT,
+	.if_freq = TDA10046_FREQ_3617,
 	.pll_init = philips_tdm1316l_pll_init,
 	.pll_set = philips_tdm1316l_pll_set,
+	.pll_sleep = NULL,
 	.request_firmware = philips_tdm1316l_request_firmware,
 };
 
@@ -865,12 +870,22 @@
 		break;
 
 	case 0x1011:		// Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+		budget_ci->tuner_pll_address = 0x63;
 		budget_ci->budget.dvb_frontend =
 			tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
 			break;
 		}
 		break;
+
+	case 0x1012:		// Hauppauge/TT Nova-T CI budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+		budget_ci->tuner_pll_address = 0x60;
+		budget_ci->budget.dvb_frontend =
+			tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			break;
+		}
+		break;
 	}
 
 	if (budget_ci->budget.dvb_frontend == NULL) {
@@ -950,11 +965,13 @@
 
 MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
 	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
+	MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
 	{
 	 .vendor = 0,
 	 }
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 083fd44..9961917 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -40,6 +40,7 @@
 #include "ves1820.h"
 #include "l64781.h"
 #include "tda8083.h"
+#include "s5h1420.h"
 
 static void Set22K (struct budget *budget, int state)
 {
@@ -177,6 +178,62 @@
 	return 0;
 }
 
+static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u8 buf;
+	struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+	switch(voltage) {
+	case SEC_VOLTAGE_13:
+		buf = (buf & 0xf7) | 0x04;
+		break;
+
+	case SEC_VOLTAGE_18:
+		buf = (buf & 0xf7) | 0x0c;
+		break;
+
+	case SEC_VOLTAGE_OFF:
+		buf = buf & 0xf0;
+		break;
+	}
+
+	msg.flags = 0;
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+	return 0;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u8 buf;
+	struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+	if (arg) {
+		buf = buf | 0x10;
+	} else {
+		buf = buf & 0xef;
+	}
+
+	msg.flags = 0;
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+	return 0;
+}
+
+static void lnbp21_init(struct budget* budget)
+{
+	u8 buf = 0x00;
+	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
+
+	i2c_transfer (&budget->i2c_adap, &msg, 1);
+}
+
 static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -395,6 +452,38 @@
 	.pll_set = grundig_29504_451_pll_set,
 };
 
+static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = params->frequency / 1000;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0xc2;
+
+	if (div < 1450)
+		data[3] = 0x00;
+	else if (div < 1850)
+		data[3] = 0x40;
+	else if (div < 2000)
+		data[3] = 0x80;
+	else
+		data[3] = 0xc0;
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+	*freqout = div * 1000;
+	return 0;
+}
+
+static struct s5h1420_config s5h1420_config = {
+	.demod_address = 0x53,
+	.pll_set = s5h1420_pll_set,
+};
+
 static u8 read_pwm(struct budget* budget)
 {
 	u8 b = 0xff;
@@ -459,6 +548,15 @@
 			break;
 		}
 		break;
+
+	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
+		budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
+			budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+			lnbp21_init(budget);
+			break;
+		}
 	}
 
 	if (budget->dvb_frontend == NULL) {
@@ -532,6 +630,7 @@
 	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
 	{
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 4aa714a..c6c1d41 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -3,6 +3,7 @@
 	depends on DVB_CORE && USB
 	select DVB_CX22700
 	select DVB_TDA1004X
+	select DVB_VES1820
 	select DVB_TDA8083
 	select DVB_STV0299
 	help
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index afa0e7a..2c17a5f 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -24,6 +24,7 @@
 #include "dmxdev.h"
 #include "dvb_demux.h"
 #include "dvb_net.h"
+#include "ves1820.h"
 #include "cx22700.h"
 #include "tda1004x.h"
 #include "stv0299.h"
@@ -1367,6 +1368,47 @@
 	.pll_set = ttusb_novas_grundig_29504_491_pll_set,
 };
 
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct ttusb* ttusb = fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (params->frequency + 35937500 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85 | ((div >> 10) & 0x60);
+	data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+	if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+
+static struct ves1820_config alps_tdbe2_config = {
+	.demod_address = 0x09,
+	.xin = 57840000UL,
+	.invert = 1,
+	.selagc = VES1820_SELAGC_SIGNAMPERR,
+	.pll_set = alps_tdbe2_pll_set,
+};
+
+static u8 read_pwm(struct ttusb* ttusb)
+{
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+				{ .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+	if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
 
 
 static void frontend_init(struct ttusb* ttusb)
@@ -1394,6 +1436,12 @@
 
 		break;
 
+	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+		ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
+		if (ttusb->fe != NULL)
+			break;
+		break;
+
 	case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
 		// try the ALPS TDMB7 first
 		ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
@@ -1570,7 +1618,7 @@
 
 static struct usb_device_id ttusb_table[] = {
 	{USB_DEVICE(0xb48, 0x1003)},
-/*	{USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/	/* to be confirmed ????  */
+	{USB_DEVICE(0xb48, 0x1004)},
 	{USB_DEVICE(0xb48, 0x1005)},
 	{}
 };
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 505bdaf..45c9a9a 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1281,6 +1281,7 @@
 	if (firmware_size < 60) {
 		printk("%s: firmware size too small for DSP code (%zu < 60).\n",
 			__FUNCTION__, firmware_size);
+		release_firmware(fw_entry);
 		return -1;
 	}
 
@@ -1294,6 +1295,7 @@
 		printk("%s: crc32 check of DSP code failed (calculated "
 		       "0x%08x != 0x%08x in file), file invalid.\n",
 			__FUNCTION__, crc32_csum, crc32_check);
+		release_firmware(fw_entry);
 		return -1;
 	}
 	memcpy(idstring, &firmware[36], 20);
@@ -1308,15 +1310,19 @@
 
 	result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
 
-	if (result)
+	if (result) {
+		release_firmware(fw_entry);
 		return result;
+	}
 
 	trans_count = 0;
 	j = 0;
 
 	b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL);
-	if (b == NULL)
+	if (b == NULL) {
+		release_firmware(fw_entry);
 		return -ENOMEM;
+	}
 
 	for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) {
 		size = firmware_size - i;
@@ -1345,6 +1351,7 @@
 
 	result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);
 
+	release_firmware(fw_entry);
 	kfree(b);
 
 	return result;
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 1699cc9..725af3a 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -157,7 +157,8 @@
 
 	/* allocate memory for the internal state */
 	state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
-	if (state == NULL) goto error;
+	if (state == NULL)
+		return NULL;
 
 	/* setup the state */
 	state->config = config;
@@ -167,10 +168,6 @@
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
 }
 
 static struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
@@ -181,7 +178,8 @@
 
 	/* allocate memory for the internal state */
 	state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
-	if (state == NULL) goto error;
+	if (state == NULL)
+		return NULL;
 
 	/* setup the state */
 	state->config = config;
@@ -193,10 +191,6 @@
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
 }
 
 static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 1b70f8b..e771064 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -344,6 +344,7 @@
 	select DVB_MT352
 	select DVB_OR51132
 	select DVB_CX22702
+	select DVB_LGDT3302
 	---help---
 	  This adds support for DVB/ATSC cards based on the
 	  Connexant 2388x chip.
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index b3fb043..b0b47c3 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-cards.c,v 1.76 2005/06/08 01:28:09 mchehab Exp $
+ * $Id: cx88-cards.c,v 1.85 2005/07/04 19:35:05 mkrufky Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * card-specific stuff.
@@ -401,7 +401,7 @@
 		.dvb            = 1,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
-		.name           = "DVICO FusionHDTV DVB-T1",
+		.name           = "DViCO FusionHDTV DVB-T1",
 		.tuner_type     = TUNER_ABSENT, /* No analog tuner */
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -445,8 +445,8 @@
                         .gpio0  = 0x000007f8,
                 },
 	},
-	[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD] = {
-		.name		= "DViCO - FusionHDTV 3 Gold",
+	[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
+		.name		= "DViCO FusionHDTV 3 Gold-Q",
 		.tuner_type     = TUNER_MICROTUNE_4042FI5,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -464,6 +464,9 @@
 		   GPIO[3] selects RF input connector on tuner module
 		    0 - RF connector labeled CABLE
 		    1 - RF connector labeled ANT
+		   GPIO[4] selects high RF for QAM256 mode
+		    0 - normal RF
+		    1 - high RF
 		*/
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
@@ -482,6 +485,7 @@
 			.vmux   = 2,
 			.gpio0	= 0x0f00,
 		}},
+		.dvb            = 1,
 	},
         [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
 		.name           = "Hauppauge Nova-T DVB-T",
@@ -520,7 +524,7 @@
 		.blackbird = 1,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
-		.name           = "DVICO FusionHDTV DVB-T Plus",
+		.name           = "DViCO FusionHDTV DVB-T Plus",
 		.tuner_type     = TUNER_ABSENT, /* No analog tuner */
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -700,21 +704,17 @@
 		 },
 	},
         [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
-                .name           = "DViCO - FusionHDTV 3 Gold-T",
+		.name           = "DViCO FusionHDTV 3 Gold-T",
 		.tuner_type     = TUNER_THOMSON_DTT7611,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		/*  See DViCO FusionHDTV 3 Gold for GPIO documentation.  */
-                .input          = {{
+		/*  See DViCO FusionHDTV 3 Gold-Q for GPIO documentation.  */
+		.input          = {{
                         .type   = CX88_VMUX_TELEVISION,
                         .vmux   = 0,
                         .gpio0  = 0x0f0d,
                 },{
-                        .type   = CX88_VMUX_CABLE,
-                        .vmux   = 0,
-                        .gpio0  = 0x0f05,
-                },{
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
                         .gpio0  = 0x0f00,
@@ -723,7 +723,36 @@
                         .vmux   = 2,
                         .gpio0  = 0x0f00,
                 }},
+		.dvb            = 1,
         },
+        [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+                .name           = "ADS Tech Instant TV DVB-T PCI",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+                        .type   = CX88_VMUX_COMPOSITE1,
+                        .vmux   = 1,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+                },{
+                        .type   = CX88_VMUX_SVIDEO,
+                        .vmux   = 2,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+                }},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
+		.name           = "TerraTec Cinergy 1400 DVB-T",
+		.tuner_type     = TUNER_ABSENT,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		}},
+		.dvb            = 1,
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -794,7 +823,7 @@
 	},{
 		.subvendor = 0x18ac,
 		.subdevice = 0xd810,
-		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
 	},{
 		.subvendor = 0x18ac,
 		.subdevice = 0xd820,
@@ -843,7 +872,15 @@
 		.subvendor = 0x10fc,
 		.subdevice = 0xd035,
 		.card      = CX88_BOARD_IODATA_GVBCTV7E,
-	}
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0334,
+		.card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
+ 	},{
+		.subvendor = 0x153b,
+		.subdevice = 0x1166,
+		.card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
+	},
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
 
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index c046a23..96cb0ff 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-core.c,v 1.28 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88-core.c,v 1.31 2005/06/22 22:58:04 mchehab Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * driver core
@@ -545,12 +545,14 @@
 	       core->name,cx_read(ch->cnt2_reg));
 }
 
+/* Used only on cx88-core */
 static char *cx88_pci_irqs[32] = {
 	"vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
 	"src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
 	"brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
 	"i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
 };
+/* Used only on cx88-video */
 char *cx88_vid_irqs[32] = {
 	"y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
 	"y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
@@ -558,6 +560,7 @@
 	"y_sync",   "u_sync",   "v_sync",   "vbi_sync",
 	"opc_err",  "par_err",  "rip_err",  "pci_abort",
 };
+/* Used only on cx88-mpeg */
 char *cx88_mpeg_irqs[32] = {
 	"ts_risci1", NULL, NULL, NULL,
 	"ts_risci2", NULL, NULL, NULL,
@@ -1006,21 +1009,7 @@
 	set_tvaudio(core);
 
 	// tell i2c chips
-#ifdef V4L2_I2C_CLIENTS
 	cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
-#else
-	{
-		struct video_channel c;
-		memset(&c,0,sizeof(c));
-		c.channel = core->input;
-		c.norm = VIDEO_MODE_PAL;
-		if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
-			c.norm = VIDEO_MODE_NTSC;
-		if (norm->id & V4L2_STD_SECAM)
-			c.norm = VIDEO_MODE_SECAM;
-		cx88_call_i2c_clients(core,VIDIOCSCHAN,&c);
-	}
-#endif
 
 	// done
 	return 0;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 1a259c3..690477a 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-dvb.c,v 1.33 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88-dvb.c,v 1.39 2005/07/02 20:00:46 mkrufky Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * MPEG Transport Stream (DVB) routines
@@ -30,9 +30,10 @@
 #include <linux/file.h>
 #include <linux/suspend.h>
 
-/* those two frontends need merging via linuxtv cvs ... */
+/* these three frontends need merging via linuxtv cvs ... */
 #define HAVE_CX22702 1
 #define HAVE_OR51132 1
+#define HAVE_LGDT3302 1
 
 #include "cx88.h"
 #include "dvb-pll.h"
@@ -44,6 +45,9 @@
 #if HAVE_OR51132
 # include "or51132.h"
 #endif
+#if HAVE_LGDT3302
+# include "lgdt3302.h"
+#endif
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -199,6 +203,32 @@
 };
 #endif
 
+#if HAVE_LGDT3302
+static int lgdt3302_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	if (is_punctured)
+		dev->ts_gen_cntrl |= 0x04;
+	else
+		dev->ts_gen_cntrl &= ~0x04;
+	return 0;
+}
+
+static struct lgdt3302_config fusionhdtv_3_gold_q = {
+	.demod_address    = 0x0e,
+	.pll_address      = 0x61,
+	.pll_desc         = &dvb_pll_microtune_4042,
+	.set_ts_params    = lgdt3302_set_ts_param,
+};
+
+static struct lgdt3302_config fusionhdtv_3_gold_t = {
+	.demod_address    = 0x0e,
+	.pll_address      = 0x61,
+	.pll_desc         = &dvb_pll_thomson_dtt7611,
+	.set_ts_params    = lgdt3302_set_ts_param,
+};
+#endif
+
 static int dvb_register(struct cx8802_dev *dev)
 {
 	/* init struct videobuf_dvb */
@@ -212,6 +242,7 @@
 		dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
 						   &dev->core->i2c_adap);
 		break;
+	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
 	case CX88_BOARD_CONEXANT_DVB_T1:
 		dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
 						   &dev->core->i2c_adap);
@@ -231,6 +262,7 @@
 		break;
 	case CX88_BOARD_KWORLD_DVB_T:
 	case CX88_BOARD_DNTV_LIVE_DVB_T:
+	case CX88_BOARD_ADSTECH_DVB_T_PCI:
 		dev->core->pll_addr = 0x61;
 		dev->core->pll_desc = &dvb_pll_unknown_1;
 		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
@@ -242,6 +274,36 @@
 						 &dev->core->i2c_adap);
 		break;
 #endif
+#if HAVE_LGDT3302
+	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+		dev->ts_gen_cntrl = 0x08;
+		{
+		/* Do a hardware reset of chip before using it. */
+		struct cx88_core *core = dev->core;
+
+		cx_clear(MO_GP0_IO, 1);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 9); // ANT connector too FIXME
+		mdelay(200);
+		dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_q,
+						    &dev->core->i2c_adap);
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
+		dev->ts_gen_cntrl = 0x08;
+		{
+		/* Do a hardware reset of chip before using it. */
+		struct cx88_core *core = dev->core;
+
+		cx_clear(MO_GP0_IO, 1);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 9); /* ANT connector too FIXME */
+		mdelay(200);
+		dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_t,
+						    &dev->core->i2c_adap);
+		}
+		break;
+#endif
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index e20adef..b534223 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-i2c.c,v 1.23 2005/06/12 04:19:19 mchehab Exp $
+    $Id: cx88-i2c.c,v 1.24 2005/06/17 18:46:23 mkrufky Exp $
 
     cx88-i2c.c  --  all the i2c code is here
 
@@ -157,6 +157,7 @@
 };
 
 static char *i2c_devs[128] = {
+	[ 0x1c >> 1 ] = "lgdt3302",
 	[ 0x86 >> 1 ] = "tda9887/cx22702",
 	[ 0xa0 >> 1 ] = "eeprom",
 	[ 0xc0 >> 1 ] = "tuner (analog)",
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index dc0dcf2..bdc26e7 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-input.c,v 1.11 2005/05/22 20:57:56 nsh Exp $
+ * $Id: cx88-input.c,v 1.13 2005/06/13 16:07:46 nsh Exp $
  *
  * Device driver for GPIO attached remote control interfaces
  * on Conexant 2388x based TV/DVB cards.
@@ -125,6 +125,86 @@
 
 /* ---------------------------------------------------------------------- */
 
+/* ADS Tech Instant TV DVB-T PCI Remote */
+static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
+	[ 0x5b ] = KEY_POWER,
+	[ 0x5f ] = KEY_MUTE,
+	[ 0x57 ] = KEY_1,
+	[ 0x4f ] = KEY_2,
+	[ 0x53 ] = KEY_3,
+	[ 0x56 ] = KEY_4,
+	[ 0x4e ] = KEY_5,
+	[ 0x5e ] = KEY_6,
+	[ 0x54 ] = KEY_7,
+	[ 0x4c ] = KEY_8,
+	[ 0x5c ] = KEY_9,
+	[ 0x4d ] = KEY_0,
+	[ 0x55 ] = KEY_GOTO,
+	[ 0x5d ] = KEY_SEARCH,
+	[ 0x17 ] = KEY_EPG,             // Guide
+	[ 0x1f ] = KEY_MENU,
+	[ 0x0f ] = KEY_UP,
+	[ 0x46 ] = KEY_DOWN,
+	[ 0x16 ] = KEY_LEFT,
+	[ 0x1e ] = KEY_RIGHT,
+	[ 0x0e ] = KEY_SELECT,          // Enter
+	[ 0x5a ] = KEY_INFO,
+	[ 0x52 ] = KEY_EXIT,
+	[ 0x59 ] = KEY_PREVIOUS,
+	[ 0x51 ] = KEY_NEXT,
+	[ 0x58 ] = KEY_REWIND,
+	[ 0x50 ] = KEY_FORWARD,
+	[ 0x44 ] = KEY_PLAYPAUSE,
+	[ 0x07 ] = KEY_STOP,
+	[ 0x1b ] = KEY_RECORD,
+	[ 0x13 ] = KEY_TUNER,           // Live
+	[ 0x0a ] = KEY_A,
+	[ 0x12 ] = KEY_B,
+	[ 0x03 ] = KEY_PROG1,           // 1
+	[ 0x01 ] = KEY_PROG2,           // 2
+	[ 0x00 ] = KEY_PROG3,           // 3
+	[ 0x06 ] = KEY_DVD,
+	[ 0x48 ] = KEY_AUX,             // Photo
+	[ 0x40 ] = KEY_VIDEO,
+	[ 0x19 ] = KEY_AUDIO,           // Music
+	[ 0x0b ] = KEY_CHANNELUP,
+	[ 0x08 ] = KEY_CHANNELDOWN,
+	[ 0x15 ] = KEY_VOLUMEUP,
+	[ 0x1c ] = KEY_VOLUMEDOWN,
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* MSI TV@nywhere remote */
+static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
+       [ 0x00 ] = KEY_0,           /* '0' */
+       [ 0x01 ] = KEY_1,           /* '1' */
+       [ 0x02 ] = KEY_2,           /* '2' */
+       [ 0x03 ] = KEY_3,           /* '3' */
+       [ 0x04 ] = KEY_4,           /* '4' */
+       [ 0x05 ] = KEY_5,           /* '5' */
+       [ 0x06 ] = KEY_6,           /* '6' */
+       [ 0x07 ] = KEY_7,           /* '7' */
+       [ 0x08 ] = KEY_8,           /* '8' */
+       [ 0x09 ] = KEY_9,           /* '9' */
+       [ 0x0c ] = KEY_MUTE,        /* 'Mute' */
+       [ 0x0f ] = KEY_SCREEN,      /* 'Full Screen' */
+       [ 0x10 ] = KEY_F,           /* 'Funtion' */
+       [ 0x11 ] = KEY_T,           /* 'Time shift' */
+       [ 0x12 ] = KEY_POWER,       /* 'Power' */
+       [ 0x13 ] = KEY_MEDIA,       /* 'MTS' */
+       [ 0x14 ] = KEY_SLOW,        /* 'Slow' */
+       [ 0x16 ] = KEY_REWIND,      /* 'backward <<' */
+       [ 0x17 ] = KEY_ENTER,       /* 'Return' */
+       [ 0x18 ] = KEY_FASTFORWARD, /* 'forward >>' */
+       [ 0x1a ] = KEY_CHANNELUP,   /* 'Channel+' */
+       [ 0x1b ] = KEY_VOLUMEUP,    /* 'Volume+' */
+       [ 0x1e ] = KEY_CHANNELDOWN, /* 'Channel-' */
+       [ 0x1f ] = KEY_VOLUMEDOWN,  /* 'Volume-' */
+};
+
+/* ---------------------------------------------------------------------- */
+
 struct cx88_IR {
 	struct cx88_core	*core;
 	struct input_dev        input;
@@ -269,6 +349,20 @@
 		ir->mask_keyup   = 0x80;
 		ir->polling      = 1; // ms
 		break;
+	case CX88_BOARD_ADSTECH_DVB_T_PCI:
+		ir_codes         = ir_codes_adstech_dvb_t_pci;
+		ir->gpio_addr    = MO_GP1_IO;
+		ir->mask_keycode = 0xbf;
+		ir->mask_keyup   = 0x40;
+		ir->polling      = 50; // ms
+		break;
+        case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+                ir_codes         = ir_codes_msi_tvanywhere;
+                ir->gpio_addr    = MO_GP1_IO;
+                ir->mask_keycode = 0x1f;
+                ir->mask_keyup   = 0x40;
+                ir->polling      = 1;
+                break;
 	}
 
 	if (NULL == ir_codes) {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 9ade2ae..85da6dc 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-mpeg.c,v 1.26 2005/06/03 13:31:51 mchehab Exp $
+ * $Id: cx88-mpeg.c,v 1.30 2005/07/05 19:44:40 mkrufky Exp $
  *
  *  Support for the mpeg transport stream transfers
  *  PCI function #2 of the cx2388x.
@@ -70,11 +70,16 @@
 
 	if (cx88_boards[core->board].dvb) {
 		/* negedge driven & software reset */
-		cx_write(TS_GEN_CNTRL, 0x40);
+		cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
 		udelay(100);
 		cx_write(MO_PINMUX_IO, 0x00);
-		cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00);
-		cx_write(TS_SOP_STAT,0x00);
+		cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
+		if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) ||
+		    (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) {
+			cx_write(TS_SOP_STAT, 0<<16 | 0<<14 | 1<<13 | 0<<12);
+		} else {
+			cx_write(TS_SOP_STAT,0x00);
+		}
 		cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
 		udelay(100);
 	}
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index e4ca735..dc99754 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-video.c,v 1.63 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88-video.c,v 1.70 2005/06/20 03:36:00 mkrufky Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * video4linux video interface
@@ -261,7 +261,7 @@
 			.default_value = 0,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
-		.off                   = 0,
+		.off                   = 128,
 		.reg                   = MO_HUE,
 		.mask                  = 0x00ff,
 		.shift                 = 0,
@@ -1351,9 +1351,6 @@
 			V4L2_CAP_STREAMING     |
 			V4L2_CAP_VBI_CAPTURE   |
 #if 0
-			V4L2_TUNER_CAP_LOW     |
-#endif
-#if 0
 			V4L2_CAP_VIDEO_OVERLAY |
 #endif
 			0;
@@ -1475,7 +1472,7 @@
 			}
 			break;
 		case 1:
-			if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD == core->board) {
+			if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) {
 				strcpy(a->name,"Line In");
 				a->capability = V4L2_AUDCAP_STEREO;
 				return 0;
@@ -1588,11 +1585,11 @@
 	{
 		struct v4l2_frequency *f = arg;
 
+		memset(f,0,sizeof(*f));
+
 		if (UNSET == core->tuner_type)
 			return -EINVAL;
-		if (f->tuner != 0)
-			return -EINVAL;
-		memset(f,0,sizeof(*f));
+
 		f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 		f->frequency = dev->freq;
 		return 0;
@@ -1612,11 +1609,7 @@
 		down(&dev->lock);
 		dev->freq = f->frequency;
 		cx88_newstation(core);
-#ifdef V4L2_I2C_CLIENTS
 		cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f);
-#else
-		cx88_call_i2c_clients(dev->core,VIDIOCSFREQ,&dev->freq);
-#endif
 		up(&dev->lock);
 		return 0;
 	}
@@ -1714,11 +1707,7 @@
 			sizeof(cap->card));
 		sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
 		cap->version = CX88_VERSION_CODE;
-		cap->capabilities = V4L2_CAP_TUNER
-#if 0
-				    | V4L2_TUNER_CAP_LOW
-#endif
-				    ;
+		cap->capabilities = V4L2_CAP_TUNER;
 		return 0;
 	}
 	case VIDIOC_G_TUNER:
@@ -1730,19 +1719,8 @@
 
 		memset(t,0,sizeof(*t));
 		strcpy(t->name, "Radio");
-                t->rangelow  = (int)(65*16);
-                t->rangehigh = (int)(108*16);
 
-#ifdef V4L2_I2C_CLIENTS
 		cx88_call_i2c_clients(dev->core,VIDIOC_G_TUNER,t);
-#else
-		{
-			struct video_tuner vt;
-			memset(&vt,0,sizeof(vt));
-			cx88_call_i2c_clients(dev,VIDIOCGTUNER,&vt);
-			t->signal = vt.signal;
-		}
-#endif
 		return 0;
 	}
 	case VIDIOC_ENUMINPUT:
@@ -1775,8 +1753,29 @@
 		*id = 0;
 		return 0;
 	}
-	case VIDIOC_S_AUDIO:
+	case VIDIOCSTUNER:
+	{
+		struct video_tuner *v = arg;
+
+		if (v->tuner) /* Only tuner 0 */
+			return -EINVAL;
+
+		cx88_call_i2c_clients(dev->core,VIDIOCSTUNER,v);
+                return 0;
+	}
 	case VIDIOC_S_TUNER:
+	{
+		struct v4l2_tuner *t = arg;
+
+		if (0 != t->index)
+			return -EINVAL;
+
+		cx88_call_i2c_clients(dev->core,VIDIOC_S_TUNER,t);
+
+		return 0;
+	}
+
+	case VIDIOC_S_AUDIO:
 	case VIDIOC_S_INPUT:
 	case VIDIOC_S_STD:
 		return 0;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 867e988..bc5e038 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88.h,v 1.62 2005/06/12 04:19:19 mchehab Exp $
+ * $Id: cx88.h,v 1.67 2005/07/01 12:10:07 mkrufky Exp $
  *
  * v4l2 device driver for cx2388x based TV cards
  *
@@ -51,8 +51,6 @@
 /* ----------------------------------------------------------- */
 /* defines and enums                                           */
 
-#define V4L2_I2C_CLIENTS 1
-
 #define FORMAT_FLAGS_PACKED       0x01
 #define FORMAT_FLAGS_PLANAR       0x02
 
@@ -159,7 +157,7 @@
 #define CX88_BOARD_KWORLD_DVB_T            14
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
 #define CX88_BOARD_KWORLD_LTV883           16
-#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD 17
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q  17
 #define CX88_BOARD_HAUPPAUGE_DVB_T1        18
 #define CX88_BOARD_CONEXANT_DVB_T1         19
 #define CX88_BOARD_PROVIDEO_PV259          20
@@ -167,10 +165,12 @@
 #define CX88_BOARD_PCHDTV_HD3000           22
 #define CX88_BOARD_DNTV_LIVE_DVB_T         23
 #define CX88_BOARD_HAUPPAUGE_ROSLYN        24
-#define CX88_BOARD_DIGITALLOGIC_MEC	       25
+#define CX88_BOARD_DIGITALLOGIC_MEC        25
 #define CX88_BOARD_IODATA_GVBCTV7E         26
 #define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
 #define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T  28
+#define CX88_BOARD_ADSTECH_DVB_T_PCI          29
+#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1  30
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 8b62327..ffbe6f4 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1363,19 +1363,7 @@
 	u32 device_state;
 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 
-	switch(state)
-	{
-		case 1: /* S1 */
-			device_state=1; /* D1 */;
-			break;
-		case 3: /* S3 */
-		case 4: /* S4 */
-			device_state=3; /* D3 */;
-			break;
-		default:
-			return -EAGAIN /*FIXME*/;
-			break;
-	}
+	device_state=pci_choose_state(pdev, state);
 
 	printk(MYIOC_s_INFO_FMT
 	"pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 5ea89bf..debb8ac 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -84,7 +84,7 @@
 extern void mptscsih_remove(struct pci_dev *);
 extern void mptscsih_shutdown(struct pci_dev *);
 #ifdef CONFIG_PM
-extern int mptscsih_suspend(struct pci_dev *pdev, u32 state);
+extern int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
 extern int mptscsih_resume(struct pci_dev *pdev);
 #endif
 extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c
index d026760..fe2e7af 100644
--- a/drivers/message/i2o/config-osm.c
+++ b/drivers/message/i2o/config-osm.c
@@ -15,7 +15,9 @@
 
 #include <linux/module.h>
 #include <linux/i2o.h>
+#include <linux/dcache.h>
 #include <linux/namei.h>
+#include <linux/fs.h>
 
 #include <asm/uaccess.h>
 
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index c2655a8..ff7c50d 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -18,7 +18,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -800,11 +799,6 @@
 
 	/* Register with Card Services */
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &pcmciamtd_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	DEBUG(2, "Calling RegisterClient");
@@ -850,6 +844,7 @@
 		.name	= "pcmciamtd"
 	},
 	.attach		= pcmciamtd_attach,
+	.event		= pcmciamtd_event,
 	.detach		= pcmciamtd_detach,
 	.owner		= THIS_MODULE,
 	.id_table	= pcmciamtd_ids,
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 00e5257..8dc657f 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1261,7 +1261,7 @@
 	spin_unlock_irqrestore(&bp->lock, flags);
 }
 
-static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_match *match)
+static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	int j, rev, ret;
 	struct bmac_data *bp;
@@ -1645,16 +1645,13 @@
 	return 0;
 }
 
-static struct of_match bmac_match[] = 
+static struct of_device_id bmac_match[] = 
 {
 	{
 	.name 		= "bmac",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH,
 	.data		= (void *)0,
 	},
 	{
-	.name 		= OF_ANY_MATCH,
 	.type		= "network",
 	.compatible	= "bmac+",
 	.data		= (void *)1,
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index ece1b1a..c27e417 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -304,7 +304,7 @@
 		scc->tx_buff = NULL;
 	}
 	
-	while (skb_queue_len(&scc->tx_queue))
+	while (!skb_queue_empty(&scc->tx_queue))
 		dev_kfree_skb(skb_dequeue(&scc->tx_queue));
 
 	spin_unlock_irqrestore(&scc->lock, flags);
@@ -1126,8 +1126,7 @@
 	
 	if (scc->stat.tx_state == TXS_WAIT)	/* maxkeyup or idle timeout */
 	{
-		if (skb_queue_len(&scc->tx_queue) == 0)	/* nothing to send */
-		{
+		if (skb_queue_empty(&scc->tx_queue)) {	/* nothing to send */
 			scc->stat.tx_state = TXS_IDLE;
 			netif_wake_queue(scc->dev);	/* t_maxkeyup locked it. */
 			return;
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 6ed2d7d..81d0a26 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -109,7 +109,7 @@
 }
 
 
-static int __devinit mace_probe(struct macio_dev *mdev, const struct of_match *match)
+static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	struct device_node *mace = macio_get_of_node(mdev);
 	struct net_device *dev;
@@ -1009,12 +1009,10 @@
     return IRQ_HANDLED;
 }
 
-static struct of_match mace_match[] = 
+static struct of_device_id mace_match[] = 
 {
 	{
 	.name 		= "mace",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{},
 };
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index f0fc04bd..71fd411 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -86,7 +86,6 @@
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -312,11 +311,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-			CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-				CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &tc574_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1299,6 +1293,7 @@
 		.name	= "3c574_cs",
 	},
 	.attach		= tc574_attach,
+	.event		= tc574_event,
 	.detach		= tc574_detach,
 	.id_table       = tc574_ids,
 };
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 8fa1b5f..d83fdd8 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -40,7 +40,6 @@
 #include <linux/ioport.h>
 #include <linux/bitops.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -226,11 +225,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &tc589_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1074,6 +1068,7 @@
 		.name	= "3c589_cs",
 	},
 	.attach		= tc589_attach,
+	.event		= tc589_event,
 	.detach		= tc589_detach,
         .id_table       = tc589_ids,
 };
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 23ce77b..8bb4e85 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -37,7 +37,6 @@
 #include <linux/netdevice.h>
 #include "../8390.h"
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -181,11 +180,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &axnet_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -884,6 +878,7 @@
 		.name	= "axnet_cs",
 	},
 	.attach		= axnet_attach,
+	.event		= axnet_event,
 	.detach		= axnet_detach,
 	.id_table       = axnet_ids,
 };
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 68d58cc..b9355d9 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -43,7 +43,6 @@
 #include <linux/arcdevice.h>
 #include <linux/com20020.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -200,11 +199,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &com20020_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -495,6 +489,7 @@
 		.name	= "com20020_cs",
 	},
 	.attach		= com20020_attach,
+	.event		= com20020_event,
 	.detach		= com20020_detach,
 	.id_table	= com20020_ids,
 };
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 917adbb..9d8197b 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -49,7 +49,6 @@
 #include <linux/ioport.h>
 #include <linux/crc32.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -288,11 +287,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &fmvj18x_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -797,6 +791,7 @@
 		.name	= "fmvj18x_cs",
 	},
 	.attach		= fmvj18x_attach,
+	.event		= fmvj18x_event,
 	.detach		= fmvj18x_detach,
 	.id_table       = fmvj18x_ids,
 };
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index cf6d073..b6c140e 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -57,7 +57,6 @@
 #include <linux/trdevice.h>
 #include <linux/ibmtr.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -190,11 +189,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ibmtr_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -521,6 +515,7 @@
 		.name	= "ibmtr_cs",
 	},
 	.attach		= ibmtr_attach,
+	.event		= ibmtr_event,
 	.detach		= ibmtr_detach,
 	.id_table       = ibmtr_ids,
 };
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index b86e725..dbb9410 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -146,7 +146,6 @@
 #include <linux/ioport.h>
 #include <linux/bitops.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cisreg.h>
@@ -502,11 +501,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &nmclan_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1688,6 +1682,7 @@
 		.name	= "nmclan_cs",
 	},
 	.attach		= nmclan_attach,
+	.event		= nmclan_event,
 	.detach		= nmclan_detach,
 	.id_table       = nmclan_ids,
 };
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 855a45d..e1664ae 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -40,7 +40,6 @@
 #include <linux/netdevice.h>
 #include <../drivers/net/8390.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -276,11 +275,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &pcnet_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1844,6 +1838,7 @@
 		.name	= "pcnet_cs",
 	},
 	.attach		= pcnet_attach,
+	.event		= pcnet_event,
 	.detach		= pcnet_detach,
 	.owner		= THIS_MODULE,
 	.id_table	= pcnet_ids,
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index bc01c88..fbc2f58 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -42,7 +42,6 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -370,10 +369,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &smc91c92_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2365,6 +2360,7 @@
 		.name	= "smc91c92_cs",
 	},
 	.attach		= smc91c92_attach,
+	.event		= smc91c92_event,
 	.detach		= smc91c92_detach,
 	.id_table       = smc91c92_ids,
 };
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 0cd225e..9f33bad 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -81,7 +81,6 @@
 #include <linux/ioport.h>
 #include <linux/bitops.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -619,11 +618,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &xirc2ps_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     if ((err = pcmcia_register_client(&link->handle, &client_reg))) {
@@ -2016,6 +2010,7 @@
 		.name	= "xirc2ps_cs",
 	},
 	.attach		= xirc2ps_attach,
+	.event		= xirc2ps_event,
 	.detach		= xirc2ps_detach,
 	.id_table       = xirc2ps_ids,
 };
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 5e48b9a..59e8183 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -364,7 +364,7 @@
 	spin_lock_irqsave(&ap->recv_lock, flags);
 	ppp_async_input(ap, buf, cflags, count);
 	spin_unlock_irqrestore(&ap->recv_lock, flags);
-	if (skb_queue_len(&ap->rqueue))
+	if (!skb_queue_empty(&ap->rqueue))
 		tasklet_schedule(&ap->tsk);
 	ap_put(ap);
 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index ab726ab..a32668e 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1237,8 +1237,8 @@
 		pch = list_entry(list, struct channel, clist);
 		navail += pch->avail = (pch->chan != NULL);
 		if (pch->avail) {
-			if (skb_queue_len(&pch->file.xq) == 0
-			    || !pch->had_frag) {
+			if (skb_queue_empty(&pch->file.xq) ||
+			    !pch->had_frag) {
 				pch->avail = 2;
 				++nfree;
 			}
@@ -1374,8 +1374,8 @@
 
 		/* try to send it down the channel */
 		chan = pch->chan;
-		if (skb_queue_len(&pch->file.xq)
-		    || !chan->ops->start_xmit(chan, frag))
+		if (!skb_queue_empty(&pch->file.xq) ||
+		    !chan->ops->start_xmit(chan, frag))
 			skb_queue_tail(&pch->file.xq, frag);
 		pch->had_frag = 1;
 		p += flen;
@@ -1412,7 +1412,7 @@
 
 	spin_lock_bh(&pch->downl);
 	if (pch->chan != 0) {
-		while (skb_queue_len(&pch->file.xq) > 0) {
+		while (!skb_queue_empty(&pch->file.xq)) {
 			skb = skb_dequeue(&pch->file.xq);
 			if (!pch->chan->ops->start_xmit(pch->chan, skb)) {
 				/* put the packet back and try again later */
@@ -1426,7 +1426,7 @@
 	}
 	spin_unlock_bh(&pch->downl);
 	/* see if there is anything from the attached unit to be sent */
-	if (skb_queue_len(&pch->file.xq) == 0) {
+	if (skb_queue_empty(&pch->file.xq)) {
 		read_lock_bh(&pch->upl);
 		ppp = pch->ppp;
 		if (ppp != 0)
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index fd9f501..4d51c0c 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -406,7 +406,7 @@
 	spin_lock_irqsave(&ap->recv_lock, flags);
 	ppp_sync_input(ap, buf, cflags, count);
 	spin_unlock_irqrestore(&ap->recv_lock, flags);
-	if (skb_queue_len(&ap->rqueue))
+	if (!skb_queue_empty(&ap->rqueue))
 		tasklet_schedule(&ap->tsk);
 	sp_put(ap);
 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 3dbb1cb..5cacc7a 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3259,7 +3259,7 @@
 }
 
 #ifdef CONFIG_PM
-static int skge_suspend(struct pci_dev *pdev, u32 state)
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct skge_hw *hw  = pci_get_drvdata(pdev);
 	int i, wol = 0;
@@ -3279,7 +3279,7 @@
 	}
 
 	pci_save_state(pdev);
-	pci_enable_wake(pdev, state, wol);
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 1f56556..2608e7a 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -3079,7 +3079,9 @@
 	gp->phy_mii.dev = dev;
 	gp->phy_mii.mdio_read = _phy_read;
 	gp->phy_mii.mdio_write = _phy_write;
-
+#ifdef CONFIG_PPC_PMAC
+	gp->phy_mii.platform_data = gp->of_node;
+#endif
 	/* By default, we start with autoneg */
 	gp->want_autoneg = 1;
 
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 0fca414..d3ddb41 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -32,6 +32,10 @@
 #include <linux/ethtool.h>
 #include <linux/delay.h>
 
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#endif
+
 #include "sungem_phy.h"
 
 /* Link modes of the BCM5400 PHY */
@@ -281,10 +285,12 @@
 static int bcm5421_init(struct mii_phy* phy)
 {
 	u16 data;
-	int rev;
+	unsigned int id;
 
-	rev = phy_read(phy, MII_PHYSID2) & 0x000f;
-	if (rev == 0) {
+	id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+
+	/* Revision 0 of 5421 needs some fixups */
+	if (id == 0x002060e0) {
 		/* This is borrowed from MacOS
 		 */
 		phy_write(phy, 0x18, 0x1007);
@@ -297,21 +303,28 @@
 		data = phy_read(phy, 0x15);
 		phy_write(phy, 0x15, data | 0x0200);
 	}
-#if 0
-	/* This has to be verified before I enable it */
-	/* Enable automatic low-power */
-	phy_write(phy, 0x1c, 0x9002);
-	phy_write(phy, 0x1c, 0xa821);
-	phy_write(phy, 0x1c, 0x941d);
-#endif
-	return 0;
-}
 
-static int bcm5421k2_init(struct mii_phy* phy)
-{
-	/* Init code borrowed from OF */
-	phy_write(phy, 4, 0x01e1);
-	phy_write(phy, 9, 0x0300);
+	/* Pick up some init code from OF for K2 version */
+	if ((id & 0xfffffff0) == 0x002062e0) {
+		phy_write(phy, 4, 0x01e1);
+		phy_write(phy, 9, 0x0300);
+	}
+
+	/* Check if we can enable automatic low power */
+#ifdef CONFIG_PPC_PMAC
+	if (phy->platform_data) {
+		struct device_node *np = of_get_parent(phy->platform_data);
+		int can_low_power = 1;
+		if (np == NULL || get_property(np, "no-autolowpower", NULL))
+			can_low_power = 0;
+		if (can_low_power) {
+			/* Enable automatic low-power */
+			phy_write(phy, 0x1c, 0x9002);
+			phy_write(phy, 0x1c, 0xa821);
+			phy_write(phy, 0x1c, 0x941d);
+		}
+	}
+#endif /* CONFIG_PPC_PMAC */
 
 	return 0;
 }
@@ -762,7 +775,7 @@
 
 /* Broadcom BCM 5421 built-in K2 */
 static struct mii_phy_ops bcm5421k2_phy_ops = {
-	.init		= bcm5421k2_init,
+	.init		= bcm5421_init,
 	.suspend	= bcm5411_suspend,
 	.setup_aneg	= bcm54xx_setup_aneg,
 	.setup_forced	= bcm54xx_setup_forced,
@@ -779,6 +792,25 @@
 	.ops		= &bcm5421k2_phy_ops
 };
 
+/* Broadcom BCM 5462 built-in Vesta */
+static struct mii_phy_ops bcm5462V_phy_ops = {
+	.init		= bcm5421_init,
+	.suspend	= bcm5411_suspend,
+	.setup_aneg	= bcm54xx_setup_aneg,
+	.setup_forced	= bcm54xx_setup_forced,
+	.poll_link	= genmii_poll_link,
+	.read_link	= bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5462V_phy_def = {
+	.phy_id		= 0x002060d0,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "BCM5462-Vesta",
+	.features	= MII_GBIT_FEATURES,
+	.magic_aneg	= 1,
+	.ops		= &bcm5462V_phy_ops
+};
+
 /* Marvell 88E1101 (Apple seem to deal with 2 different revs,
  * I masked out the 8 last bits to get both, but some specs
  * would be useful here) --BenH.
@@ -824,6 +856,7 @@
 	&bcm5411_phy_def,
 	&bcm5421_phy_def,
 	&bcm5421k2_phy_def,
+	&bcm5462V_phy_def,
 	&marvell_phy_def,
 	&genmii_phy_def,
 	NULL
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
index 822cb58..4305444 100644
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -43,9 +43,10 @@
 	int			pause;
 
 	/* Provided by host chip */
-	struct net_device*	dev;
+	struct net_device	*dev;
 	int (*mdio_read) (struct net_device *dev, int mii_id, int reg);
 	void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val);
+	void			*platform_data;
 };
 
 /* Pass in a struct mii_phy with dev, mdio_read and mdio_write
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 7bfee36..effab0b 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -215,7 +215,7 @@
 
 	poll_wait(file, &tun->read_wait, wait);
  
-	if (skb_queue_len(&tun->readq))
+	if (!skb_queue_empty(&tun->readq))
 		mask |= POLLIN | POLLRDNORM;
 
 	return mask;
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 0b5ca25..ecfa6f8 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1906,9 +1906,9 @@
 	 */
 	netif_carrier_off(tp->dev);
 
-	pci_enable_wake(tp->pdev, pci_choose_state(pdev, state), 1);
+	pci_enable_wake(tp->pdev, state, 1);
 	pci_disable_device(pdev);
-	return pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	return pci_set_power_state(pdev, state);
 }
 
 static int
@@ -2274,7 +2274,7 @@
 		goto need_resume;
 	}
 
-	if(typhoon_sleep(tp, state, tp->wol_events) < 0) {
+	if(typhoon_sleep(tp, pci_choose_state(pdev, state), tp->wol_events) < 0) {
 		printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
 		goto need_resume;
 	}
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index c12648d..47f3c5d 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -2374,7 +2374,7 @@
 	/*
 	 * Clean out tx queue
 	 */
-	if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) {
+	if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
 		struct sk_buff *skb = NULL;
 		for (;(skb = skb_dequeue(&ai->txq));)
 			dev_kfree_skb(skb);
@@ -3287,7 +3287,7 @@
 				if (status & EV_TXEXC)
 					get_tx_error(apriv, -1);
 				spin_lock_irqsave(&apriv->aux_lock, flags);
-				if (skb_queue_len (&apriv->txq)) {
+				if (!skb_queue_empty(&apriv->txq)) {
 					spin_unlock_irqrestore(&apriv->aux_lock,flags);
 					mpi_send_packet (dev);
 				} else {
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index f10a952..bf25584 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -33,7 +33,6 @@
 #include <linux/timer.h>
 #include <linux/netdevice.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -210,11 +209,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &airo_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -574,6 +568,7 @@
 		.name	= "airo_cs",
 	},
 	.attach		= airo_attach,
+	.event		= airo_event,
 	.detach		= airo_detach,
 	.id_table       = airo_ids,
 };
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index b4f4bd7..9d49670 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -184,7 +184,7 @@
 }
 
 static int
-airport_attach(struct macio_dev *mdev, const struct of_match *match)
+airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	struct orinoco_private *priv;
 	struct net_device *dev;
@@ -266,16 +266,16 @@
 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
 MODULE_LICENSE("Dual MPL/GPL");
 
-static struct of_match airport_match[] = 
+static struct of_device_id airport_match[] = 
 {
 	{
 	.name 		= "radio",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{},
 };
 
+MODULE_DEVICE_TABLE (of, airport_match);
+
 static struct macio_driver airport_driver = 
 {
 	.name 		= DRIVER_NAME,
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 86379d4..ff031a3 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -43,7 +43,6 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -218,11 +217,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &atmel_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -668,12 +662,13 @@
 MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
 
 static struct pcmcia_driver atmel_driver = {
-        .owner          = THIS_MODULE,
-        .drv            = {
-                .name   = "atmel_cs",
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "atmel_cs",
         },
-        .attach         = atmel_attach,
-        .detach         = atmel_detach,
+	.attach         = atmel_attach,
+	.event		= atmel_event,
+	.detach		= atmel_detach,
 	.id_table	= atmel_ids,
 };
 
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index e12bd75..5f507c4 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -62,7 +62,6 @@
 #endif	/* WIRELESS_EXT > 12 */
 #endif
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -491,11 +490,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &netwave_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1680,6 +1674,7 @@
 		.name	= "netwave_cs",
 	},
 	.attach		= netwave_attach,
+	.event		= netwave_event,
 	.detach		= netwave_detach,
 	.id_table       = netwave_ids,
 };
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 597c458..368d2f9 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -31,7 +31,6 @@
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -186,11 +185,6 @@
 	dev_list = link;
 
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &orinoco_cs_event;
 	client_reg.Version = 0x0210; /* FIXME: what does this mean? */
 	client_reg.event_callback_args.client_data = link;
 
@@ -664,6 +658,7 @@
 		.name	= DRIVER_NAME,
 	},
 	.attach		= orinoco_cs_attach,
+	.event		= orinoco_cs_event,
 	.detach		= orinoco_cs_detach,
 	.id_table       = orinoco_cs_ids,
 };
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 31652af..0e0ba61 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -46,7 +46,6 @@
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -393,11 +392,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ray_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
 
@@ -2916,6 +2910,7 @@
 		.name	= "ray_cs",
 	},
 	.attach		= ray_attach,
+	.event		= ray_event,
 	.detach		= ray_detach,
 	.id_table       = ray_ids,
 };
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 89532fd..f6130a5 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -4684,12 +4684,6 @@
 
   /* Register with Card Services */
   client_reg.dev_info = &dev_info;
-  client_reg.EventMask = 
-    CS_EVENT_REGISTRATION_COMPLETE |
-    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-  client_reg.event_handler = &wavelan_event;
   client_reg.Version = 0x0210;
   client_reg.event_callback_args.client_data = link;
 
@@ -4904,6 +4898,7 @@
 		.name	= "wavelan_cs",
 	},
 	.attach		= wavelan_attach,
+	.event		= wavelan_event,
 	.detach		= wavelan_detach,
 	.id_table       = wavelan_ids,
 };
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index ea2ef8d..677ff71 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -452,7 +452,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
-#include <pcmcia/version.h>
 
 /* Wavelan declarations */
 #include "i82593.h"	/* Definitions for the Intel chip */
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e3a9004..dd90212 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -49,7 +49,6 @@
 
 #include <net/iw_handler.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -2005,13 +2004,6 @@
 	link->next		 = wl3501_dev_list;
 	wl3501_dev_list		 = link;
 	client_reg.dev_info	 = &wl3501_dev_info;
-	client_reg.EventMask	 = CS_EVENT_CARD_INSERTION |
-				   CS_EVENT_RESET_PHYSICAL |
-				   CS_EVENT_CARD_RESET |
-				   CS_EVENT_CARD_REMOVAL |
-				   CS_EVENT_PM_SUSPEND |
-				   CS_EVENT_PM_RESUME;
-	client_reg.event_handler = wl3501_event;
 	client_reg.Version	 = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2246,12 +2238,13 @@
 MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
 
 static struct pcmcia_driver wl3501_driver = {
-	.owner          = THIS_MODULE,
-	.drv            = {
-		.name   = "wl3501_cs",
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "wl3501_cs",
 	},
-	.attach         = wl3501_attach,
-	.detach         = wl3501_detach,
+	.attach		= wl3501_attach,
+	.event		= wl3501_event,
+	.detach		= wl3501_detach,
 	.id_table	= wl3501_ids,
 };
 
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index ff45662..24e6aac 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -48,7 +48,6 @@
 #include <linux/parport.h>
 #include <linux/parport_pc.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -133,11 +132,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &parport_event;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -386,6 +380,7 @@
 		.name	= "parport_cs",
 	},
 	.attach		= parport_attach,
+	.event		= parport_event,
 	.detach		= parport_detach,
 	.id_table	= parport_ids,
 
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 1a4d4ca..9c4a39e 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -187,9 +187,10 @@
 
 config HOTPLUG_PCI_SGI
 	tristate "SGI PCI Hotplug Support"
-	depends on HOTPLUG_PCI && IA64_SGI_SN2
+	depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC)
 	help
-	  Say Y here if you have an SGI IA64 Altix system.
+	  Say Y here if you want to use the SGI Altix Hotplug
+	  Driver for PCI devices.
 
 	  When in doubt, say N.
 
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 3e632ff..31a3070 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_HOTPLUG_PCI_SHPC)		+= shpchp.o
 obj-$(CONFIG_HOTPLUG_PCI_RPA)		+= rpaphp.o
 obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR)	+= rpadlpar_io.o
+obj-$(CONFIG_HOTPLUG_PCI_SGI)		+= sgi_hotplug.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o
 
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
new file mode 100644
index 0000000..323041f
--- /dev/null
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -0,0 +1,611 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This work was based on the 2.4/2.6 kernel development by Dick Reigner.
+ * Work to add BIOS PROM support was completed by Mike Habeck.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+
+#include <asm/sn/addrs.h>
+#include <asm/sn/l1.h>
+#include <asm/sn/module.h>
+#include <asm/sn/pcibr_provider.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/types.h>
+
+#include "../pci.h"
+#include "pci_hotplug.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
+MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
+
+#define PCIIO_ASIC_TYPE_TIOCA     4
+#define PCI_SLOT_ALREADY_UP       2     /* slot already up */
+#define PCI_SLOT_ALREADY_DOWN     3     /* slot already down */
+#define PCI_L1_ERR                7     /* L1 console command error */
+#define PCI_EMPTY_33MHZ          15     /* empty 33 MHz bus */
+#define PCI_L1_QSIZE            128     /* our L1 message buffer size */
+#define SN_MAX_HP_SLOTS		 32	/* max number of hotplug slots */
+#define SGI_HOTPLUG_PROM_REV	0x0420  /* Min. required PROM version */
+
+/* internal list head */
+static struct list_head sn_hp_list;
+
+/* hotplug_slot struct's private pointer */
+struct slot {
+	int device_num;
+	struct pci_bus *pci_bus;
+	/* this struct for glue internal only */
+	struct hotplug_slot *hotplug_slot;
+	struct list_head hp_list;
+};
+
+struct pcibr_slot_enable_resp {
+	int resp_sub_errno;
+	char resp_l1_msg[PCI_L1_QSIZE + 1];
+};
+
+struct pcibr_slot_disable_resp {
+	int resp_sub_errno;
+	char resp_l1_msg[PCI_L1_QSIZE + 1];
+};
+
+enum sn_pci_req_e {
+	PCI_REQ_SLOT_ELIGIBLE,
+	PCI_REQ_SLOT_DISABLE
+};
+
+static int enable_slot(struct hotplug_slot *slot);
+static int disable_slot(struct hotplug_slot *slot);
+static int get_power_status(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops sn_hotplug_slot_ops = {
+	.owner                  = THIS_MODULE,
+	.enable_slot            = enable_slot,
+	.disable_slot           = disable_slot,
+	.get_power_status       = get_power_status,
+};
+
+static DECLARE_MUTEX(sn_hotplug_sem);
+
+static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
+{
+	struct pcibus_info *pcibus_info;
+	int bricktype;
+	int bus_num;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
+
+	/* Check to see if this is a valid slot on 'pci_bus' */
+	if (!(pcibus_info->pbi_valid_devices & (1 << device)))
+		return -EPERM;
+
+	bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid);
+	bus_num = pcibus_info->pbi_buscommon.bs_persist_busnum & 0xf;
+
+	/* Do not allow hotplug operations on base I/O cards */
+	if ((bricktype == L1_BRICKTYPE_IX ||  bricktype == L1_BRICKTYPE_IA) &&
+	    (bus_num == 1 && device != 1))
+		return -EPERM;
+
+	return 1;
+}
+
+static int sn_pci_bus_valid(struct pci_bus *pci_bus)
+{
+	struct pcibus_info *pcibus_info;
+	int asic_type;
+	int bricktype;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
+
+	/* Don't register slots hanging off the TIOCA bus */
+	asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
+	if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
+		return -EPERM;
+
+	/* Only register slots in I/O Bricks that support hotplug */
+	bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid);
+	switch (bricktype) {
+	case L1_BRICKTYPE_IX:
+	case L1_BRICKTYPE_PX:
+	case L1_BRICKTYPE_IA:
+	case L1_BRICKTYPE_PA:
+		return 1;
+		break;
+	default:
+		return -EPERM;
+		break;
+	}
+
+	return -EIO;
+}
+
+static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
+				    struct pci_bus *pci_bus, int device)
+{
+	struct pcibus_info *pcibus_info;
+	struct slot *slot;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
+
+	bss_hotplug_slot->private = kcalloc(1, sizeof(struct slot),
+					    GFP_KERNEL);
+	if (!bss_hotplug_slot->private)
+		return -ENOMEM;
+	slot = (struct slot *)bss_hotplug_slot->private;
+
+	bss_hotplug_slot->name = kmalloc(33, GFP_KERNEL);
+	if (!bss_hotplug_slot->name) {
+		kfree(bss_hotplug_slot->private);
+		return -ENOMEM;
+	}
+
+	slot->device_num = device;
+	slot->pci_bus = pci_bus;
+
+	sprintf(bss_hotplug_slot->name, "module_%c%c%c%c%.2d_b_%d_s_%d",
+		'0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
+		'0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
+		'0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
+		MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid),
+		MODULE_GET_BPOS(pcibus_info->pbi_moduleid),
+		((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf,
+		device + 1);
+
+	slot->hotplug_slot = bss_hotplug_slot;
+	list_add(&slot->hp_list, &sn_hp_list);
+
+	return 0;
+}
+
+static struct hotplug_slot * sn_hp_destroy(void)
+{
+	struct slot *slot;
+	struct list_head *list;
+	struct hotplug_slot *bss_hotplug_slot = NULL;
+
+	list_for_each(list, &sn_hp_list) {
+		slot = list_entry(list, struct slot, hp_list);
+		bss_hotplug_slot = slot->hotplug_slot;
+		list_del(&((struct slot *)bss_hotplug_slot->private)->
+			 hp_list);
+		break;
+	}
+	return bss_hotplug_slot;
+}
+
+static void sn_bus_alloc_data(struct pci_dev *dev)
+{
+	struct list_head *node;
+	struct pci_bus *subordinate_bus;
+	struct pci_dev *child;
+
+	sn_pci_fixup_slot(dev);
+
+	/* Recursively sets up the sn_irq_info structs */
+	if (dev->subordinate) {
+		subordinate_bus = dev->subordinate;
+		list_for_each(node, &subordinate_bus->devices) {
+			child = list_entry(node, struct pci_dev, bus_list);
+			sn_bus_alloc_data(child);
+		}
+	}
+}
+
+static void sn_bus_free_data(struct pci_dev *dev)
+{
+	struct list_head *node;
+	struct pci_bus *subordinate_bus;
+	struct pci_dev *child;
+
+	/* Recursively clean up sn_irq_info structs */
+	if (dev->subordinate) {
+		subordinate_bus = dev->subordinate;
+		list_for_each(node, &subordinate_bus->devices) {
+			child = list_entry(node, struct pci_dev, bus_list);
+			sn_bus_free_data(child);
+		}
+	}
+	sn_pci_unfixup_slot(dev);
+}
+
+static u8 sn_power_status_get(struct hotplug_slot *bss_hotplug_slot)
+{
+	struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+	struct pcibus_info *pcibus_info;
+	u8 retval;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+	retval = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
+
+	return retval ? 1 : 0;
+}
+
+static void sn_slot_mark_enable(struct hotplug_slot *bss_hotplug_slot,
+				int device_num)
+{
+	struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+	struct pcibus_info *pcibus_info;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+	pcibus_info->pbi_enabled_devices |= (1 << device_num);
+}
+
+static void sn_slot_mark_disable(struct hotplug_slot *bss_hotplug_slot,
+				 int device_num)
+{
+	struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+	struct pcibus_info *pcibus_info;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+	pcibus_info->pbi_enabled_devices &= ~(1 << device_num);
+}
+
+static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
+			  int device_num)
+{
+	struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+	struct pcibus_info *pcibus_info;
+	struct pcibr_slot_enable_resp resp;
+	int rc;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+
+	/*
+	 * Power-on and initialize the slot in the SN
+	 * PCI infrastructure.
+	 */
+	rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+
+	if (rc == PCI_SLOT_ALREADY_UP) {
+		dev_dbg(slot->pci_bus->self, "is already active\n");
+		return -EPERM;
+	}
+
+	if (rc == PCI_L1_ERR) {
+		dev_dbg(slot->pci_bus->self,
+			"L1 failure %d with message: %s",
+			resp.resp_sub_errno, resp.resp_l1_msg);
+		return -EPERM;
+	}
+
+	if (rc) {
+		dev_dbg(slot->pci_bus->self,
+			"insert failed with error %d sub-error %d\n",
+			rc, resp.resp_sub_errno);
+		return -EIO;
+	}
+
+	sn_slot_mark_enable(bss_hotplug_slot, device_num);
+
+	return 0;
+}
+
+static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
+			   int device_num, int action)
+{
+	struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+	struct pcibus_info *pcibus_info;
+	struct pcibr_slot_disable_resp resp;
+	int rc;
+
+	pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+
+	rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp);
+
+	if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_SLOT_ALREADY_DOWN) {
+		dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n");
+		return -ENODEV;
+	}
+
+	if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_EMPTY_33MHZ) {
+		dev_dbg(slot->pci_bus->self,
+			"Cannot remove last 33MHz card\n");
+		return -EPERM;
+	}
+
+	if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_L1_ERR) {
+		dev_dbg(slot->pci_bus->self,
+			"L1 failure %d with message \n%s\n",
+			resp.resp_sub_errno, resp.resp_l1_msg);
+		return -EPERM;
+	}
+
+	if (action == PCI_REQ_SLOT_ELIGIBLE && rc) {
+		dev_dbg(slot->pci_bus->self,
+			"remove failed with error %d sub-error %d\n",
+			rc, resp.resp_sub_errno);
+		return -EIO;
+	}
+
+	if (action == PCI_REQ_SLOT_ELIGIBLE && !rc)
+		return 0;
+
+	if (action == PCI_REQ_SLOT_DISABLE && !rc) {
+		sn_slot_mark_disable(bss_hotplug_slot, device_num);
+		dev_dbg(slot->pci_bus->self, "remove successful\n");
+		return 0;
+	}
+
+	if (action == PCI_REQ_SLOT_DISABLE && rc) {
+		dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+	struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+	struct pci_bus *new_bus = NULL;
+	struct pci_dev *dev;
+	int func, num_funcs;
+	int new_ppb = 0;
+	int rc;
+
+	/* Serialize the Linux PCI infrastructure */
+	down(&sn_hotplug_sem);
+
+	/*
+	 * Power-on and initialize the slot in the SN
+	 * PCI infrastructure.
+	 */
+	rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+	if (rc) {
+		up(&sn_hotplug_sem);
+		return rc;
+	}
+
+	num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num+1,
+							   PCI_FUNC(0)));
+	if (!num_funcs) {
+		dev_dbg(slot->pci_bus->self, "no device in slot\n");
+		up(&sn_hotplug_sem);
+		return -ENODEV;
+	}
+
+	sn_pci_controller_fixup(pci_domain_nr(slot->pci_bus),
+				slot->pci_bus->number,
+				slot->pci_bus);
+	/*
+	 * Map SN resources for all functions on the card
+	 * to the Linux PCI interface and tell the drivers
+	 * about them.
+	 */
+	for (func = 0; func < num_funcs;  func++) {
+		dev = pci_get_slot(slot->pci_bus,
+				   PCI_DEVFN(slot->device_num + 1,
+					     PCI_FUNC(func)));
+
+
+		if (dev) {
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+				unsigned char sec_bus;
+				pci_read_config_byte(dev, PCI_SECONDARY_BUS,
+						     &sec_bus);
+				new_bus = pci_add_new_bus(dev->bus, dev,
+							  sec_bus);
+				pci_scan_child_bus(new_bus);
+				sn_pci_controller_fixup(pci_domain_nr(new_bus),
+							new_bus->number,
+							new_bus);
+				new_ppb = 1;
+			}
+			sn_bus_alloc_data(dev);
+			pci_dev_put(dev);
+		}
+	}
+
+	/* Call the driver for the new device */
+	pci_bus_add_devices(slot->pci_bus);
+	/* Call the drivers for the new devices subordinate to PPB */
+	if (new_ppb)
+		pci_bus_add_devices(new_bus);
+
+	up(&sn_hotplug_sem);
+
+	if (rc == 0)
+		dev_dbg(slot->pci_bus->self,
+			"insert operation successful\n");
+	else
+		dev_dbg(slot->pci_bus->self,
+			"insert operation failed rc = %d\n", rc);
+
+	return rc;
+}
+
+static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+	struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+	struct pci_dev *dev;
+	int func;
+	int rc;
+
+	/* Acquire update access to the bus */
+	down(&sn_hotplug_sem);
+
+	/* is it okay to bring this slot down? */
+	rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
+			     PCI_REQ_SLOT_ELIGIBLE);
+	if (rc)
+		goto leaving;
+
+	/* Free the SN resources assigned to the Linux device.*/
+	for (func = 0; func < 8;  func++) {
+		dev = pci_get_slot(slot->pci_bus,
+				   PCI_DEVFN(slot->device_num+1,
+				   	     PCI_FUNC(func)));
+		if (dev) {
+			/*
+			 * Some drivers may use dma accesses during the
+			 * driver remove function. We release the sysdata
+			 * areas after the driver remove functions have
+			 * been called.
+			 */
+			sn_bus_store_sysdata(dev);
+			sn_bus_free_data(dev);
+			pci_remove_bus_device(dev);
+			pci_dev_put(dev);
+		}
+	}
+
+	/* free the collected sysdata pointers */
+	sn_bus_free_sysdata();
+
+	/* Deactivate slot */
+	rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
+			     PCI_REQ_SLOT_DISABLE);
+ leaving:
+	/* Release the bus lock */
+	up(&sn_hotplug_sem);
+
+	return rc;
+}
+
+static int get_power_status(struct hotplug_slot *bss_hotplug_slot, u8 *value)
+{
+	down(&sn_hotplug_sem);
+	*value = sn_power_status_get(bss_hotplug_slot);
+	up(&sn_hotplug_sem);
+	return 0;
+}
+
+static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+	kfree(bss_hotplug_slot->info);
+	kfree(bss_hotplug_slot->name);
+	kfree(bss_hotplug_slot->private);
+	kfree(bss_hotplug_slot);
+}
+
+static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
+{
+	int device;
+	struct hotplug_slot *bss_hotplug_slot;
+	int rc = 0;
+
+	/*
+	 * Currently only four devices are supported,
+	 * in the future there maybe more -- up to 32.
+	 */
+
+	for (device = 0; device < SN_MAX_HP_SLOTS ; device++) {
+		if (sn_pci_slot_valid(pci_bus, device) != 1)
+			continue;
+
+		bss_hotplug_slot = kcalloc(1,sizeof(struct hotplug_slot),
+					   GFP_KERNEL);
+		if (!bss_hotplug_slot) {
+			rc = -ENOMEM;
+			goto alloc_err;
+		}
+
+		bss_hotplug_slot->info =
+			kcalloc(1,sizeof(struct hotplug_slot_info),
+				GFP_KERNEL);
+		if (!bss_hotplug_slot->info) {
+			rc = -ENOMEM;
+			goto alloc_err;
+		}
+
+		if (sn_hp_slot_private_alloc(bss_hotplug_slot,
+					     pci_bus, device)) {
+			rc = -ENOMEM;
+			goto alloc_err;
+		}
+
+		bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
+		bss_hotplug_slot->release = &sn_release_slot;
+
+		rc = pci_hp_register(bss_hotplug_slot);
+		if (rc)
+			goto register_err;
+	}
+	dev_dbg(pci_bus->self, "Registered bus with hotplug\n");
+	return rc;
+
+register_err:
+	dev_dbg(pci_bus->self, "bus failed to register with err = %d\n",
+	        rc);
+
+alloc_err:
+	if (rc == -ENOMEM)
+		dev_dbg(pci_bus->self, "Memory allocation error\n");
+
+	/* destroy THIS element */
+	if (bss_hotplug_slot)
+		sn_release_slot(bss_hotplug_slot);
+
+	/* destroy anything else on the list */
+	while ((bss_hotplug_slot = sn_hp_destroy()))
+		pci_hp_deregister(bss_hotplug_slot);
+
+	return rc;
+}
+
+static int sn_pci_hotplug_init(void)
+{
+	struct pci_bus *pci_bus = NULL;
+	int rc;
+	int registered = 0;
+
+	INIT_LIST_HEAD(&sn_hp_list);
+
+	if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) {
+		printk(KERN_ERR "%s: PROM version must be greater than 4.05\n",
+		       __FUNCTION__);
+		return -EPERM;
+	}
+
+	while ((pci_bus = pci_find_next_bus(pci_bus))) {
+		if (!pci_bus->sysdata)
+			continue;
+
+		rc = sn_pci_bus_valid(pci_bus);
+		if (rc != 1) {
+			dev_dbg(pci_bus->self, "not a valid hotplug bus\n");
+			continue;
+		}
+		dev_dbg(pci_bus->self, "valid hotplug bus\n");
+
+		rc = sn_hotplug_slot_register(pci_bus);
+		if (!rc)
+			registered = 1;
+		else {
+			registered = 0;
+			break;
+		}
+	}
+
+	return registered == 1 ? 0 : -ENODEV;
+}
+
+static void sn_pci_hotplug_exit(void)
+{
+	struct hotplug_slot *bss_hotplug_slot;
+
+	while ((bss_hotplug_slot = sn_hp_destroy())) {
+		pci_hp_deregister(bss_hotplug_slot);
+	}
+
+	if (!list_empty(&sn_hp_list))
+		printk(KERN_ERR "%s: internal list is not empty\n", __FILE__);
+}
+
+module_init(sn_pci_hotplug_init);
+module_exit(sn_pci_hotplug_exit);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index aac6de9..e4115a0 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -17,13 +17,13 @@
  * Dynamic device IDs are disabled for !CONFIG_HOTPLUG
  */
 
-#ifdef CONFIG_HOTPLUG
-
 struct pci_dynid {
 	struct list_head node;
 	struct pci_device_id id;
 };
 
+#ifdef CONFIG_HOTPLUG
+
 /**
  * store_new_id
  *
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 4db6998..393e0ce 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -325,7 +325,7 @@
 static int suspend_iter(struct device *dev, void *data)
 {
 	struct pcie_port_service_driver *service_driver;
-	u32 state = (u32)data;
+	pm_message_t state = * (pm_message_t *) data;
 
  	if ((dev->bus == &pcie_port_bus_type) &&
  	    (dev->driver)) {
@@ -336,9 +336,9 @@
 	return 0;
 }
 
-int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
+int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
 {
-	device_for_each_child(&dev->dev, (void *)state, suspend_iter);
+	device_for_each_child(&dev->dev, &state, suspend_iter);
 	return 0;
 }
 
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index a90a533..05fa91a 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -379,6 +379,7 @@
 EXPORT_SYMBOL(pci_dev_present);
 
 EXPORT_SYMBOL(pci_find_bus);
+EXPORT_SYMBOL(pci_find_next_bus);
 EXPORT_SYMBOL(pci_find_device);
 EXPORT_SYMBOL(pci_find_device_reverse);
 EXPORT_SYMBOL(pci_find_slot);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index c1bdfb4..9fe48f7 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -74,6 +74,7 @@
 		idx = res - &list->dev->resource[0];
 		if (pci_assign_resource(list->dev, idx)) {
 			res->start = 0;
+			res->end = 0;
 			res->flags = 0;
 		}
 		tmp = list;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 52ea345..6485f75 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -1,8 +1,5 @@
 #
-# PCMCIA bus subsystem configuration
-#
-# Right now the non-CardBus choices are not supported
-# by the integrated kernel driver.
+# PCCARD (PCMCIA/CardBus) bus subsystem configuration
 #
 
 menu "PCCARD (PCMCIA/CardBus) support"
@@ -32,7 +29,7 @@
 
 	  The kernel command line options are:
 	    pcmcia_core.pc_debug=N
-	    ds.pc_debug=N
+	    pcmcia.pc_debug=N
 	    sa11xx_core.pc_debug=N
 
 	  The module option is called pc_debug=N
@@ -73,7 +70,7 @@
 	  If unsure, say Y.
 
 config PCMCIA_IOCTL
-	bool
+	bool "PCMCIA control ioctl (obsolete)"
 	depends on PCMCIA
 	default y
 	help
@@ -81,9 +78,8 @@
 	  subsystem will be built. It is needed by cardmgr and cardctl
 	  (pcmcia-cs) to function properly.
 
-	  If you do not use the new pcmciautils package, and have a
-	  yenta, Cirrus PD6729, i82092, i82365 or tcic compatible bridge,
-	  you need to say Y here to be able to use 16-bit PCMCIA cards.
+	  You should use the new pcmciautils package instead (see
+	  <file:Documentation/Changes> for location and details).
 
 	  If unsure, say Y.
 
@@ -106,7 +102,8 @@
 
 config YENTA
 	tristate "CardBus yenta-compatible bridge support"
-	depends on CARDBUS
+	depends on PCI
+	select CARDBUS if !EMBEDDED
 	select PCCARD_NONSTATIC
 	---help---
 	  This option enables support for CardBus host bridges.  Virtually
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index 417bc15..d5122b1 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -22,7 +22,6 @@
 #define __ASM_AU1000_PCMCIA_H
 
 /* include the world */
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index df19ce1..d414a3b 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -33,7 +33,6 @@
 #include <linux/version.h>
 #include <linux/types.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index 1dfc776..f113b69 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -38,7 +38,6 @@
 #include <linux/version.h>
 #include <linux/types.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 3ccb524..1d755e2 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -31,7 +31,6 @@
 #include <asm/io.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index e82859d..e39178f 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -33,7 +33,6 @@
 #include <asm/irq.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
@@ -216,6 +215,13 @@
 	list_add_tail(&socket->socket_list, &pcmcia_socket_list);
 	up_write(&pcmcia_socket_list_rwsem);
 
+#ifndef CONFIG_CARDBUS
+	/*
+	 * If we do not support Cardbus, ensure that
+	 * the Cardbus socket capability is disabled.
+	 */
+	socket->features &= ~SS_CAP_CARDBUS;
+#endif
 
 	/* set proper values in socket->dev */
 	socket->dev.class_data = socket;
@@ -449,11 +455,11 @@
 	}
 
 	if (status & SS_CARDBUS) {
+		if (!(skt->features & SS_CAP_CARDBUS)) {
+			cs_err(skt, "cardbus cards are not supported.\n");
+			return CS_BAD_TYPE;
+		}
 		skt->state |= SOCKET_CARDBUS;
-#ifndef CONFIG_CARDBUS
-		cs_err(skt, "cardbus cards are not supported.\n");
-		return CS_BAD_TYPE;
-#endif
 	}
 
 	/*
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 0b4c18e..6bbfbd0 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -99,23 +99,11 @@
 	}
 }
 
-#define CHECK_HANDLE(h) \
-    (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
-
 #define CHECK_SOCKET(s) \
     (((s) >= sockets) || (socket_table[s]->ops == NULL))
 
-#define SOCKET(h) (h->Socket)
-#define CONFIG(h) (&SOCKET(h)->config[(h)->Function])
-
-#define CHECK_REGION(r) \
-    (((r) == NULL) || ((r)->region_magic != REGION_MAGIC))
-
-#define CHECK_ERASEQ(q) \
-    (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC))
-
-#define EVENT(h, e, p) \
-    ((h)->event_handler((e), (p), &(h)->event_callback_args))
+#define SOCKET(h) (h->socket)
+#define CONFIG(h) (&SOCKET(h)->config[(h)->func])
 
 /* In cardbus.c */
 int cb_alloc(struct pcmcia_socket *s);
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index d5afd55..3e3c6f1 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -158,17 +158,15 @@
 };
 
 
-static int pcmcia_report_error(client_handle_t handle, error_info_t *err)
+static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err)
 {
 	int i;
 	char *serv;
 
-	if (CHECK_HANDLE(handle))
+	if (!p_dev)
 		printk(KERN_NOTICE);
-	else {
-		struct pcmcia_device *p_dev = handle_to_pdev(handle);
+	else
 		printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id);
-	}
 
 	for (i = 0; i < ARRAY_SIZE(service_table); i++)
 		if (service_table[i].key == err->func)
@@ -193,10 +191,10 @@
 
 /*======================================================================*/
 
-void cs_error(client_handle_t handle, int func, int ret)
+void cs_error(struct pcmcia_device *p_dev, int func, int ret)
 {
 	error_info_t err = { func, ret };
-	pcmcia_report_error(handle, &err);
+	pcmcia_report_error(p_dev, &err);
 }
 EXPORT_SYMBOL(cs_error);
 
@@ -207,6 +205,10 @@
 	unsigned int i;
 	u32 hash;
 
+	if (!p_drv->attach || !p_drv->event || !p_drv->detach)
+		printk(KERN_DEBUG "pcmcia: %s does misses a callback function",
+		       p_drv->drv.name);
+
 	while (did && did->match_flags) {
 		for (i=0; i<4; i++) {
 			if (!did->prod_id[i])
@@ -376,7 +378,7 @@
 
 	if (p_drv->attach) {
 		p_dev->instance = p_drv->attach();
-		if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) {
+		if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) {
 			printk(KERN_NOTICE "ds: unable to create instance "
 			       "of '%s'!\n", p_drv->drv.name);
 			ret = -EINVAL;
@@ -516,10 +518,7 @@
 	sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
 
 	/* compat */
-	p_dev->client.client_magic = CLIENT_MAGIC;
-	p_dev->client.Socket = s;
-	p_dev->client.Function = function;
-	p_dev->client.state = CLIENT_UNBOUND;
+	p_dev->state = CLIENT_UNBOUND;
 
 	/* Add to the list in pcmcia_bus_socket */
 	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
@@ -573,8 +572,6 @@
 	else
 		no_funcs = 1;
 
-	/* this doesn't handle multifunction devices on one pcmcia function
-	 * yet. */
 	for (i=0; i < no_funcs; i++)
 		pcmcia_device_add(s, i);
 
@@ -914,6 +911,7 @@
 static int send_event_callback(struct device *dev, void * _data)
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+	struct pcmcia_driver *p_drv;
 	struct send_event_data *data = _data;
 
 	/* we get called for all sockets, but may only pass the event
@@ -921,11 +919,16 @@
 	if (p_dev->socket != data->skt)
 		return 0;
 
-	if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE))
+	p_drv = to_pcmcia_drv(p_dev->dev.driver);
+	if (!p_drv)
 		return 0;
 
-	if (p_dev->client.EventMask & data->event)
-		return EVENT(&p_dev->client, data->event, data->priority);
+	if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE))
+		return 0;
+
+	if (p_drv->event)
+		return p_drv->event(data->event, data->priority,
+				    &p_dev->event_callback_args);
 
 	return 0;
 }
@@ -987,11 +990,11 @@
 
 
 
-int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
+int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req)
 {
-	client_t *client = NULL;
 	struct pcmcia_socket *s = NULL;
 	struct pcmcia_device *p_dev = NULL;
+	struct pcmcia_driver *p_drv = NULL;
 
 	/* Look for unbound client with matching dev_info */
 	down_read(&pcmcia_socket_list_rwsem);
@@ -1006,18 +1009,16 @@
 			continue;
 		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 		list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
-			struct pcmcia_driver *p_drv;
 			p_dev = pcmcia_get_dev(p_dev);
 			if (!p_dev)
 				continue;
-			if (!(p_dev->client.state & CLIENT_UNBOUND) ||
+			if (!(p_dev->state & CLIENT_UNBOUND) ||
 			    (!p_dev->dev.driver)) {
 				pcmcia_put_dev(p_dev);
 				continue;
 			}
 			p_drv = to_pcmcia_drv(p_dev->dev.driver);
 			if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) {
-				client = &p_dev->client;
 				spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 				goto found;
 			}
@@ -1028,26 +1029,20 @@
 	}
  found:
 	up_read(&pcmcia_socket_list_rwsem);
-	if (!p_dev || !client)
+	if (!p_dev)
 		return -ENODEV;
 
 	pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */
 
-	*handle = client;
-	client->state &= ~CLIENT_UNBOUND;
-	client->Socket = s;
-	client->EventMask = req->EventMask;
-	client->event_handler = req->event_handler;
-	client->event_callback_args = req->event_callback_args;
-	client->event_callback_args.client_handle = client;
+	*handle = p_dev;
+	p_dev->state &= ~CLIENT_UNBOUND;
+	p_dev->event_callback_args = req->event_callback_args;
+	p_dev->event_callback_args.client_handle = p_dev;
 
-	if (s->state & SOCKET_CARDBUS)
-		client->state |= CLIENT_CARDBUS;
 
-	if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
-	    (client->Function != BIND_FN_ALL)) {
+	if (!s->functions) {
 		cistpl_longlink_mfc_t mfc;
-		if (pccard_read_tuple(s, client->Function, CISTPL_LONGLINK_MFC, &mfc)
+		if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc)
 		    == CS_SUCCESS)
 			s->functions = mfc.nfn;
 		else
@@ -1060,13 +1055,13 @@
 	}
 
 	ds_dbg(1, "register_client(): client 0x%p, dev %s\n",
-	       client, p_dev->dev.bus_id);
-	if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
-		EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
+	       p_dev, p_dev->dev.bus_id);
 
 	if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) {
-		if (client->EventMask & CS_EVENT_CARD_INSERTION)
-			EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+		if (p_drv->event)
+			p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW,
+				     &p_dev->event_callback_args);
+
 	}
 
 	return CS_SUCCESS;
@@ -1099,7 +1094,7 @@
 		}
 		p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
 		list_del(&p_dev->socket_device_list);
-		p_dev->client.state |= CLIENT_STALE;
+		p_dev->state |= CLIENT_STALE;
 		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
 		device_unregister(&p_dev->dev);
@@ -1108,31 +1103,25 @@
 	return 0;
 } /* unbind_request */
 
-int pcmcia_deregister_client(client_handle_t handle)
+int pcmcia_deregister_client(struct pcmcia_device *p_dev)
 {
 	struct pcmcia_socket *s;
 	int i;
-	struct pcmcia_device *p_dev = handle_to_pdev(handle);
 
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
+	s = p_dev->socket;
+	ds_dbg(1, "deregister_client(%p)\n", p_dev);
 
-	s = SOCKET(handle);
-	ds_dbg(1, "deregister_client(%p)\n", handle);
-
-	if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+	if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
 		goto warn_out;
 	for (i = 0; i < MAX_WIN; i++)
-		if (handle->state & CLIENT_WIN_REQ(i))
+		if (p_dev->state & CLIENT_WIN_REQ(i))
 			goto warn_out;
 
-	if (handle->state & CLIENT_STALE) {
-		handle->client_magic = 0;
-		handle->state &= ~CLIENT_STALE;
+	if (p_dev->state & CLIENT_STALE) {
+		p_dev->state &= ~CLIENT_STALE;
 		pcmcia_put_dev(p_dev);
 	} else {
-		handle->state = CLIENT_UNBOUND;
-		handle->event_handler = NULL;
+		p_dev->state = CLIENT_UNBOUND;
 	}
 
 	return CS_SUCCESS;
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index 5ab55ae..316f8bc 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -43,7 +43,6 @@
 #include <asm/hd64465/hd64465.h>
 #include <asm/hd64465/io.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index d72f9a3..a713015 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -53,7 +53,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
@@ -698,14 +697,6 @@
     struct i82365_socket *t = &socket[sockets-ns];
 
     base = sockets-ns;
-    if (t->ioaddr > 0) {
-	if (!request_region(t->ioaddr, 2, "i82365")) {
-	    printk(KERN_ERR "i82365: IO region conflict at %#lx, not available\n",
-			t->ioaddr);
-	    return;
-	}
-    }
-    
     if (base == 0) printk("\n");
     printk(KERN_INFO "  %s", pcic[type].name);
     printk(" ISA-to-PCMCIA at port %#lx ofs 0x%02x",
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index b1111c6..65f3ee3 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -29,7 +29,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index c0997c4..7b14d7e 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -30,7 +30,6 @@
 #include <asm/system.h>
 #include <asm/addrspace.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c
index 1cc8331..ebb161c 100644
--- a/drivers/pcmcia/pcmcia_compat.c
+++ b/drivers/pcmcia/pcmcia_compat.c
@@ -18,7 +18,6 @@
 #include <linux/init.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/bulkmem.h>
@@ -28,64 +27,39 @@
 
 #include "cs_internal.h"
 
-int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_first_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
 {
-	struct pcmcia_socket *s;
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
-	return pccard_get_first_tuple(s, handle->Function, tuple);
+	return pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple);
 }
 EXPORT_SYMBOL(pcmcia_get_first_tuple);
 
-int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_next_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
 {
-	struct pcmcia_socket *s;
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
-	return pccard_get_next_tuple(s, handle->Function, tuple);
+	return pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple);
 }
 EXPORT_SYMBOL(pcmcia_get_next_tuple);
 
-int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_tuple_data(struct pcmcia_device *p_dev, tuple_t *tuple)
 {
-	struct pcmcia_socket *s;
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
-	return pccard_get_tuple_data(s, tuple);
+	return pccard_get_tuple_data(p_dev->socket, tuple);
 }
 EXPORT_SYMBOL(pcmcia_get_tuple_data);
 
-int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+int pcmcia_parse_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, cisparse_t *parse)
 {
 	return pccard_parse_tuple(tuple, parse);
 }
 EXPORT_SYMBOL(pcmcia_parse_tuple);
 
-int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
+int pcmcia_validate_cis(struct pcmcia_device *p_dev, cisinfo_t *info)
 {
-	struct pcmcia_socket *s;
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
-	return pccard_validate_cis(s, handle->Function, info);
+	return pccard_validate_cis(p_dev->socket, p_dev->func, info);
 }
 EXPORT_SYMBOL(pcmcia_validate_cis);
 
 
-int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
+int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req)
 {
-	struct pcmcia_socket *skt;
-    
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	skt = SOCKET(handle);
-	if (!skt)
-		return CS_BAD_HANDLE;
-
-	return pccard_reset_card(skt);
+	return pccard_reset_card(p_dev->socket);
 }
 EXPORT_SYMBOL(pcmcia_reset_card);
-
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index b883bc1..39ba640 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -31,7 +31,6 @@
 #include <linux/workqueue.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -71,29 +70,6 @@
 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
 #endif
 
-static const char *release = "Linux Kernel Card Services";
-
-/** pcmcia_get_card_services_info
- *
- * Return information about this version of Card Services
- */
-static int pcmcia_get_card_services_info(servinfo_t *info)
-{
-	unsigned int socket_count = 0;
-	struct list_head *tmp;
-	info->Signature[0] = 'C';
-	info->Signature[1] = 'S';
-	down_read(&pcmcia_socket_list_rwsem);
-	list_for_each(tmp, &pcmcia_socket_list)
-		socket_count++;
-	up_read(&pcmcia_socket_list_rwsem);
-	info->Count = socket_count;
-	info->Revision = CS_RELEASE_CODE;
-	info->CSLevel = 0x0210;
-	info->VendorString = (char *)release;
-	return CS_SUCCESS;
-} /* get_card_services_info */
-
 
 /* backwards-compatible accessing of driver --- by name! */
 
@@ -591,9 +567,6 @@
     case DS_ADJUST_RESOURCE_INFO:
 	ret = pcmcia_adjust_resource_info(&buf->adjust);
 	break;
-    case DS_GET_CARD_SERVICES_INFO:
-	ret = pcmcia_get_card_services_info(&buf->servinfo);
-	break;
     case DS_GET_CONFIGURATION_INFO:
 	if (buf->config.Function &&
 	   (buf->config.Function >= s->functions))
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index c01dc6b..184f4f8 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -23,7 +23,6 @@
 #include <linux/device.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
@@ -202,14 +201,11 @@
 	return CS_SUCCESS;
 } /* pccard_access_configuration_register */
 
-int pcmcia_access_configuration_register(client_handle_t handle,
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
 					 conf_reg_t *reg)
 {
-	struct pcmcia_socket *s;
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
-	return pccard_access_configuration_register(s, handle->Function, reg);
+	return pccard_access_configuration_register(p_dev->socket,
+						    p_dev->func, reg);
 }
 EXPORT_SYMBOL(pcmcia_access_configuration_register);
 
@@ -271,17 +267,11 @@
 	return CS_SUCCESS;
 } /* pccard_get_configuration_info */
 
-int pcmcia_get_configuration_info(client_handle_t handle,
+int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
 				  config_info_t *config)
 {
-	struct pcmcia_socket *s;
-
-	if ((CHECK_HANDLE(handle)) || !config)
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
-	if (!s)
-		return CS_BAD_HANDLE;
-	return pccard_get_configuration_info(s, handle->Function, config);
+	return pccard_get_configuration_info(p_dev->socket, p_dev->func,
+					     config);
 }
 EXPORT_SYMBOL(pcmcia_get_configuration_info);
 
@@ -382,10 +372,8 @@
 int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
 {
 	struct pcmcia_socket *s;
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
 	s = SOCKET(handle);
-	return pccard_get_status(s, handle->Function, status);
+	return pccard_get_status(s, handle->func, status);
 }
 EXPORT_SYMBOL(pcmcia_get_status);
 
@@ -426,16 +414,14 @@
  *
  * Modify a locked socket configuration
  */
-int pcmcia_modify_configuration(client_handle_t handle,
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
 				modconf_t *mod)
 {
 	struct pcmcia_socket *s;
 	config_t *c;
 
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
-	c = CONFIG(handle);
+	s = p_dev->socket;
+	c = CONFIG(p_dev);
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
 	if (!(c->state & CONFIG_LOCKED))
@@ -472,25 +458,18 @@
 EXPORT_SYMBOL(pcmcia_modify_configuration);
 
 
-int pcmcia_release_configuration(client_handle_t handle)
+int pcmcia_release_configuration(struct pcmcia_device *p_dev)
 {
 	pccard_io_map io = { 0, 0, 0, 0, 1 };
-	struct pcmcia_socket *s;
+	struct pcmcia_socket *s = p_dev->socket;
 	int i;
 
-	if (CHECK_HANDLE(handle) ||
-	    !(handle->state & CLIENT_CONFIG_LOCKED))
+	if (!(p_dev->state & CLIENT_CONFIG_LOCKED))
 		return CS_BAD_HANDLE;
-	handle->state &= ~CLIENT_CONFIG_LOCKED;
-	s = SOCKET(handle);
+	p_dev->state &= ~CLIENT_CONFIG_LOCKED;
 
-#ifdef CONFIG_CARDBUS
-	if (handle->state & CLIENT_CARDBUS)
-		return CS_SUCCESS;
-#endif
-
-	if (!(handle->state & CLIENT_STALE)) {
-		config_t *c = CONFIG(handle);
+	if (!(p_dev->state & CLIENT_STALE)) {
+		config_t *c = CONFIG(p_dev);
 		if (--(s->lock_count) == 0) {
 			s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
 			s->socket.Vpp = 0;
@@ -523,22 +502,16 @@
  * don't bother checking the port ranges against the current socket
  * values.
  */
-int pcmcia_release_io(client_handle_t handle, io_req_t *req)
+int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
 {
-	struct pcmcia_socket *s;
+	struct pcmcia_socket *s = p_dev->socket;
 
-	if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+	if (!(p_dev->state & CLIENT_IO_REQ))
 		return CS_BAD_HANDLE;
-	handle->state &= ~CLIENT_IO_REQ;
-	s = SOCKET(handle);
+	p_dev->state &= ~CLIENT_IO_REQ;
 
-#ifdef CONFIG_CARDBUS
-	if (handle->state & CLIENT_CARDBUS)
-		return CS_SUCCESS;
-#endif
-
-	if (!(handle->state & CLIENT_STALE)) {
-		config_t *c = CONFIG(handle);
+	if (!(p_dev->state & CLIENT_STALE)) {
+		config_t *c = CONFIG(p_dev);
 		if (c->state & CONFIG_LOCKED)
 			return CS_CONFIGURATION_LOCKED;
 		if ((c->io.BasePort1 != req->BasePort1) ||
@@ -558,16 +531,15 @@
 EXPORT_SYMBOL(pcmcia_release_io);
 
 
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req)
+int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 {
-	struct pcmcia_socket *s;
-	if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
+	struct pcmcia_socket *s = p_dev->socket;
+	if (!(p_dev->state & CLIENT_IRQ_REQ))
 		return CS_BAD_HANDLE;
-	handle->state &= ~CLIENT_IRQ_REQ;
-	s = SOCKET(handle);
+	p_dev->state &= ~CLIENT_IRQ_REQ;
 
-	if (!(handle->state & CLIENT_STALE)) {
-		config_t *c = CONFIG(handle);
+	if (!(p_dev->state & CLIENT_STALE)) {
+		config_t *c = CONFIG(p_dev);
 		if (c->state & CONFIG_LOCKED)
 			return CS_CONFIGURATION_LOCKED;
 		if (c->irq.Attributes != req->Attributes)
@@ -623,29 +595,21 @@
 EXPORT_SYMBOL(pcmcia_release_window);
 
 
-int pcmcia_request_configuration(client_handle_t handle,
+int pcmcia_request_configuration(struct pcmcia_device *p_dev,
 				 config_req_t *req)
 {
 	int i;
 	u_int base;
-	struct pcmcia_socket *s;
+	struct pcmcia_socket *s = p_dev->socket;
 	config_t *c;
 	pccard_io_map iomap;
 
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
 
-#ifdef CONFIG_CARDBUS
-	if (handle->state & CLIENT_CARDBUS)
-		return CS_UNSUPPORTED_MODE;
-#endif
-
 	if (req->IntType & INT_CARDBUS)
 		return CS_UNSUPPORTED_MODE;
-	c = CONFIG(handle);
+	c = CONFIG(p_dev);
 	if (c->state & CONFIG_LOCKED)
 		return CS_CONFIGURATION_LOCKED;
 
@@ -746,7 +710,7 @@
 	}
 
 	c->state |= CONFIG_LOCKED;
-	handle->state |= CLIENT_CONFIG_LOCKED;
+	p_dev->state |= CLIENT_CONFIG_LOCKED;
 	return CS_SUCCESS;
 } /* pcmcia_request_configuration */
 EXPORT_SYMBOL(pcmcia_request_configuration);
@@ -757,29 +721,17 @@
  * Request_io() reserves ranges of port addresses for a socket.
  * I have not implemented range sharing or alias addressing.
  */
-int pcmcia_request_io(client_handle_t handle, io_req_t *req)
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
 {
-	struct pcmcia_socket *s;
+	struct pcmcia_socket *s = p_dev->socket;
 	config_t *c;
 
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
 
-	if (handle->state & CLIENT_CARDBUS) {
-#ifdef CONFIG_CARDBUS
-		handle->state |= CLIENT_IO_REQ;
-		return CS_SUCCESS;
-#else
-		return CS_UNSUPPORTED_FUNCTION;
-#endif
-	}
-
 	if (!req)
 		return CS_UNSUPPORTED_MODE;
-	c = CONFIG(handle);
+	c = CONFIG(p_dev);
 	if (c->state & CONFIG_LOCKED)
 		return CS_CONFIGURATION_LOCKED;
 	if (c->state & CONFIG_IO_REQ)
@@ -804,7 +756,7 @@
 
 	c->io = *req;
 	c->state |= CONFIG_IO_REQ;
-	handle->state |= CLIENT_IO_REQ;
+	p_dev->state |= CLIENT_IO_REQ;
 	return CS_SUCCESS;
 } /* pcmcia_request_io */
 EXPORT_SYMBOL(pcmcia_request_io);
@@ -827,19 +779,15 @@
 }
 #endif
 
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 {
-	struct pcmcia_socket *s;
+	struct pcmcia_socket *s = p_dev->socket;
 	config_t *c;
 	int ret = CS_IN_USE, irq = 0;
-	struct pcmcia_device *p_dev = handle_to_pdev(handle);
 
-	if (CHECK_HANDLE(handle))
-		return CS_BAD_HANDLE;
-	s = SOCKET(handle);
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
-	c = CONFIG(handle);
+	c = CONFIG(p_dev);
 	if (c->state & CONFIG_LOCKED)
 		return CS_CONFIGURATION_LOCKED;
 	if (c->state & CONFIG_IRQ_REQ)
@@ -903,7 +851,7 @@
 	s->irq.Config++;
 
 	c->state |= CONFIG_IRQ_REQ;
-	handle->state |= CLIENT_IRQ_REQ;
+	p_dev->state |= CLIENT_IRQ_REQ;
 
 #ifdef CONFIG_PCMCIA_PROBE
 	pcmcia_used_irq[irq]++;
@@ -919,16 +867,13 @@
  * Request_window() establishes a mapping between card memory space
  * and system memory space.
  */
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh)
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh)
 {
-	struct pcmcia_socket *s;
+	struct pcmcia_socket *s = (*p_dev)->socket;
 	window_t *win;
 	u_long align;
 	int w;
 
-	if (CHECK_HANDLE(*handle))
-		return CS_BAD_HANDLE;
-	s = (*handle)->Socket;
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
 	if (req->Attributes & (WIN_PAGED | WIN_SHARED))
@@ -957,7 +902,7 @@
 	win = &s->win[w];
 	win->magic = WINDOW_MAGIC;
 	win->index = w;
-	win->handle = *handle;
+	win->handle = *p_dev;
 	win->sock = s;
 
 	if (!(s->features & SS_CAP_STATIC_MAP)) {
@@ -966,7 +911,7 @@
 		if (!win->ctl.res)
 			return CS_IN_USE;
 	}
-	(*handle)->state |= CLIENT_WIN_REQ(w);
+	(*p_dev)->state |= CLIENT_WIN_REQ(w);
 
 	/* Configure the socket controller */
 	win->ctl.map = w+1;
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index f1bb791..e98bb3d 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -34,7 +34,6 @@
 #include <linux/init.h>
 #include <linux/config.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 700a155..6f14126 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -11,7 +11,6 @@
 
 /* include the world */
 #include <linux/cpufreq.h>
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index fcef54c..1040a6c 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -29,7 +29,6 @@
 #include <asm/irq.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index aacbbb5..d5a61ea 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -50,7 +50,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index c7ba998..fbe233e 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -154,8 +154,6 @@
 #define ENE_TEST_C9			0xc9	/* 8bit */
 #define ENE_TEST_C9_TLTENABLE		0x02
 
-#ifdef CONFIG_CARDBUS
-
 /*
  * Texas Instruments CardBus controller overrides.
  */
@@ -843,7 +841,5 @@
 	return ti12xx_override(socket);
 }
 
-#endif /* CONFIG_CARDBUS */
-
 #endif /* _LINUX_TI113X_H */
 
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 02b23ab..0e7aa81 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
@@ -869,14 +868,11 @@
  */
 static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask)
 {
-	socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
-	socket->socket.map_size = 0x1000;
 	socket->socket.pci_irq = socket->cb_irq;
 	if (isa_probe)
 		socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
 	else
 		socket->socket.irq_mask = 0;
-	socket->socket.cb_dev = socket->dev;
 
 	printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n",
 	       socket->socket.irq_mask, socket->cb_irq);
@@ -942,6 +938,9 @@
 	socket->socket.dev.dev = &dev->dev;
 	socket->socket.driver_data = socket;
 	socket->socket.owner = THIS_MODULE;
+	socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
+	socket->socket.map_size = 0x1000;
+	socket->socket.cb_dev = dev;
 
 	/* prepare struct yenta_socket */
 	socket->dev = dev;
@@ -1012,6 +1011,10 @@
 		socket->poll_timer.data = (unsigned long)socket;
 		socket->poll_timer.expires = jiffies + HZ;
 		add_timer(&socket->poll_timer);
+		printk(KERN_INFO "Yenta: no PCI IRQ, CardBus support disabled for this socket.\n"
+		       KERN_INFO "Yenta: check your BIOS CardBus, BIOS IRQ or ACPI settings.\n");
+	} else {
+		socket->socket.features |= SS_CAP_CARDBUS;
 	}
 
 	/* Figure out what the dang thing can do for the PCMCIA layer... */
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 60440db..24c0af4 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -428,7 +428,7 @@
 	new_skb = NULL;		/* assume no dice */
 	pkt_cnt = 0;
 	CLAW_DBF_TEXT(4,trace,"PackSKBe");
-	if (skb_queue_len(&p_ch->collect_queue) > 0) {
+	if (!skb_queue_empty(&p_ch->collect_queue)) {
 	/* some data */
 		held_skb = skb_dequeue(&p_ch->collect_queue);
 		if (p_env->packing != DO_PACKED)
@@ -1254,7 +1254,7 @@
 	privptr = (struct claw_privbk *) dev->priv;
         claw_free_wrt_buf( dev );
 	if ((privptr->write_free_count > 0) &&
-	    (skb_queue_len(&p_ch->collect_queue) > 0)) {
+	    !skb_queue_empty(&p_ch->collect_queue)) {
 	  	pk_skb = claw_pack_skb(privptr);
 		while (pk_skb != NULL) {
 			rc = claw_hw_tx( pk_skb, dev,1);
diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
index 3080393..968f2c1 100644
--- a/drivers/s390/net/ctctty.c
+++ b/drivers/s390/net/ctctty.c
@@ -156,7 +156,7 @@
 					skb_queue_head(&info->rx_queue, skb);
 				else {
 					kfree_skb(skb);
-					ret = skb_queue_len(&info->rx_queue);
+					ret = !skb_queue_empty(&info->rx_queue);
 				}
 			}
 		}
@@ -530,7 +530,7 @@
 		total += c;
 		count -= c;
 	}
-	if (skb_queue_len(&info->tx_queue)) {
+	if (!skb_queue_empty(&info->tx_queue)) {
 		info->lsr &= ~UART_LSR_TEMT;
 		tasklet_schedule(&info->tasklet);
 	}
@@ -594,7 +594,7 @@
 		return;
 	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars"))
 		return;
-	if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
+	if (tty->stopped || tty->hw_stopped || skb_queue_empty(&info->tx_queue))
 		return;
 	tasklet_schedule(&info->tasklet);
 }
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index edd47d1..932dcf0 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -424,7 +424,7 @@
 	.use_clustering	= DISABLE_CLUSTERING,
 };
 
-static int mac53c94_probe(struct macio_dev *mdev, const struct of_match *match)
+static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	struct device_node *node = macio_get_of_node(mdev);
 	struct pci_dev *pdev = macio_get_pci_dev(mdev);
@@ -544,15 +544,14 @@
 }
 
 
-static struct of_match mac53c94_match[] = 
+static struct of_device_id mac53c94_match[] = 
 {
 	{
 	.name 		= "53c94",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{},
 };
+MODULE_DEVICE_TABLE (of, mac53c94_match);
 
 static struct macio_driver mac53c94_driver = 
 {
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index b05737a..ff19332 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1847,7 +1847,7 @@
 	.use_clustering			= DISABLE_CLUSTERING,
 };
 
-static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
+static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	struct device_node *mesh = macio_get_of_node(mdev);
 	struct pci_dev* pdev = macio_get_pci_dev(mdev);
@@ -2012,20 +2012,18 @@
 }
 
 
-static struct of_match mesh_match[] = 
+static struct of_device_id mesh_match[] = 
 {
 	{
 	.name 		= "mesh",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{
-	.name 		= OF_ANY_MATCH,
 	.type		= "scsi",
 	.compatible	= "chrp,mesh0"
 	},
 	{},
 };
+MODULE_DEVICE_TABLE (of, mesh_match);
 
 static struct macio_driver mesh_driver = 
 {
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index f1f6bf5..7c53064 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -50,7 +50,6 @@
 #include <scsi/scsi_host.h>
 #include "aha152x.h"
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -134,11 +133,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.event_handler = &aha152x_event;
-    client_reg.EventMask =
-	CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -334,6 +328,7 @@
 		.name	= "aha152x_cs",
 	},
 	.attach		= aha152x_attach,
+	.event		= aha152x_event,
 	.detach		= aha152x_detach,
 	.id_table       = aha152x_ids,
 };
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 853e6ee..db8f5cd 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -47,7 +47,6 @@
 #include <scsi/scsi_host.h>
 #include "fdomain.h"
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -120,11 +119,6 @@
     link->next = dev_list;
     dev_list = link;
     client_reg.dev_info = &dev_info;
-    client_reg.event_handler = &fdomain_event;
-    client_reg.EventMask =
-	CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
     client_reg.Version = 0x0210;
     client_reg.event_callback_args.client_data = link;
     ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -314,6 +308,7 @@
 		.name	= "fdomain_cs",
 	},
 	.attach		= fdomain_attach,
+	.event		= fdomain_event,
 	.detach		= fdomain_detach,
 	.id_table       = fdomain_ids,
 };
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 91b3f28..3cd3b40 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -51,7 +51,6 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -1642,11 +1641,6 @@
 	link->next               = dev_list;
 	dev_list                 = link;
 	client_reg.dev_info	 = &dev_info;
-	client_reg.EventMask	 =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET	|
-		CS_EVENT_PM_SUSPEND	| CS_EVENT_PM_RESUME	 ;
-	client_reg.event_handler = &nsp_cs_event;
 	client_reg.Version	 = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2138,12 +2132,13 @@
 MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
 
 static struct pcmcia_driver nsp_driver = {
-	.owner          = THIS_MODULE,
-	.drv            = {
-		.name   = "nsp_cs",
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "nsp_cs",
 	},
-	.attach         = nsp_cs_attach,
-	.detach         = nsp_cs_detach,
+	.attach		= nsp_cs_attach,
+	.event		= nsp_cs_event,
+	.detach		= nsp_cs_detach,
 	.id_table	= nsp_cs_ids,
 };
 #endif
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 0dcf411..7a516f3 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -49,7 +49,6 @@
 #include <scsi/scsi_host.h>
 #include "../qlogicfas408.h"
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -194,8 +193,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.event_handler = &qlogic_event;
-	client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -423,6 +420,7 @@
 	.name		= "qlogic_cs",
 	},
 	.attach		= qlogic_attach,
+	.event		= qlogic_event,
 	.detach		= qlogic_detach,
 	.id_table       = qlogic_ids,
 };
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 7d4b16b..b4b3a1a 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -979,10 +979,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.event_handler = &SYM53C500_event;
-	client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
-	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1013,6 +1009,7 @@
 		.name	= "sym53c500_cs",
 	},
 	.attach		= SYM53C500_attach,
+	.event		= SYM53C500_event,
 	.detach		= SYM53C500_detach,
 	.id_table       = sym53c500_ids,
 };
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 1c9f716..7db2f37 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1545,7 +1545,7 @@
 /*
  * Called upon match with an escc node in the devive-tree.
  */
-static int pmz_attach(struct macio_dev *mdev, const struct of_match *match)
+static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
 {
 	int i;
 	
@@ -1850,20 +1850,17 @@
 	return rc;
 }
 
-static struct of_match pmz_match[] = 
+static struct of_device_id pmz_match[] = 
 {
 	{
 	.name 		= "ch-a",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{
 	.name 		= "ch-b",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH
 	},
 	{},
 };
+MODULE_DEVICE_TABLE (of, pmz_match);
 
 static struct macio_driver pmz_driver = 
 {
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 73a34b1..de0136c 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -45,7 +45,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -232,11 +231,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &serial_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -883,6 +877,7 @@
 		.name	= "serial_cs",
 	},
 	.attach		= serial_attach,
+	.event		= serial_event,
 	.detach		= serial_detach,
 	.id_table	= serial_ids,
 };
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index ce5ebfe..57c0c6e 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -9,7 +9,6 @@
 #include <linux/errno.h>	/* error codes */
 #include <linux/slab.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -69,11 +68,6 @@
 	link->next = dev_list;
 	dev_list = link;
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask =
-	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &ixj_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -307,6 +301,7 @@
 		.name	= "ixj_cs",
 	},
 	.attach		= ixj_attach,
+	.event		= ixj_event,
 	.detach		= ixj_detach,
 	.id_table	= ixj_ids,
 };
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 269d8ef..38aebe3 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -20,7 +20,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -389,11 +388,6 @@
 	dev_list = link;
 	client_reg.dev_info = (dev_info_t *) &driver_name;
 	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-	client_reg.EventMask =
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &sl811_cs_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -418,6 +412,7 @@
 		.name	= (char *)driver_name,
 	},
 	.attach		= sl811_cs_attach,
+	.event		= sl811_cs_event,
 	.detach		= sl811_cs_detach,
 	.id_table	= sl811_ids,
 };
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index 8a945f4..576f3b8 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -3227,9 +3227,9 @@
 	temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
 
 	// maybe wait for deletions to finish.
-	while (skb_queue_len (&dev->rxq)
-			&& skb_queue_len (&dev->txq)
-			&& skb_queue_len (&dev->done)) {
+	while (!skb_queue_empty(&dev->rxq) &&
+	       !skb_queue_empty(&dev->txq) &&
+	       !skb_queue_empty(&dev->done)) {
 		msleep(UNLINK_TIMEOUT_MS);
 		if (netif_msg_ifdown (dev))
 			devdbg (dev, "waited for %d urb completions", temp);
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 7dfbf39..ddc9443 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -256,7 +256,7 @@
 	unsigned int offset = 0, i;
 
 	if (!fb_info->cmap.red || !fb_info->cmap.blue ||
-	    fb_info->cmap.green || fb_info->cmap.transp)
+	    !fb_info->cmap.green || !fb_info->cmap.transp)
 		return -EINVAL;
 
 	for (i = 0; i < fb_info->cmap.len; i++) {
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 6ba10e3..3e9ccf3 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -63,5 +63,10 @@
 	depends on LOGO && SUPERH
 	default y
 
+config LOGO_M32R_CLUT224
+	bool "224-color M32R Linux logo"
+	depends on LOGO && M32R
+	default y
+
 endmenu
 
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index b0d9950..d0244c04 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -12,6 +12,7 @@
 obj-$(CONFIG_LOGO_SUPERH_MONO)		+= logo_superh_mono.o
 obj-$(CONFIG_LOGO_SUPERH_VGA16)		+= logo_superh_vga16.o
 obj-$(CONFIG_LOGO_SUPERH_CLUT224)	+= logo_superh_clut224.o
+obj-$(CONFIG_LOGO_M32R_CLUT224)		+= logo_m32r_clut224.o
 
 # How to generate logo's
 
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 77b6220..788fa81 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -33,6 +33,7 @@
 extern const struct linux_logo logo_superh_mono;
 extern const struct linux_logo logo_superh_vga16;
 extern const struct linux_logo logo_superh_clut224;
+extern const struct linux_logo logo_m32r_clut224;
 
 
 const struct linux_logo *fb_find_logo(int depth)
@@ -97,6 +98,10 @@
 		/* SuperH Linux logo */
 		logo = &logo_superh_clut224;
 #endif
+#ifdef CONFIG_LOGO_M32R_CLUT224
+		/* M32R Linux logo */
+		logo = &logo_m32r_clut224;
+#endif
 	}
 	return logo;
 }
diff --git a/drivers/video/logo/logo_m32r_clut224.ppm b/drivers/video/logo/logo_m32r_clut224.ppm
new file mode 100644
index 0000000..8b2983c
--- /dev/null
+++ b/drivers/video/logo/logo_m32r_clut224.ppm
@@ -0,0 +1,1292 @@
+P3
+# CREATOR: The GIMP's PNM Filter Version 1.0
+#
+# Note: how to convert ppm to pnm(ascii).
+#   $ convert -posterize 224 m32r.ppm - | pnm2asc -f5 >logo_m32r_clut224.ppm
+#
+# convert - imagemagick: /usr/bin/convert
+# pnm2asc - pnm to ascii-pnm format converter
+#   http://www.is.aist.go.jp/etlcdb/util/p2a.htm#English
+
+80 80
+255
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  43 43 43  75 75 75  27 27 27  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  59 59 59  123 123 123  67 67 67  27 27 27
+  2 2 3  2 2 3  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  10 6 3  59 59 59  80 80 80  43 43 43  27 27 27
+  2 2 3  2 2 3  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  19 19 19  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  2 2 3  10 6 3  10 6 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  10 6 3  11 11 11  11 11 11  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  2 2 3  2 2 3  27 27 27  10 6 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  19 19 19  2 2 3  2 2 3  51 51 51  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  123 123 123  196 196 196  115 115 115  2 2 3
+  2 2 3  2 2 3  2 2 3  75 75 75  141 141 140
+  172 172 172  196 196 196  190 189 188  2 2 3  11 11 11
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  27 27 27  164 164 164  228 228 228  221 221 220  10 6 3
+  2 2 3  2 2 3  2 2 3  172 172 172  245 245 245
+  254 254 252  254 254 252  221 221 220  35 35 35  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  164 164 164  228 228 228  35 35 35  236 236 236  236 236 236
+  2 2 3  11 11 11  2 2 3  254 254 252  245 245 245
+  2 2 3  75 75 75  245 245 245  245 245 245  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  212 212 212  2 2 3  51 51 51  11 11 11  245 245 245
+  27 27 27  80 80 80  10 6 3  254 254 252  2 2 3
+  2 2 3  91 91 91  19 19 19  254 254 252  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  196 196 196  10 6 3  2 2 3  11 11 11  107 107 107
+  49 35 5  57 42 11  31 22 3  236 236 236  2 2 3
+  2 2 3  2 2 3  2 2 3  254 254 252  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  107 107 107  221 221 220  2 2 3  64 43 7  194 148 10
+  236 188 10  225 180 10  170 126 10  236 188 10  94 86 67
+  2 2 3  2 2 3  204 204 204  236 236 236  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  228 228 228  182 126 10  218 164 9  236 188 10
+  236 188 10  237 204 14  236 205 40  246 214 48  246 214 48
+  245 189 11  209 156 9  196 196 196  11 11 11  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  165 114 10  207 148 7  229 172 9  236 180 10
+  236 196 11  237 204 14  242 218 43  246 218 75  246 218 19
+  246 213 13  246 218 19  244 205 11  218 164 9  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  164 109 5  192 133 7  224 165 9  236 180 10  236 188 10
+  236 196 11  241 212 42  246 218 75  246 218 19  246 218 19
+  246 218 19  236 196 11  150 114 10  229 172 9  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  165 114 10  201 142 7  229 172 9  242 182 11  236 188 10
+  237 204 14  245 213 67  246 218 19  246 213 13  246 213 13
+  154 119 10  207 148 7  218 164 9  216 156 8  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  120 78 3  225 180 10  245 189 11  236 205 40
+  241 212 42  241 212 17  237 204 14  148 107 9  182 126 10
+  216 156 8  218 164 9  207 148 7  82 70 43  2 2 3
+  2 2 3  123 123 123  35 35 35  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  10 6 3  180 180 180  156 102 5  135 88 5  142 106 7
+  126 98 11  165 114 10  185 132 9  207 148 7  215 150 13
+  199 140 8  188 148 71  196 196 196  190 189 188  2 2 3
+  2 2 3  11 11 11  132 132 132  75 75 75  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  10 6 3  190 189 188  190 189 188  151 97 5  192 133 7
+  207 148 7  206 142 8  199 140 8  180 121 7  180 132 31
+  190 189 188  190 189 188  212 212 212  212 212 212  107 107 107
+  2 2 3  2 2 3  99 99 99  51 51 51  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  190 189 188  190 189 188  190 189 188  136 95 7
+  151 97 5  151 97 5  151 97 5  183 156 91  190 189 188
+  190 189 188  228 228 228  254 254 252  254 254 252  221 221 220
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  10 6 3  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  2 2 3
+  75 75 75  245 245 245  196 196 196  190 189 188  190 189 188
+  190 189 188  196 196 196  190 189 188  190 189 188  204 204 204
+  236 236 236  254 254 252  254 254 252  254 254 252  254 254 252
+  35 35 35  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  2 2 3  27 27 27  2 2 3
+  245 245 245  254 254 252  245 245 245  190 189 188  190 189 188
+  190 189 188  190 189 188  190 189 188  212 212 212  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  10 6 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  2 2 3  2 2 3  132 132 132
+  254 254 252  254 254 252  254 254 252  236 236 236  196 196 196
+  190 189 188  204 204 204  245 245 245  245 245 245  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  80 80 80  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  2 2 3  2 2 3  2 2 3  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  245 245 245  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  2 2 3  2 2 3  2 2 3  212 212 212  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  2 2 3  2 2 3  204 204 204  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  245 245 245  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  245 245 245  236 236 236  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  2 2 3
+  2 2 3  2 2 3  11 11 11  164 164 164  212 212 212
+  236 236 236  245 245 245  254 254 252  236 236 236  221 221 220
+  221 221 220  228 228 228  245 245 245  245 245 245  245 245 245
+  236 236 236  221 221 220  212 212 212  204 204 204  204 204 204
+  196 196 196  204 204 204  59 59 59  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  2 2 3
+  2 2 3  2 2 3  27 27 27  172 172 172  212 212 212
+  236 236 236  254 254 252  254 254 252  254 254 252  228 228 228
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  245 245 245  221 221 220  204 204 204  196 196 196
+  196 196 196  196 196 196  228 228 228  19 19 19  2 2 3
+  80 80 80  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  2 2 3  2 2 3  2 2 3
+  11 11 11  2 2 3  164 164 164  236 236 236  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  236 236 236  212 212 212  196 196 196  245 245 245  2 2 3
+  2 2 3  11 11 11  51 51 51  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  2 2 3  2 2 3  86 86 83
+  2 2 3  27 27 27  236 236 236  254 254 252  254 254 252
+  245 245 245  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  212 212 212  196 196 196  91 91 91
+  2 2 3  2 2 3  2 2 3  11 11 11  2 2 3
+  2 2 3  2 2 3  2 2 3  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  2 2 3  2 2 3  2 2 3
+  2 2 3  245 245 245  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  245 245 245  254 254 252  254 254 252  254 254 252
+  254 254 252  245 245 245  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  221 221 220  245 245 245
+  2 2 3  11 11 11  43 43 43  19 19 19  10 6 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  2 2 3  80 80 80  2 2 3
+  2 2 3  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  245 245 245  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  43 43 43  27 27 27  80 80 80  19 19 19  80 80 80
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  2 2 3  2 2 3  2 2 3  2 2 3
+  245 245 245  254 254 252  254 254 252  17 11 233  254 254 252
+  254 254 252  254 254 252  254 254 252  236 236 236  17 11 233
+  17 11 233  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  11 11 11  11 11 11  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  2 2 3  67 67 67  2 2 3  19 19 19
+  254 254 252  254 254 252  245 245 245  17 11 233  245 245 245
+  254 254 252  254 254 252  17 11 233  228 228 228  17 11 233
+  17 11 233  17 11 233  17 11 233  254 254 252  17 11 233
+  17 11 233  254 254 252  254 254 252  17 11 233  17 11 233
+  17 11 233  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  2 2 3  2 2 3  2 2 3  2 2 3
+  11 11 11  2 2 3  2 2 3  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  2 2 3  10 6 3  11 11 11  2 2 3  228 228 228
+  254 254 252  254 254 252  254 254 252  17 11 233  254 254 252
+  254 254 252  17 11 233  17 11 233  17 11 233  245 245 245
+  254 254 252  254 254 252  17 11 233  17 11 233  17 11 233
+  17 11 233  17 11 233  254 254 252  17 11 233  17 11 233
+  17 11 233  17 11 233  254 254 252  254 254 252  254 254 252
+  254 254 252  2 2 3  2 2 3  2 2 3  2 2 3
+  27 27 27  2 2 3  2 2 3  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  2 2 3  2 2 3  2 2 3  2 2 3  254 254 252
+  254 254 252  254 254 252  254 254 252  17 11 233  17 11 233
+  17 11 233  17 11 233  17 11 233  17 11 233  254 254 252
+  17 11 233  17 11 233  17 11 233  254 254 252  254 254 252
+  17 11 233  17 11 233  254 254 252  17 11 233  17 11 233
+  254 254 252  17 11 233  254 254 252  254 254 252  254 254 252
+  254 254 252  2 2 3  2 2 3  2 2 3  2 2 3
+  11 11 11  2 2 3  2 2 3  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  19 19 19  2 2 3  2 2 3  254 254 252
+  254 254 252  254 254 252  17 11 233  245 245 245  17 11 233
+  17 11 233  245 245 245  254 254 252  17 11 233  254 254 252
+  17 11 233  17 11 233  17 11 233  254 254 252  254 254 252
+  17 11 233  17 11 233  254 254 252  17 11 233  17 11 233
+  17 11 233  17 11 233  254 254 252  254 254 252  254 254 252
+  254 254 252  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  2 2 3
+  2 2 3  19 19 19  2 2 3  19 19 19  254 254 252
+  254 254 252  245 245 245  17 11 233  254 254 252  17 11 233
+  17 11 233  254 254 252  254 254 252  17 11 233  254 254 252
+  254 254 252  254 254 252  17 11 233  17 11 233  254 254 252
+  17 11 233  17 11 233  254 254 252  17 11 233  17 11 233
+  17 11 233  17 11 233  17 11 233  254 254 252  254 254 252
+  254 254 252  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  2 2 3
+  2 2 3  43 43 43  2 2 3  43 43 43  254 254 252
+  245 245 245  254 254 252  17 11 233  254 254 252  17 11 233
+  254 254 252  254 254 252  254 254 252  17 11 233  17 11 233
+  17 11 233  17 11 233  17 11 233  254 254 252  17 11 233
+  17 11 233  17 11 233  17 11 233  17 11 233  17 11 233
+  245 245 245  254 254 252  17 11 233  254 254 252  254 254 252
+  245 245 245  2 2 3  2 2 3  2 2 3  11 11 11
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  2 2 3
+  2 2 3  75 75 75  2 2 3  99 99 99  254 254 252
+  254 254 252  254 254 252  17 11 233  254 254 252  254 254 252
+  254 254 252  254 254 252  245 245 245  228 228 228  254 254 252
+  254 254 252  17 11 233  245 245 245  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  17 11 233  17 11 233
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  2 2 3  2 2 3  2 2 3  75 75 75
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  2 2 3
+  2 2 3  2 2 3  11 11 11  107 107 107  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  245 245 245  254 254 252  245 245 245  236 236 236  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  2 2 3  2 2 3  11 11 11  19 19 19
+  11 11 11  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  2 2 3  11 11 11
+  140 102 3  11 11 11  10 6 3  67 67 67  254 254 252
+  245 245 245  245 245 245  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  245 245 245  228 228 228  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  245 245 245  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  2 2 3  43 43 43  2 2 3  2 2 3
+  2 2 3  11 11 11  67 67 67  11 11 11  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  185 132 9  242 182 11
+  245 189 11  245 189 11  49 35 5  2 2 3  228 228 228
+  254 254 252  254 254 252  254 254 252  245 245 245  254 254 252
+  254 254 252  254 254 252  254 254 252  228 228 228  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  245 238 222  232 189 94
+  226 186 99  43 43 43  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  59 59 59  2 2 3
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  216 156 8  236 180 22
+  245 189 11  245 189 11  245 189 11  49 35 5  11 11 11
+  212 212 212  245 245 245  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  245 245 245  228 228 228  254 254 252
+  245 245 245  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  245 245 245  254 254 252  254 254 252  229 172 9  246 218 19
+  246 218 19  41 27 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  19 19 19  27 27 27  196 154 14
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  199 140 8  229 172 9  242 182 11
+  245 189 11  245 189 11  245 189 11  244 196 10  2 2 3
+  2 2 3  115 115 115  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  245 245 245  228 228 228  254 254 252
+  254 254 252  245 245 245  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  224 165 9  245 189 11
+  236 196 11  19 19 19  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  11 11 11  236 196 11
+  244 205 11  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  182 126 10  209 156 9  215 150 13
+  193 140 10  207 148 24  216 156 8  242 182 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  209 156 9
+  2 2 3  2 2 3  43 43 43  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  236 236 236  216 156 8  245 189 11
+  229 172 9  64 43 7  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  207 148 7  236 188 10
+  245 189 11  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  180 121 7  216 156 8  242 182 11  236 180 10
+  229 172 9  242 182 11  242 182 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  237 204 14
+  170 126 10  2 2 3  2 2 3  11 11 11  236 236 236
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  204 204 204  196 196 196  216 156 8  236 180 10
+  224 165 9  182 126 10  73 48 6  2 2 3  2 2 3
+  2 2 3  41 27 3  199 140 8  229 172 9  236 180 10
+  245 189 11  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  185 132 9  229 172 9  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  226 188 11  2 2 3  2 2 3  2 2 3  11 11 11
+  245 245 245  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  245 245 245  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  196 196 196  196 196 196  215 150 13  236 180 10
+  229 172 9  201 142 7  185 132 9  180 121 7  173 120 10
+  180 121 7  192 133 7  229 172 9  242 182 11  245 189 11
+  245 189 11  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  180 126 47  224 165 9  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  236 188 10  193 140 10  2 2 3  2 2 3  2 2 3
+  2 2 3  212 212 212  254 254 252  245 245 245  245 245 245
+  254 254 252  254 254 252  254 254 252  245 245 245  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  204 204 204  196 196 196  199 140 8  229 172 9
+  236 180 10  218 164 9  215 150 13  207 148 7  207 148 7
+  216 156 8  229 172 9  245 189 11  245 189 11  245 189 11
+  245 189 11  242 182 11  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  185 132 9  216 156 8  242 182 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  236 196 11  19 19 19  2 2 3  2 2 3
+  2 2 3  11 11 11  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  245 245 245  254 254 252  254 254 252
+  245 245 245  221 221 220  196 196 196  185 132 9  229 172 9
+  242 182 11  229 172 9  224 165 9  218 164 9  224 165 9
+  229 172 9  236 180 10  245 189 11  245 189 11  245 189 11
+  245 189 11  236 180 22  242 182 11  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  236 180 22  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  236 188 10  225 180 10  2 2 3  2 2 3
+  2 2 3  11 11 11  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  221 221 220  19 19 19  185 132 9  224 165 9
+  245 189 11  245 189 11  242 182 11  236 180 10  236 180 10
+  242 182 11  242 182 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  196 154 14
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  207 148 7  236 180 22  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  242 182 11
+  245 189 11  245 189 11  237 204 14  135 88 5  2 2 3
+  27 27 27  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  245 245 245  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  67 67 67  19 13 3  185 132 9  229 172 9
+  242 182 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  236 180 22  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  245 189 11  242 182 11
+  242 182 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  236 188 10  226 188 11  104 83 48
+  254 254 252  254 254 252  254 254 252  254 254 252  245 245 245
+  254 254 252  254 254 252  245 245 245  254 254 252  245 245 245
+  254 254 252  245 245 245  254 254 252  254 254 252  254 254 252
+  2 2 3  2 2 3  56 38 5  185 132 9  229 172 9
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  242 182 11
+  229 172 9  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  182 126 10  215 150 13  242 182 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  242 182 11  245 189 11  236 196 11  216 156 8
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  245 245 245  2 2 3
+  2 2 3  2 2 3  75 54 3  182 126 10  229 172 9
+  242 182 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  229 172 9
+  207 148 24  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  192 133 7  229 172 9  242 182 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  242 182 11  225 180 10  224 165 9
+  107 69 5  245 245 245  254 254 252  254 254 252  254 254 252
+  254 254 252  254 254 252  254 254 252  254 254 252  254 254 252
+  254 254 252  236 236 236  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  91 67 9  182 126 10  229 172 9
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  242 182 11  242 182 11  216 156 8  180 126 47
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  206 142 8  224 165 9  245 189 11  242 182 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  242 182 11
+  245 189 11  245 189 11  242 182 11  242 182 11  216 156 8
+  156 102 5  19 13 3  43 43 43  196 196 196  254 254 252
+  245 245 245  254 254 252  254 254 252  204 204 204  51 51 51
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  95 62 5  185 132 9  229 172 9
+  242 182 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  242 182 11  245 189 11  245 189 11
+  236 180 22  216 156 8  206 142 8  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  192 133 7  215 150 13  229 172 9  229 172 9
+  236 180 10  236 180 22  242 182 11  242 182 11  245 189 11
+  245 189 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  245 189 11  245 189 11  229 172 9  216 156 8
+  156 102 5  83 54 6  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  115 73 3  185 132 9  229 172 9
+  242 182 11  245 189 11  245 189 11  245 189 11  245 189 11
+  245 189 11  242 182 11  229 172 9  229 172 9  216 156 8
+  180 121 7  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  180 121 7  182 126 10  192 133 7  199 140 8
+  207 148 7  215 150 13  216 156 8  224 165 9  229 172 9
+  236 180 22  245 189 11  242 182 11  245 189 11  242 182 11
+  245 189 11  245 189 11  242 182 11  229 172 9  199 140 8
+  151 97 5  101 67 7  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  115 73 3  180 121 7  216 156 8
+  236 180 22  242 182 11  245 189 11  245 189 11  242 182 11
+  236 180 10  224 165 9  215 150 13  206 142 8  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  156 102 5  164 109 5  172 114 5  180 121 7  180 121 7
+  192 133 7  201 142 7  216 156 8  224 165 9  236 180 22
+  245 189 11  242 182 11  229 172 9  201 142 7  172 114 5
+  125 83 5  83 54 6  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  2 2 3  2 2 3  2 2 3
+  2 2 3  2 2 3  91 58 5  156 102 5  192 133 7
+  216 156 8  229 172 9  236 180 10  236 180 10  229 172 9
+  215 150 13  199 140 8  164 109 5  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  120 78 3  132 82 3
+  151 97 5  157 106 7  180 121 7  185 132 9  193 140 10
+  207 148 7  207 148 7  192 133 7  172 114 5  132 82 3
+  101 67 7  41 27 3  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  73 48 6  143 90 3  180 121 7
+  192 133 7  207 148 7  207 148 7  201 142 7  185 132 9
+  173 120 10  136 95 7  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  91 58 5  125 83 5  135 88 5
+  144 95 7  151 97 5  132 82 3  115 73 3  95 62 5
+  64 43 7  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  64 43 7  91 58 5  151 97 5
+  157 106 7  172 114 5  172 114 5  164 109 5  151 97 5
+  85 59 6  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  73 48 6
+  91 58 5  95 62 5  95 62 5  91 58 5  56 38 5
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  83 54 6
+  107 69 5  132 82 3  125 83 5  101 67 7  71 47 31
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
+  215 150 13  215 150 13  215 150 13  215 150 13  215 150 13
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 3dd1de1..b00887e 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -523,7 +523,7 @@
 #define invalidate_cache(addr)
 #endif
 
-static int __devinit platinumfb_probe(struct of_device* odev, const struct of_match *match)
+static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match)
 {
 	struct device_node	*dp = odev->node;
 	struct fb_info		*info;
@@ -647,12 +647,10 @@
 	return 0;
 }
 
-static struct of_match platinumfb_match[] = 
+static struct of_device_id platinumfb_match[] = 
 {
 	{
 	.name 		= "platinum",
-	.type		= OF_ANY_MATCH,
-	.compatible	= OF_ANY_MATCH,
 	},
 	{},
 };
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 789de13..3848be2 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -67,12 +67,18 @@
 static inline u8
 s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno)
 {
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+	regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
+#endif
 	return readb(par->regs + regno);
 }
 
 static inline void
 s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value)
 {
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+	regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
+#endif
 	writeb(value, par->regs + regno);
 }
 
@@ -259,7 +265,11 @@
 			dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n",
 				    regno, pseudo_val);
 
+#if defined(CONFIG_PLAT_MAPPI)
+			((u32 *)info->pseudo_palette)[regno] = cpu_to_le16(pseudo_val);
+#else
 			((u32 *)info->pseudo_palette)[regno] = pseudo_val;
+#endif
 
 			break;
 		case FB_VISUAL_PSEUDOCOLOR:
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 8fadcda..f4633d1 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2113,7 +2113,7 @@
 	printk(KERN_DEBUG "state: %u\n", state);
 
 	acquire_console_sem();
-	fb_set_suspend(info, state);
+	fb_set_suspend(info, pci_choose_state(dev, state));
 	savage_disable_mmio(par);
 	release_console_sem();
 
diff --git a/fs/Kconfig b/fs/Kconfig
index 8d50a61..f93fd41 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -29,6 +29,7 @@
 config EXT2_FS_POSIX_ACL
 	bool "Ext2 POSIX Access Control Lists"
 	depends on EXT2_FS_XATTR
+	select FS_POSIX_ACL
 	help
 	  Posix Access Control Lists (ACLs) support permissions for users and
 	  groups beyond the owner/group/world scheme.
@@ -114,6 +115,7 @@
 config EXT3_FS_POSIX_ACL
 	bool "Ext3 POSIX Access Control Lists"
 	depends on EXT3_FS_XATTR
+	select FS_POSIX_ACL
 	help
 	  Posix Access Control Lists (ACLs) support permissions for users and
 	  groups beyond the owner/group/world scheme.
@@ -241,6 +243,7 @@
 config REISERFS_FS_POSIX_ACL
 	bool "ReiserFS POSIX Access Control Lists"
 	depends on REISERFS_FS_XATTR
+	select FS_POSIX_ACL
 	help
 	  Posix Access Control Lists (ACLs) support permissions for users and
 	  groups beyond the owner/group/world scheme.
@@ -274,6 +277,7 @@
 config JFS_POSIX_ACL
 	bool "JFS POSIX Access Control Lists"
 	depends on JFS_FS
+	select FS_POSIX_ACL
 	help
 	  Posix Access Control Lists (ACLs) support permissions for users and
 	  groups beyond the owner/group/world scheme.
@@ -318,8 +322,7 @@
 # 	Never use this symbol for ifdefs.
 #
 	bool
-	depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || REISERFS_FS_POSIX_ACL || NFSD_V4
-	default y
+	default n
 
 source "fs/xfs/Kconfig"
 
@@ -1430,6 +1433,7 @@
 	select NFSD_TCP
 	select CRYPTO_MD5
 	select CRYPTO
+	select FS_POSIX_ACL
 	help
 	  If you would like to include the NFSv4 server as well as the NFSv2
 	  and NFSv3 servers, say Y here.  This feature is experimental, and
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index fa2348d..3df8628 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -231,8 +231,8 @@
 		int type = (notify == NFY_MOUNT ?
 			autofs_ptype_missing : autofs_ptype_expire_multi);
 
-		DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
-			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify));
+		DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
+			(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
 
 		/* autofs4_notify_daemon() may block */
 		autofs4_notify_daemon(sbi, wq, type);
diff --git a/fs/bio.c b/fs/bio.c
index 3a1472a..ca8f7a8 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -52,7 +52,7 @@
  */
 
 #define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
-static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] = {
+static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
 	BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
 };
 #undef BV
diff --git a/fs/buffer.c b/fs/buffer.c
index 561e63a..6a25d7d 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -513,8 +513,8 @@
  */
 static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
 {
-	static DEFINE_SPINLOCK(page_uptodate_lock);
 	unsigned long flags;
+	struct buffer_head *first;
 	struct buffer_head *tmp;
 	struct page *page;
 	int page_uptodate = 1;
@@ -536,7 +536,9 @@
 	 * two buffer heads end IO at almost the same time and both
 	 * decide that the page is now completely done.
 	 */
-	spin_lock_irqsave(&page_uptodate_lock, flags);
+	first = page_buffers(page);
+	local_irq_save(flags);
+	bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
 	clear_buffer_async_read(bh);
 	unlock_buffer(bh);
 	tmp = bh;
@@ -549,7 +551,8 @@
 		}
 		tmp = tmp->b_this_page;
 	} while (tmp != bh);
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+	bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+	local_irq_restore(flags);
 
 	/*
 	 * If none of the buffers had errors and they are all
@@ -561,7 +564,8 @@
 	return;
 
 still_busy:
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+	bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+	local_irq_restore(flags);
 	return;
 }
 
@@ -572,8 +576,8 @@
 void end_buffer_async_write(struct buffer_head *bh, int uptodate)
 {
 	char b[BDEVNAME_SIZE];
-	static DEFINE_SPINLOCK(page_uptodate_lock);
 	unsigned long flags;
+	struct buffer_head *first;
 	struct buffer_head *tmp;
 	struct page *page;
 
@@ -594,7 +598,10 @@
 		SetPageError(page);
 	}
 
-	spin_lock_irqsave(&page_uptodate_lock, flags);
+	first = page_buffers(page);
+	local_irq_save(flags);
+	bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
+
 	clear_buffer_async_write(bh);
 	unlock_buffer(bh);
 	tmp = bh->b_this_page;
@@ -605,12 +612,14 @@
 		}
 		tmp = tmp->b_this_page;
 	}
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+	bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+	local_irq_restore(flags);
 	end_page_writeback(page);
 	return;
 
 still_busy:
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+	bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+	local_irq_restore(flags);
 	return;
 }
 
diff --git a/fs/dcookies.c b/fs/dcookies.c
index 581aac9..02aa0dd 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -94,12 +94,10 @@
 	if (!dcs)
 		return NULL;
 
-	atomic_inc(&dentry->d_count);
-	atomic_inc(&vfsmnt->mnt_count);
 	dentry->d_cookie = dcs;
 
-	dcs->dentry = dentry;
-	dcs->vfsmnt = vfsmnt;
+	dcs->dentry = dget(dentry);
+	dcs->vfsmnt = mntget(vfsmnt);
 	hash_dcookie(dcs);
 
 	return dcs;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 0b2db4f..9989fdc 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2663,7 +2663,7 @@
 	} else for (block = 0; block < EXT3_N_BLOCKS; block++)
 		raw_inode->i_block[block] = ei->i_data[block];
 
-	if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
+	if (ei->i_extra_isize)
 		raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
 
 	BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index f8e0cbd..6f553e1 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -491,7 +492,7 @@
 		fd = open_host_sock(host_file, &filter);
 		if(fd > 0){
 			data->contents = hppfs_get_data(fd, filter,
-							&data->proc_file,
+							data->proc_file,
 							file, &data->len);
 			if(!IS_ERR(data->contents))
 				data->host_fd = fd;
@@ -543,7 +544,7 @@
 static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
 {
 	struct hppfs_private *data = file->private_data;
-	struct file *proc_file = &data->proc_file;
+	struct file *proc_file = data->proc_file;
 	loff_t (*llseek)(struct file *, loff_t, int);
 	loff_t ret;
 
@@ -586,7 +587,7 @@
 static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
 {
 	struct hppfs_private *data = file->private_data;
-	struct file *proc_file = &data->proc_file;
+	struct file *proc_file = data->proc_file;
 	int (*readdir)(struct file *, void *, filldir_t);
 	struct hppfs_dirent dirent = ((struct hppfs_dirent)
 		                      { .vfs_dirent  	= ent,
diff --git a/fs/inode.c b/fs/inode.c
index 1f9a3a2..6d69503 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1052,7 +1052,7 @@
  * inode when the usage count drops to zero, and
  * i_nlink is zero.
  */
-static void generic_drop_inode(struct inode *inode)
+void generic_drop_inode(struct inode *inode)
 {
 	if (!inode->i_nlink)
 		generic_delete_inode(inode);
@@ -1060,6 +1060,8 @@
 		generic_forget_inode(inode);
 }
 
+EXPORT_SYMBOL_GPL(generic_drop_inode);
+
 /*
  * Called when we're dropping the last reference
  * to an inode. 
diff --git a/fs/ioprio.c b/fs/ioprio.c
index 663e420..97e1f08 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -43,7 +43,7 @@
 	return 0;
 }
 
-asmlinkage int sys_ioprio_set(int which, int who, int ioprio)
+asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
 {
 	int class = IOPRIO_PRIO_CLASS(ioprio);
 	int data = IOPRIO_PRIO_DATA(ioprio);
@@ -115,7 +115,7 @@
 	return ret;
 }
 
-asmlinkage int sys_ioprio_get(int which, int who)
+asmlinkage long sys_ioprio_get(int which, int who)
 {
 	struct task_struct *g, *p;
 	struct user_struct *user;
diff --git a/fs/locks.c b/fs/locks.c
index a0bc034..29fa5da 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1276,7 +1276,7 @@
  */
 static int __setlease(struct file *filp, long arg, struct file_lock **flp)
 {
-	struct file_lock *fl, **before, **my_before = NULL, *lease = *flp;
+	struct file_lock *fl, **before, **my_before = NULL, *lease;
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	int error, rdlease_count = 0, wrlease_count = 0;
@@ -1287,6 +1287,8 @@
 	if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
 		goto out;
 
+	lease = *flp;
+
 	error = -EAGAIN;
 	if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
 		goto out;
diff --git a/fs/namei.c b/fs/namei.c
index fa8df81..1d93cb4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -314,7 +314,7 @@
 void path_release_on_umount(struct nameidata *nd)
 {
 	dput(nd->dentry);
-	_mntput(nd->mnt);
+	mntput_no_expire(nd->mnt);
 }
 
 /*
diff --git a/fs/namespace.c b/fs/namespace.c
index 208c079..587eb0d 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -61,7 +61,7 @@
 		INIT_LIST_HEAD(&mnt->mnt_child);
 		INIT_LIST_HEAD(&mnt->mnt_mounts);
 		INIT_LIST_HEAD(&mnt->mnt_list);
-		INIT_LIST_HEAD(&mnt->mnt_fslink);
+		INIT_LIST_HEAD(&mnt->mnt_expire);
 		if (name) {
 			int size = strlen(name)+1;
 			char *newname = kmalloc(size, GFP_KERNEL);
@@ -165,8 +165,8 @@
 		/* stick the duplicate mount on the same expiry list
 		 * as the original if that was on one */
 		spin_lock(&vfsmount_lock);
-		if (!list_empty(&old->mnt_fslink))
-			list_add(&mnt->mnt_fslink, &old->mnt_fslink);
+		if (!list_empty(&old->mnt_expire))
+			list_add(&mnt->mnt_expire, &old->mnt_expire);
 		spin_unlock(&vfsmount_lock);
 	}
 	return mnt;
@@ -345,12 +345,13 @@
 	for (p = mnt; p; p = next_mnt(p, mnt)) {
 		list_del(&p->mnt_list);
 		list_add(&p->mnt_list, &kill);
+		p->mnt_namespace = NULL;
 	}
 
 	while (!list_empty(&kill)) {
 		mnt = list_entry(kill.next, struct vfsmount, mnt_list);
 		list_del_init(&mnt->mnt_list);
-		list_del_init(&mnt->mnt_fslink);
+		list_del_init(&mnt->mnt_expire);
 		if (mnt->mnt_parent == mnt) {
 			spin_unlock(&vfsmount_lock);
 		} else {
@@ -644,7 +645,7 @@
 	if (mnt) {
 		/* stop bind mounts from expiring */
 		spin_lock(&vfsmount_lock);
-		list_del_init(&mnt->mnt_fslink);
+		list_del_init(&mnt->mnt_expire);
 		spin_unlock(&vfsmount_lock);
 
 		err = graft_tree(mnt, nd);
@@ -743,7 +744,7 @@
 
 	/* if the mount is moved, it should no longer be expire
 	 * automatically */
-	list_del_init(&old_nd.mnt->mnt_fslink);
+	list_del_init(&old_nd.mnt->mnt_expire);
 out2:
 	spin_unlock(&vfsmount_lock);
 out1:
@@ -807,12 +808,13 @@
 		goto unlock;
 
 	newmnt->mnt_flags = mnt_flags;
+	newmnt->mnt_namespace = current->namespace;
 	err = graft_tree(newmnt, nd);
 
 	if (err == 0 && fslist) {
 		/* add to the specified expiration list */
 		spin_lock(&vfsmount_lock);
-		list_add_tail(&newmnt->mnt_fslink, fslist);
+		list_add_tail(&newmnt->mnt_expire, fslist);
 		spin_unlock(&vfsmount_lock);
 	}
 
@@ -824,6 +826,54 @@
 
 EXPORT_SYMBOL_GPL(do_add_mount);
 
+static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
+{
+	spin_lock(&vfsmount_lock);
+
+	/*
+	 * Check if mount is still attached, if not, let whoever holds it deal
+	 * with the sucker
+	 */
+	if (mnt->mnt_parent == mnt) {
+		spin_unlock(&vfsmount_lock);
+		return;
+	}
+
+	/*
+	 * Check that it is still dead: the count should now be 2 - as
+	 * contributed by the vfsmount parent and the mntget above
+	 */
+	if (atomic_read(&mnt->mnt_count) == 2) {
+		struct nameidata old_nd;
+
+		/* delete from the namespace */
+		list_del_init(&mnt->mnt_list);
+		mnt->mnt_namespace = NULL;
+		detach_mnt(mnt, &old_nd);
+		spin_unlock(&vfsmount_lock);
+		path_release(&old_nd);
+
+		/*
+		 * Now lay it to rest if this was the last ref on the superblock
+		 */
+		if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
+			/* last instance - try to be smart */
+			lock_kernel();
+			DQUOT_OFF(mnt->mnt_sb);
+			acct_auto_close(mnt->mnt_sb);
+			unlock_kernel();
+		}
+		mntput(mnt);
+	} else {
+		/*
+		 * Someone brought it back to life whilst we didn't have any
+		 * locks held so return it to the expiration list
+		 */
+		list_add_tail(&mnt->mnt_expire, mounts);
+		spin_unlock(&vfsmount_lock);
+	}
+}
+
 /*
  * process a list of expirable mountpoints with the intent of discarding any
  * mountpoints that aren't in use and haven't been touched since last we came
@@ -846,13 +896,13 @@
 	 * - still marked for expiry (marked on the last call here; marks are
 	 *   cleared by mntput())
 	 */
-	list_for_each_entry_safe(mnt, next, mounts, mnt_fslink) {
+	list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
 		if (!xchg(&mnt->mnt_expiry_mark, 1) ||
 		    atomic_read(&mnt->mnt_count) != 1)
 			continue;
 
 		mntget(mnt);
-		list_move(&mnt->mnt_fslink, &graveyard);
+		list_move(&mnt->mnt_expire, &graveyard);
 	}
 
 	/*
@@ -862,61 +912,19 @@
 	 * - dispose of the corpse
 	 */
 	while (!list_empty(&graveyard)) {
-		mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink);
-		list_del_init(&mnt->mnt_fslink);
+		mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
+		list_del_init(&mnt->mnt_expire);
 
 		/* don't do anything if the namespace is dead - all the
 		 * vfsmounts from it are going away anyway */
 		namespace = mnt->mnt_namespace;
-		if (!namespace || atomic_read(&namespace->count) <= 0)
+		if (!namespace || !namespace->root)
 			continue;
 		get_namespace(namespace);
 
 		spin_unlock(&vfsmount_lock);
 		down_write(&namespace->sem);
-		spin_lock(&vfsmount_lock);
-
-		/* check that it is still dead: the count should now be 2 - as
-		 * contributed by the vfsmount parent and the mntget above */
-		if (atomic_read(&mnt->mnt_count) == 2) {
-			struct vfsmount *xdmnt;
-			struct dentry *xdentry;
-
-			/* delete from the namespace */
-			list_del_init(&mnt->mnt_list);
-			list_del_init(&mnt->mnt_child);
-			list_del_init(&mnt->mnt_hash);
-			mnt->mnt_mountpoint->d_mounted--;
-
-			xdentry = mnt->mnt_mountpoint;
-			mnt->mnt_mountpoint = mnt->mnt_root;
-			xdmnt = mnt->mnt_parent;
-			mnt->mnt_parent = mnt;
-
-			spin_unlock(&vfsmount_lock);
-
-			mntput(xdmnt);
-			dput(xdentry);
-
-			/* now lay it to rest if this was the last ref on the
-			 * superblock */
-			if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
-				/* last instance - try to be smart */
-				lock_kernel();
-				DQUOT_OFF(mnt->mnt_sb);
-				acct_auto_close(mnt->mnt_sb);
-				unlock_kernel();
-			}
-
-			mntput(mnt);
-		} else {
-			/* someone brought it back to life whilst we didn't
-			 * have any locks held so return it to the expiration
-			 * list */
-			list_add_tail(&mnt->mnt_fslink, mounts);
-			spin_unlock(&vfsmount_lock);
-		}
-
+		expire_mount(mnt, mounts);
 		up_write(&namespace->sem);
 
 		mntput(mnt);
@@ -1449,16 +1457,12 @@
 
 void __put_namespace(struct namespace *namespace)
 {
-	struct vfsmount *mnt;
-
+	struct vfsmount *root = namespace->root;
+	namespace->root = NULL;
+	spin_unlock(&vfsmount_lock);
 	down_write(&namespace->sem);
 	spin_lock(&vfsmount_lock);
-
-	list_for_each_entry(mnt, &namespace->list, mnt_list) {
-		mnt->mnt_namespace = NULL;
-	}
-
-	umount_tree(namespace->root);
+	umount_tree(root);
 	spin_unlock(&vfsmount_lock);
 	up_write(&namespace->sem);
 	kfree(namespace);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index d71f145..e08edc1 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -169,12 +169,6 @@
 		(int)open->op_fname.len, open->op_fname.data,
 		open->op_stateowner);
 
-	if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
-		return nfserr_grace;
-
-	if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
-		return nfserr_no_grace;
-
 	/* This check required by spec. */
 	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
 		return nfserr_inval;
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 095f174..57ed50f 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -119,25 +119,12 @@
 	return status;
 }
 
-static int
-nfsd4_rec_fsync(struct dentry *dentry)
+static void
+nfsd4_sync_rec_dir(void)
 {
-	struct file *filp;
-	int status = nfs_ok;
-
-	dprintk("NFSD: nfs4_fsync_rec_dir\n");
-	filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR);
-	if (IS_ERR(filp)) {
-		status = PTR_ERR(filp);
-		goto out;
-	}
-	if (filp->f_op && filp->f_op->fsync)
-		status = filp->f_op->fsync(filp, filp->f_dentry, 0);
-	fput(filp);
-out:
-	if (status)
-		printk("nfsd4: unable to sync recovery directory\n");
-	return status;
+	down(&rec_dir.dentry->d_inode->i_sem);
+	nfsd_sync_dir(rec_dir.dentry);
+	up(&rec_dir.dentry->d_inode->i_sem);
 }
 
 int
@@ -176,7 +163,7 @@
 	up(&rec_dir.dentry->d_inode->i_sem);
 	if (status == 0) {
 		clp->cl_firststate = 1;
-		status = nfsd4_rec_fsync(rec_dir.dentry);
+		nfsd4_sync_rec_dir();
 	}
 	nfs4_reset_user(uid, gid);
 	dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
@@ -302,7 +289,9 @@
 
 	dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
 
+	down(&rec_dir.dentry->d_inode->i_sem);
 	dentry = lookup_one_len(name, rec_dir.dentry, namlen);
+	up(&rec_dir.dentry->d_inode->i_sem);
 	if (IS_ERR(dentry)) {
 		status = PTR_ERR(dentry);
 		return status;
@@ -327,11 +316,12 @@
 	if (!rec_dir_init || !clp->cl_firststate)
 		return;
 
+	clp->cl_firststate = 0;
 	nfs4_save_user(&uid, &gid);
 	status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
 	nfs4_reset_user(uid, gid);
 	if (status == 0)
-		status = nfsd4_rec_fsync(rec_dir.dentry);
+		nfsd4_sync_rec_dir();
 	if (status)
 		printk("NFSD: Failed to remove expired client state directory"
 				" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
@@ -362,7 +352,7 @@
 		return;
 	status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
 	if (status == 0)
-		status = nfsd4_rec_fsync(rec_dir.dentry);
+		nfsd4_sync_rec_dir();
 	if (status)
 		printk("nfsd4: failed to purge old clients from recovery"
 			" directory %s\n", rec_dir.dentry->d_name.name);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 89e3652..b83f8fb 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -874,6 +874,7 @@
 			  * change request correctly. */
 			atomic_set(&conf->cl_callback.cb_set, 0);
 			gen_confirm(conf);
+			nfsd4_remove_clid_dir(unconf);
 			expire_client(unconf);
 			status = nfs_ok;
 
@@ -1159,6 +1160,7 @@
 	stp->st_deny_bmap = 0;
 	__set_bit(open->op_share_access, &stp->st_access_bmap);
 	__set_bit(open->op_share_deny, &stp->st_deny_bmap);
+	stp->st_openstp = NULL;
 }
 
 static void
@@ -1294,7 +1296,7 @@
 	fp = find_file(ino);
 	if (!fp)
 		return nfs_ok;
-	ret = nfserr_share_denied;
+	ret = nfserr_locked;
 	/* Search for conflicting share reservations */
 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
 		if (test_bit(deny_type, &stp->st_deny_bmap) ||
@@ -1482,7 +1484,7 @@
 	if (sop) {
 		open->op_stateowner = sop;
 		/* check for replay */
-		if (open->op_seqid == sop->so_seqid){
+		if (open->op_seqid == sop->so_seqid - 1){
 			if (sop->so_replay.rp_buflen)
 				return NFSERR_REPLAY_ME;
 			else {
@@ -1497,7 +1499,7 @@
 				goto renew;
 			}
 		} else if (sop->so_confirmed) {
-			if (open->op_seqid == sop->so_seqid + 1)
+			if (open->op_seqid == sop->so_seqid)
 				goto renew;
 			status = nfserr_bad_seqid;
 			goto out;
@@ -1530,8 +1532,6 @@
 	status = nfs_ok;
 	renew_client(sop->so_client);
 out:
-	if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
-		status = nfserr_reclaim_bad;
 	return status;
 }
 
@@ -1685,19 +1685,11 @@
 }
 
 
-/* decrement seqid on successful reclaim, it will be bumped in encode_open */
 static void
-nfs4_set_claim_prev(struct nfsd4_open *open, int *status)
+nfs4_set_claim_prev(struct nfsd4_open *open)
 {
-	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
-		if (*status)
-			*status = nfserr_reclaim_bad;
-		else {
-			open->op_stateowner->so_confirmed = 1;
-			open->op_stateowner->so_client->cl_firststate = 1;
-			open->op_stateowner->so_seqid--;
-		}
-	}
+	open->op_stateowner->so_confirmed = 1;
+	open->op_stateowner->so_client->cl_firststate = 1;
 }
 
 /*
@@ -1789,6 +1781,12 @@
 	struct nfs4_delegation *dp = NULL;
 	int status;
 
+	if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+		return nfserr_grace;
+
+	if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+		return nfserr_no_grace;
+
 	status = nfserr_inval;
 	if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
 		goto out;
@@ -1823,6 +1821,7 @@
 		status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
 		if (status)
 			goto out;
+		update_stateid(&stp->st_stateid);
 	} else {
 		/* Stateid was not found, this is a new OPEN */
 		int flags = 0;
@@ -1856,8 +1855,8 @@
 out:
 	if (fp)
 		put_nfs4_file(fp);
-	/* CLAIM_PREVIOUS has different error returns */
-	nfs4_set_claim_prev(open, &status);
+	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+		nfs4_set_claim_prev(open);
 	/*
 	* To finish the open response, we just need to set the rflags.
 	*/
@@ -1990,14 +1989,11 @@
 	queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
 }
 
-/* search ownerid_hashtbl[] and close_lru for stateid owner
- * (stateid->si_stateownerid)
- */
 static struct nfs4_stateowner *
-find_openstateowner_id(u32 st_id, int flags) {
+search_close_lru(u32 st_id, int flags)
+{
 	struct nfs4_stateowner *local = NULL;
 
-	dprintk("NFSD: find_openstateowner_id %d\n", st_id);
 	if (flags & CLOSE_STATE) {
 		list_for_each_entry(local, &close_lru, so_close_lru) {
 			if (local->so_id == st_id)
@@ -2163,14 +2159,19 @@
 	return status;
 }
 
+static inline int
+setlkflg (int type)
+{
+	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
+		RD_STATE : WR_STATE;
+}
 
 /* 
  * Checks for sequence id mutating operations. 
  */
 static int
-nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
+nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
 {
-	int status;
 	struct nfs4_stateid *stp;
 	struct nfs4_stateowner *sop;
 
@@ -2178,53 +2179,65 @@
 			"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
 		stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
 		stateid->si_generation);
-			        
+
 	*stpp = NULL;
 	*sopp = NULL;
 
-	status = nfserr_bad_stateid;
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
 		printk("NFSD: preprocess_seqid_op: magic stateid!\n");
-		goto out;
+		return nfserr_bad_stateid;
 	}
 
-	status = nfserr_stale_stateid;
 	if (STALE_STATEID(stateid))
-		goto out;
+		return nfserr_stale_stateid;
 	/*
 	* We return BAD_STATEID if filehandle doesn't match stateid, 
 	* the confirmed flag is incorrecly set, or the generation 
 	* number is incorrect.  
-	* If there is no entry in the openfile table for this id, 
-	* we can't always return BAD_STATEID;
-	* this might be a retransmitted CLOSE which has arrived after 
-	* the openfile has been released.
 	*/
-	if (!(stp = find_stateid(stateid, flags)))
-		goto no_nfs4_stateid;
+	stp = find_stateid(stateid, flags);
+	if (stp == NULL) {
+		/*
+		 * Also, we should make sure this isn't just the result of
+		 * a replayed close:
+		 */
+		sop = search_close_lru(stateid->si_stateownerid, flags);
+		if (sop == NULL)
+			return nfserr_bad_stateid;
+		*sopp = sop;
+		goto check_replay;
+	}
 
-	status = nfserr_bad_stateid;
-
-	/* for new lock stateowners:
-	 * check that the lock->v.new.open_stateid
-	 * refers to an open stateowner
-	 *
-	 * check that the lockclid (nfs4_lock->v.new.clientid) is the same
-	 * as the open_stateid->st_stateowner->so_client->clientid
-	 */
-	if (lockclid) {
+	if (lock) {
 		struct nfs4_stateowner *sop = stp->st_stateowner;
+		clientid_t *lockclid = &lock->v.new.clientid;
 		struct nfs4_client *clp = sop->so_client;
+		int lkflg = 0;
+		int status;
 
-		if (!sop->so_is_open_owner)
-			goto out;
-		if (!cmp_clid(&clp->cl_clientid, lockclid))
-			goto out;
+		lkflg = setlkflg(lock->lk_type);
+
+		if (lock->lk_is_new) {
+                       if (!sop->so_is_open_owner)
+			       return nfserr_bad_stateid;
+                       if (!cmp_clid(&clp->cl_clientid, lockclid))
+			       return nfserr_bad_stateid;
+                       /* stp is the open stateid */
+                       status = nfs4_check_openmode(stp, lkflg);
+                       if (status)
+			       return status;
+               } else {
+                       /* stp is the lock stateid */
+                       status = nfs4_check_openmode(stp->st_openstp, lkflg);
+                       if (status)
+			       return status;
+               }
+
 	}
 
 	if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
 		printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
-		goto out;
+		return nfserr_bad_stateid;
 	}
 
 	*stpp = stp;
@@ -2235,63 +2248,41 @@
 	*  For the moment, we ignore the possibility of 
 	*  generation number wraparound.
 	*/
-	if (seqid != sop->so_seqid + 1)
+	if (seqid != sop->so_seqid)
 		goto check_replay;
 
-	if (sop->so_confirmed) {
-		if (flags & CONFIRM) {
-			printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
-			goto out;
-		}
+	if (sop->so_confirmed && flags & CONFIRM) {
+		printk("NFSD: preprocess_seqid_op: expected"
+				" unconfirmed stateowner!\n");
+		return nfserr_bad_stateid;
 	}
-	else {
-		if (!(flags & CONFIRM)) {
-			printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
-			goto out;
-		}
+	if (!sop->so_confirmed && !(flags & CONFIRM)) {
+		printk("NFSD: preprocess_seqid_op: stateowner not"
+				" confirmed yet!\n");
+		return nfserr_bad_stateid;
 	}
 	if (stateid->si_generation > stp->st_stateid.si_generation) {
 		printk("NFSD: preprocess_seqid_op: future stateid?!\n");
-		goto out;
+		return nfserr_bad_stateid;
 	}
 
-	status = nfserr_old_stateid;
 	if (stateid->si_generation < stp->st_stateid.si_generation) {
 		printk("NFSD: preprocess_seqid_op: old stateid!\n");
-		goto out;
+		return nfserr_old_stateid;
 	}
-	/* XXX renew the client lease here */
-	status = nfs_ok;
-
-out:
-	return status;
-
-no_nfs4_stateid:
-
-	/*
-	* We determine whether this is a bad stateid or a replay, 
-	* starting by trying to look up the stateowner.
-	* If stateowner is not found - stateid is bad.
-	*/
-	if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
-		printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
-		status = nfserr_bad_stateid;
-		goto out;
-	}
-	*sopp = sop;
+	renew_client(sop->so_client);
+	return nfs_ok;
 
 check_replay:
-	if (seqid == sop->so_seqid) {
+	if (seqid == sop->so_seqid - 1) {
 		printk("NFSD: preprocess_seqid_op: retransmission?\n");
 		/* indicate replay to calling function */
-		status = NFSERR_REPLAY_ME;
-	} else  {
-		printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
-
-		*sopp = NULL;
-		status = nfserr_bad_seqid;
+		return NFSERR_REPLAY_ME;
 	}
-	goto out;
+	printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+			sop->so_seqid, seqid);
+	*sopp = NULL;
+	return nfserr_bad_seqid;
 }
 
 int
@@ -2609,7 +2600,6 @@
  * occured. 
  *
  * strhashval = lock_ownerstr_hashval 
- * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode 
  */
 
 static struct nfs4_stateowner *
@@ -2634,7 +2624,7 @@
 	sop->so_is_open_owner = 0;
 	sop->so_id = current_ownerid++;
 	sop->so_client = clp;
-	sop->so_seqid = lock->lk_new_lock_seqid - 1;
+	sop->so_seqid = lock->lk_new_lock_seqid;
 	sop->so_confirmed = 1;
 	rp = &sop->so_replay;
 	rp->rp_status = NFSERR_SERVERFAULT;
@@ -2669,6 +2659,7 @@
 	stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
 	stp->st_access_bmap = open_stp->st_access_bmap;
 	stp->st_deny_bmap = open_stp->st_deny_bmap;
+	stp->st_openstp = open_stp;
 
 out:
 	return stp;
@@ -2699,22 +2690,17 @@
 		(long long) lock->lk_offset,
 		(long long) lock->lk_length);
 
-	if (nfs4_in_grace() && !lock->lk_reclaim)
-		return nfserr_grace;
-	if (!nfs4_in_grace() && lock->lk_reclaim)
-		return nfserr_no_grace;
-
 	if (check_lock_length(lock->lk_offset, lock->lk_length))
 		 return nfserr_inval;
 
 	nfs4_lock_state();
 
 	if (lock->lk_is_new) {
-	/*
-	 * Client indicates that this is a new lockowner.
-	 * Use open owner and open stateid to create lock owner and lock 
-	 * stateid.
-	 */
+		/*
+		 * Client indicates that this is a new lockowner.
+		 * Use open owner and open stateid to create lock owner and
+		 * lock stateid.
+		 */
 		struct nfs4_stateid *open_stp = NULL;
 		struct nfs4_file *fp;
 		
@@ -2724,23 +2710,14 @@
 			goto out;
 		}
 
-		/* is the new lock seqid presented by the client zero? */
-		status = nfserr_bad_seqid;
-		if (lock->v.new.lock_seqid != 0)
-			goto out;
-
 		/* validate and update open stateid and open seqid */
 		status = nfs4_preprocess_seqid_op(current_fh, 
 				        lock->lk_new_open_seqid,
 		                        &lock->lk_new_open_stateid,
 		                        CHECK_FH | OPEN_STATE,
-		                        &open_sop, &open_stp,
-					&lock->v.new.clientid);
-		if (status) {
-			if (lock->lk_reclaim)
-				status = nfserr_reclaim_bad;
+		                        &open_sop, &open_stp, lock);
+		if (status)
 			goto out;
-		}
 		/* create lockowner and lock stateid */
 		fp = open_stp->st_file;
 		strhashval = lock_ownerstr_hashval(fp->fi_inode, 
@@ -2766,7 +2743,7 @@
 				       lock->lk_old_lock_seqid, 
 				       &lock->lk_old_lock_stateid, 
 				       CHECK_FH | LOCK_STATE, 
-				       &lock->lk_stateowner, &lock_stp, NULL);
+				       &lock->lk_stateowner, &lock_stp, lock);
 		if (status)
 			goto out;
 	}
@@ -2778,6 +2755,13 @@
 		goto out;
 	}
 
+	status = nfserr_grace;
+	if (nfs4_in_grace() && !lock->lk_reclaim)
+		goto out;
+	status = nfserr_no_grace;
+	if (!nfs4_in_grace() && lock->lk_reclaim)
+		goto out;
+
 	locks_init_lock(&file_lock);
 	switch (lock->lk_type) {
 		case NFS4_READ_LT:
@@ -2844,10 +2828,10 @@
 out_destroy_new_stateid:
 	if (lock->lk_is_new) {
 		dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
-	/*
-	* An error encountered after instantiation of the new
-	* stateid has forced us to destroy it.
-	*/
+		/*
+		 * An error encountered after instantiation of the new
+		 * stateid has forced us to destroy it.
+		 */
 		if (!seqid_mutating_err(status))
 			open_sop->so_seqid--;
 
@@ -3083,7 +3067,12 @@
 	 * of the lockowner state released; so don't release any until all
 	 * have been checked. */
 	status = nfs_ok;
-	list_for_each_entry(sop, &matches, so_perclient) {
+	while (!list_empty(&matches)) {
+		sop = list_entry(matches.next, struct nfs4_stateowner,
+								so_perclient);
+		/* unhash_stateowner deletes so_perclient only
+		 * for openowners. */
+		list_del(&sop->so_perclient);
 		release_stateowner(sop);
 	}
 out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 91fb171..4c41463 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1210,16 +1210,15 @@
 	save = resp->p;
 
 /*
- * Routine for encoding the result of a
- * "seqid-mutating" NFSv4 operation.  This is
- * where seqids are incremented, and the
- * replay cache is filled.
+ * Routine for encoding the result of a "seqid-mutating" NFSv4 operation.  This
+ * is where sequence id's are incremented, and the replay cache is filled.
+ * Note that we increment sequence id's here, at the last moment, so we're sure
+ * we know whether the error to be returned is a sequence id mutating error.
  */
 
 #define ENCODE_SEQID_OP_TAIL(stateowner) do {			\
 	if (seqid_mutating_err(nfserr) && stateowner) { 	\
-		if (stateowner->so_confirmed)			\
-			stateowner->so_seqid++;			\
+		stateowner->so_seqid++;				\
 		stateowner->so_replay.rp_status = nfserr;   	\
 		stateowner->so_replay.rp_buflen = 		\
 			  (((char *)(resp)->p - (char *)save)); \
@@ -1367,9 +1366,9 @@
 		if ((buflen -= 4) < 0)
 			goto out_resource;
 		if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
-			WRITE32(NFS4_FH_VOLATILE_ANY);
+			WRITE32(NFS4_FH_PERSISTENT);
 		else
-			WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME);
+			WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
 	}
 	if (bmval0 & FATTR4_WORD0_CHANGE) {
 		/*
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index be24ead..5e0bf391 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -733,7 +733,7 @@
 	up(&inode->i_sem);
 }
 
-static void
+void
 nfsd_sync_dir(struct dentry *dp)
 {
 	nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
diff --git a/fs/super.c b/fs/super.c
index 25bc1ec..6e57ee2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -840,7 +840,6 @@
 	mnt->mnt_root = dget(sb->s_root);
 	mnt->mnt_mountpoint = sb->s_root;
 	mnt->mnt_parent = mnt;
-	mnt->mnt_namespace = current->namespace;
 	up_write(&sb->s_umount);
 	free_secdata(secdata);
 	put_filesystem(type);
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 408aea5..e139463 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -132,6 +132,8 @@
 #define __S110	_PAGE_S(0)
 #define __S111	_PAGE_S(0)
 
+#define pgprot_noncached(prot)	(prot)
+
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
  * BAD_PAGE is used for a bogus page.
diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h
index 52ded51..c0caf3e 100644
--- a/include/asm-arm/arch-ixp2000/platform.h
+++ b/include/asm-arm/arch-ixp2000/platform.h
@@ -115,6 +115,7 @@
 }
 
 void ixp2000_map_io(void);
+void ixp2000_uart_init(void);
 void ixp2000_init_irq(void);
 void ixp2000_init_time(unsigned long);
 unsigned long ixp2000_gettimeoffset(void);
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index c27b9d3..7495026 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -3,7 +3,7 @@
  *
  * Author: Deepak Saxena <dsaxena@plexity.net>
  *
- * Copyright (C) 2002-2004  MontaVista Software, Inc.
+ * Copyright (C) 2002-2005  MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -383,6 +383,180 @@
 		*vaddr++ = inl(io_addr);
 }
 
+#define	__is_io_address(p)	(((unsigned long)p >= 0x0) && \
+					((unsigned long)p <= 0x0000ffff))
+static inline unsigned int
+__ixp4xx_ioread8(void __iomem *port)
+{
+	if (__is_io_address(port))
+		return	(unsigned int)__ixp4xx_inb((unsigned int)port);
+	else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		return (unsigned int)__raw_readb((u32)port);
+#else
+		return (unsigned int)__ixp4xx_readb((u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_ioread8_rep(u32 port, u8 *vaddr, u32 count)
+{
+	if (__is_io_address(port))
+		__ixp4xx_insb(port, vaddr, count);
+	else
+#ifndef	CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_readsb((void __iomem *)port, vaddr, count);
+#else
+		__ixp4xx_readsb(port, vaddr, count);
+#endif
+}
+
+static inline unsigned int
+__ixp4xx_ioread16(void __iomem *port)
+{
+	if (__is_io_address(port))
+		return	(unsigned int)__ixp4xx_inw((unsigned int)port);
+	else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		return le16_to_cpu(__raw_readw((u32)port));
+#else
+		return (unsigned int)__ixp4xx_readw((u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_ioread16_rep(u32 port, u16 *vaddr, u32 count)
+{
+	if (__is_io_address(port))
+		__ixp4xx_insw(port, vaddr, count);
+	else
+#ifndef	CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_readsw((void __iomem *)port, vaddr, count);
+#else
+		__ixp4xx_readsw(port, vaddr, count);
+#endif
+}
+
+static inline unsigned int
+__ixp4xx_ioread32(void __iomem *port)
+{
+	if (__is_io_address(port))
+		return	(unsigned int)__ixp4xx_inl((unsigned int)port);
+	else {
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		return le32_to_cpu(__raw_readl((u32)port));
+#else
+		return (unsigned int)__ixp4xx_readl((u32)port);
+#endif
+	}
+}
+
+static inline void
+__ixp4xx_ioread32_rep(u32 port, u32 *vaddr, u32 count)
+{
+	if (__is_io_address(port))
+		__ixp4xx_insl(port, vaddr, count);
+	else
+#ifndef	CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_readsl((void __iomem *)port, vaddr, count);
+#else
+		__ixp4xx_readsl(port, vaddr, count);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite8(u8 value, void __iomem *port)
+{
+	if (__is_io_address(port))
+		__ixp4xx_outb(value, (unsigned int)port);
+	else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_writeb(value, (u32)port);
+#else
+		__ixp4xx_writeb(value, (u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite8_rep(u32 port, u8 *vaddr, u32 count)
+{
+	if (__is_io_address(port))
+		__ixp4xx_outsb(port, vaddr, count);
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_writesb((void __iomem *)port, vaddr, count);
+#else
+		__ixp4xx_writesb(port, vaddr, count);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite16(u16 value, void __iomem *port)
+{
+	if (__is_io_address(port))
+		__ixp4xx_outw(value, (unsigned int)port);
+	else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_writew(cpu_to_le16(value), (u32)port);
+#else
+		__ixp4xx_writew(value, (u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite16_rep(u32 port, u16 *vaddr, u32 count)
+{
+	if (__is_io_address(port))
+		__ixp4xx_outsw(port, vaddr, count);
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_readsw((void __iomem *)port, vaddr, count);
+#else
+		__ixp4xx_writesw(port, vaddr, count);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite32(u32 value, void __iomem *port)
+{
+	if (__is_io_address(port))
+		__ixp4xx_outl(value, (unsigned int)port);
+	else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_writel(cpu_to_le32(value), (u32)port);
+#else
+		__ixp4xx_writel(value, (u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite32_rep(u32 port, u32 *vaddr, u32 count)
+{
+	if (__is_io_address(port))
+		__ixp4xx_outsl(port, vaddr, count);
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+		__raw_readsl((void __iomem *)port, vaddr, count);
+#else
+		__ixp4xx_outsl(port, vaddr, count);
+#endif
+}
+
+#define	ioread8(p)			__ixp4xx_ioread8(p)
+#define	ioread16(p)			__ixp4xx_ioread16(p)
+#define	ioread32(p)			__ixp4xx_ioread32(p)
+
+#define	ioread8_rep(p, v, c)		__ixp4xx_ioread8_rep(p, v, c)
+#define	ioread16_rep(p, v, c)		__ixp4xx_ioread16_rep(p, v, c)
+#define	ioread32_rep(p, v, c)		__ixp4xx_ioread32_rep(p, v, c)
+
+#define	iowrite8(v,p)			__ixp4xx_iowrite8(v,p)
+#define	iowrite16(v,p)			__ixp4xx_iowrite16(v,p)
+#define	iowrite32(v,p)			__ixp4xx_iowrite32(v,p)
+
+#define	iowrite8_rep(p, v, c)		__ixp4xx_iowrite8_rep(p, v, c)
+#define	iowrite16_rep(p, v, c)		__ixp4xx_iowrite16_rep(p, v, c)
+#define	iowrite32_rep(p, v, c)		__ixp4xx_iowrite32_rep(p, v, c)
+
+#define	ioport_map(port, nr)		((void __iomem*)port)
+#define	ioport_unmap(addr)
 
 #endif	//  __ASM_ARM_ARCH_IO_H
 
diff --git a/include/asm-arm/arch-omap/board-h2.h b/include/asm-arm/arch-omap/board-h2.h
index 60f002b..39ca5a3 100644
--- a/include/asm-arm/arch-omap/board-h2.h
+++ b/include/asm-arm/arch-omap/board-h2.h
@@ -34,11 +34,6 @@
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
 #define OMAP1610_ETHR_START		0x04000300
 
-/* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
-#define OMAP_NOR_FLASH_SIZE             SZ_32M
-#define OMAP_NOR_FLASH_START1           0x0C000000 /* CS3 */
-#define OMAP_NOR_FLASH_START2           0x0A000000 /* CS2B */
-
 /* Samsung NAND flash at CS2B or CS3(NAND Boot) */
 #define OMAP_NAND_FLASH_START1           0x0A000000 /* CS2B */
 #define OMAP_NAND_FLASH_START2           0x0C000000 /* CS3 */
diff --git a/include/asm-arm/arch-omap/board-h3.h b/include/asm-arm/arch-omap/board-h3.h
index e4d1cd2..1b12c1d 100644
--- a/include/asm-arm/arch-omap/board-h3.h
+++ b/include/asm-arm/arch-omap/board-h3.h
@@ -30,11 +30,6 @@
 /* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
 #define OMAP1710_ETHR_START		0x04000300
 
-/* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
-#define OMAP_NOR_FLASH_SIZE             SZ_32M
-#define OMAP_NOR_FLASH_START1 		0x0C000000 /* CS3 */
-#define OMAP_NOR_FLASH_START2 		0x0A000000 /* CS2B */
-
 /* Samsung NAND flash at CS2B or CS3(NAND Boot) */
 #define OMAP_NAND_FLASH_START1           0x0A000000 /* CS2B */
 #define OMAP_NAND_FLASH_START2           0x0C000000 /* CS3 */
diff --git a/include/asm-arm/arch-omap/board-osk.h b/include/asm-arm/arch-omap/board-osk.h
index aaa49a0..2b1a8a4 100644
--- a/include/asm-arm/arch-omap/board-osk.h
+++ b/include/asm-arm/arch-omap/board-osk.h
@@ -32,10 +32,5 @@
 /* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
 #define OMAP_OSK_ETHR_START		0x04800300
 
-/* Micron NOR flash at CS3 mapped to address 0x0 if BM bit is 1 */
-#define OMAP_OSK_NOR_FLASH_BASE		0xD8000000
-#define OMAP_OSK_NOR_FLASH_SIZE		SZ_32M
-#define OMAP_OSK_NOR_FLASH_START	0x00000000
-
 #endif /*  __ASM_ARCH_OMAP_OSK_H */
 
diff --git a/include/asm-arm/arch-omap/board.h b/include/asm-arm/arch-omap/board.h
index 1cefd60..95bd625 100644
--- a/include/asm-arm/arch-omap/board.h
+++ b/include/asm-arm/arch-omap/board.h
@@ -16,10 +16,11 @@
 /* Different peripheral ids */
 #define OMAP_TAG_CLOCK		0x4f01
 #define OMAP_TAG_MMC		0x4f02
-#define OMAP_TAG_UART		0x4f03
+#define OMAP_TAG_SERIAL_CONSOLE 0x4f03
 #define OMAP_TAG_USB		0x4f04
 #define OMAP_TAG_LCD		0x4f05
 #define OMAP_TAG_GPIO_SWITCH	0x4f06
+#define OMAP_TAG_UART		0x4f07
 
 #define OMAP_TAG_BOOT_REASON    0x4f80
 #define OMAP_TAG_FLASH_PART	0x4f81
@@ -35,7 +36,7 @@
 	s16 mmc1_switch_pin, mmc2_switch_pin;
 };
 
-struct omap_uart_config {
+struct omap_serial_console_config {
 	u8 console_uart;
 	u32 console_speed;
 };
@@ -82,7 +83,8 @@
  */
 #define OMAP_GPIO_SWITCH_TYPE_COVER		0x0000
 #define OMAP_GPIO_SWITCH_TYPE_CONNECTION	0x0001
-#define OMAP_GPIO_SWITCH_FLAG_INVERTED          0x0001
+#define OMAP_GPIO_SWITCH_FLAG_INVERTED		0x0001
+#define OMAP_GPIO_SWITCH_FLAG_OUTPUT		0x0002
 struct omap_gpio_switch_config {
 	char name[12];
 	u16 gpio;
@@ -99,6 +101,10 @@
 	char reason_str[12];
 };
 
+struct omap_uart_config {
+	/* Bit field of UARTs present; bit 0 --> UART1 */
+	unsigned int enabled_uarts;
+};
 
 struct omap_board_config_entry {
 	u16 tag;
diff --git a/arch/arm/mach-omap/common.h b/include/asm-arm/arch-omap/common.h
similarity index 94%
rename from arch/arm/mach-omap/common.h
rename to include/asm-arm/arch-omap/common.h
index 9f62858..2a676b4 100644
--- a/arch/arm/mach-omap/common.h
+++ b/include/asm-arm/arch-omap/common.h
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/common.h
+ * linux/include/asm-arm/arch-omap/common.h
  *
  * Header for code common to all OMAP machines.
  *
@@ -29,7 +29,7 @@
 
 struct sys_timer;
 
-extern void omap_map_io(void);
+extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
 extern void omap_serial_init(int ports[]);
 
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index d785248..ce114ce 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -241,6 +241,7 @@
 extern dma_addr_t omap_get_dma_src_pos(int lch);
 extern dma_addr_t omap_get_dma_dst_pos(int lch);
 extern void omap_clear_dma(int lch);
+extern int omap_dma_running(void);
 
 /* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */
 extern int omap_dma_in_1510_mode(void);
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
index 37e06c7..48258c7 100644
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -54,6 +54,19 @@
 
 /*
  * ----------------------------------------------------------------------------
+ * Timers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_MPU_TIMER1_BASE	(0xfffec500)
+#define OMAP_MPU_TIMER2_BASE	(0xfffec600)
+#define OMAP_MPU_TIMER3_BASE	(0xfffec700)
+#define MPU_TIMER_FREE		(1 << 6)
+#define MPU_TIMER_CLOCK_ENABLE	(1 << 5)
+#define MPU_TIMER_AR		(1 << 1)
+#define MPU_TIMER_ST		(1 << 0)
+
+/*
+ * ----------------------------------------------------------------------------
  * Clocks
  * ----------------------------------------------------------------------------
  */
@@ -78,6 +91,7 @@
 
 /* DSP clock control */
 #define DSP_CONFIG_REG_BASE     (0xe1008000)
+#define DSP_CKCTL		(DSP_CONFIG_REG_BASE + 0x0)
 #define DSP_IDLECT1		(DSP_CONFIG_REG_BASE + 0x4)
 #define DSP_IDLECT2		(DSP_CONFIG_REG_BASE + 0x8)
 
@@ -88,6 +102,7 @@
  */
 #define ULPD_REG_BASE		(0xfffe0800)
 #define ULPD_IT_STATUS		(ULPD_REG_BASE + 0x14)
+#define ULPD_SETUP_ANALOG_CELL_3	(ULPD_REG_BASE + 0x24)
 #define ULPD_CLOCK_CTRL		(ULPD_REG_BASE + 0x30)
 #	define DIS_USB_PVCI_CLK		(1 << 5)	/* no USB/FAC synch */
 #	define USB_MCLK_EN		(1 << 4)	/* enable W4_USB_CLKO */
@@ -268,17 +283,10 @@
  * Processor specific defines
  * ---------------------------------------------------------------------------
  */
-#ifdef CONFIG_ARCH_OMAP730
+
 #include "omap730.h"
-#endif
-
-#ifdef CONFIG_ARCH_OMAP1510
 #include "omap1510.h"
-#endif
-
-#ifdef CONFIG_ARCH_OMAP16XX
 #include "omap16xx.h"
-#endif
 
 /*
  * ---------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 6701fd9..0d05a7c 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -159,6 +159,7 @@
 #define INT_1610_GPIO_BANK3	(41 + IH2_BASE)
 #define INT_1610_MMC2		(42 + IH2_BASE)
 #define INT_1610_CF		(43 + IH2_BASE)
+#define INT_1610_WAKE_UP_REQ	(46 + IH2_BASE)
 #define INT_1610_GPIO_BANK4	(48 + IH2_BASE)
 #define INT_1610_SPI		(49 + IH2_BASE)
 #define INT_1610_DMA_CH6	(53 + IH2_BASE)
@@ -238,6 +239,8 @@
 #define IH_MPUIO_BASE		(OMAP_MAX_GPIO_LINES + IH_GPIO_BASE)
 #define IH_BOARD_BASE		(16 + IH_MPUIO_BASE)
 
+#define OMAP_IRQ_BIT(irq)	(1 << ((irq) % 32))
+
 #ifndef __ASSEMBLY__
 extern void omap_init_irq(void);
 #endif
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
index 39f99de..5bd3f00 100644
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -231,7 +231,7 @@
 	J19_1610_ETM_D6,
 	J18_1610_ETM_D7,
 
-	/* OMAP-1610 GPIO */
+	/* OMAP16XX GPIO */
 	P20_1610_GPIO4,
 	V9_1610_GPIO7,
 	W8_1610_GPIO9,
@@ -241,6 +241,9 @@
 	AA20_1610_GPIO_41,
 	W19_1610_GPIO48,
 	M7_1610_GPIO62,
+	V14_16XX_GPIO37,
+	R9_16XX_GPIO18,
+	L14_16XX_GPIO49,
 
 	/* OMAP-1610 uWire */
 	V19_1610_UWIRE_SCLK,
@@ -285,12 +288,13 @@
 	V6_USB2_TXD,
 	W5_USB2_SE0,
 
-	/* UART1 1610 */
-
+	/* 16XX UART */
 	R13_1610_UART1_TX,
-	V14_1610_UART1_RX,
+	V14_16XX_UART1_RX,
 	R14_1610_UART1_CTS,
 	AA15_1610_UART1_RTS,
+	R9_16XX_UART2_RX,
+	L14_16XX_UART3_RX,
 
 	/* I2C OMAP-1610 */
 	I2C_SCL,
@@ -332,7 +336,7 @@
  * Table of various FUNC_MUX and PULL_DWN combinations for each device.
  * See also reg_cfg_t above for the lookup table.
  */
-static reg_cfg_set __initdata_or_module
+static const reg_cfg_set __initdata_or_module
 reg_cfg_table[] = {
 /*
  *	 description		mux  mode   mux	 pull pull  pull  pu_pd	 pu  dbg
@@ -455,7 +459,7 @@
 MUX_CFG("J19_1610_ETM_D6",	 5,    0,    1,	  0,  20,   0,	  0,	 0,  1)
 MUX_CFG("J18_1610_ETM_D7",	 5,   27,    1,	  0,  19,   0,	  0,	 0,  1)
 
-/* OMAP-1610 GPIO */
+/* OMAP16XX GPIO */
 MUX_CFG("P20_1610_GPIO4",	 6,   27,    0,	  1,   7,   0,	  1,	 1,  1)
 MUX_CFG("V9_1610_GPIO7",	 B,   12,    1,	  2,  20,   0,	  2,	 1,  1)
 MUX_CFG("W8_1610_GPIO9",	 B,   21,    0,	  2,  23,   0,	  2,	 1,  1)
@@ -465,6 +469,9 @@
 MUX_CFG("AA20_1610_GPIO_41",	 9,    9,    7,	  1,  31,   0,	  1,	 1,  1)
 MUX_CFG("W19_1610_GPIO48",	 8,   15,    7,   1,  23,   1,    1,     0,  1)
 MUX_CFG("M7_1610_GPIO62",	10,    0,    0,   4,  24,   0,    4,     0,  1)
+MUX_CFG("V14_16XX_GPIO37",	 9,   18,    7,	  2,   2,   0,	  2,	 2,  0)
+MUX_CFG("R9_16XX_GPIO18",	 C,   18,    7,   3,   0,   0,    3,     0,  0)
+MUX_CFG("L14_16XX_GPIO49",	 6,    3,    7,   0,  31,   0,    0,    31,  0)
 
 /* OMAP-1610 uWire */
 MUX_CFG("V19_1610_UWIRE_SCLK",	 8,    6,    0,	  1,  20,   0,	  1,	 1,  1)
@@ -503,16 +510,17 @@
 MUX_CFG("W9_USB2_TXEN",		 B,   9,     1,	 NA,   0,   0,	 NA,	 0,  1)
 MUX_CFG("AA9_USB2_VP",		 B,   6,     1,	 NA,   0,   0,	 NA,	 0,  1)
 MUX_CFG("Y5_USB2_RCV",		 C,  21,     1,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("R8_USB2_VM",		 C,  18,     1,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("R9_USB2_VM",		 C,  18,     1,	 NA,   0,   0,	 NA,	 0,  1)
 MUX_CFG("V6_USB2_TXD",		 C,  27,     2,	 NA,   0,   0,	 NA,	 0,  1)
 MUX_CFG("W5_USB2_SE0",		 C,  24,     2,	 NA,   0,   0,	 NA,	 0,  1)
 
-
-/* UART1 */
+/* 16XX UART */
 MUX_CFG("R13_1610_UART1_TX",	 A,  12,     6,	  2,  10,   0,	  2,	10,  1)
-MUX_CFG("V14_1610_UART1_RX",	 9,  18,     0,	  2,   2,   0,	  2,	 2,  1)
+MUX_CFG("V14_16XX_UART1_RX",	 9,  18,     0,	  2,   2,   0,	  2,	 2,  1)
 MUX_CFG("R14_1610_UART1_CTS",	 9,  15,     0,	  2,   1,   0,	  2,	 1,  1)
 MUX_CFG("AA15_1610_UART1_RTS",	 9,  12,     1,	  2,   0,   0,	  2,	 0,  1)
+MUX_CFG("R9_16XX_UART2_RX",	 C,  18,     0,   3,   0,   0,    3,     0,  1)
+MUX_CFG("L14_16XX_UART3_RX",	 6,   3,     0,   0,  31,   0,    0,    31,  1)
 
 /* I2C interface */
 MUX_CFG("I2C_SCL",		 7,  24,     0,	 NA,   0,   0,	 NA,	 0,  0)
diff --git a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h
index 88b1fe4..38a9b95 100644
--- a/include/asm-arm/arch-omap/omap16xx.h
+++ b/include/asm-arm/arch-omap/omap16xx.h
@@ -183,5 +183,37 @@
 #define OMAP16XX_PWL_ENABLE	(OMAP16XX_PWL_BASE + 0x00)
 #define OMAP16XX_PWL_CLK_ENABLE	(OMAP16XX_PWL_BASE + 0x04)
 
+/*
+ * ---------------------------------------------------------------------------
+ * Watchdog timer
+ * ---------------------------------------------------------------------------
+ */
+
+/* 32-bit Watchdog timer in OMAP 16XX */
+#define OMAP_16XX_WATCHDOG_BASE        (0xfffeb000)
+#define OMAP_16XX_WIDR         (OMAP_16XX_WATCHDOG_BASE + 0x00)
+#define OMAP_16XX_WD_SYSCONFIG (OMAP_16XX_WATCHDOG_BASE + 0x10)
+#define OMAP_16XX_WD_SYSSTATUS (OMAP_16XX_WATCHDOG_BASE + 0x14)
+#define OMAP_16XX_WCLR         (OMAP_16XX_WATCHDOG_BASE + 0x24)
+#define OMAP_16XX_WCRR         (OMAP_16XX_WATCHDOG_BASE + 0x28)
+#define OMAP_16XX_WLDR         (OMAP_16XX_WATCHDOG_BASE + 0x2c)
+#define OMAP_16XX_WTGR         (OMAP_16XX_WATCHDOG_BASE + 0x30)
+#define OMAP_16XX_WWPS         (OMAP_16XX_WATCHDOG_BASE + 0x34)
+#define OMAP_16XX_WSPR         (OMAP_16XX_WATCHDOG_BASE + 0x48)
+
+#define WCLR_PRE_SHIFT         5
+#define WCLR_PTV_SHIFT         2
+
+#define WWPS_W_PEND_WSPR       (1 << 4)
+#define WWPS_W_PEND_WTGR       (1 << 3)
+#define WWPS_W_PEND_WLDR       (1 << 2)
+#define WWPS_W_PEND_WCRR       (1 << 1)
+#define WWPS_W_PEND_WCLR       (1 << 0)
+
+#define WSPR_ENABLE_0          (0x0000bbbb)
+#define WSPR_ENABLE_1          (0x00004444)
+#define WSPR_DISABLE_0         (0x0000aaaa)
+#define WSPR_DISABLE_1         (0x00005555)
+
 #endif /*  __ASM_ARCH_OMAP16XX_H */
 
diff --git a/include/asm-arm/arch-omap/system.h b/include/asm-arm/arch-omap/system.h
index 17a2c48..ff37bc2 100644
--- a/include/asm-arm/arch-omap/system.h
+++ b/include/asm-arm/arch-omap/system.h
@@ -5,7 +5,9 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 #include <linux/config.h>
+#include <asm/mach-types.h>
 #include <asm/arch/hardware.h>
+#include <asm/mach-types.h>
 
 static inline void arch_idle(void)
 {
@@ -14,7 +16,24 @@
 
 static inline void arch_reset(char mode)
 {
-	omap_writew(1, ARM_RSTCT1);
+
+#ifdef CONFIG_ARCH_OMAP16XX
+	/*
+	 * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
+	 * "Global Software Reset Affects Traffic Controller Frequency".
+	 */
+	if (cpu_is_omap5912()) {
+		omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4),
+				 DPLL_CTL);
+		omap_writew(0x8, ARM_RSTCT1);
+	}
+#endif
+#ifdef CONFIG_MACH_VOICEBLUE
+	if (machine_is_voiceblue())
+		voiceblue_reset();
+	else
+#endif
+		omap_writew(1, ARM_RSTCT1);
 }
 
 #endif
diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
index 33ce5d3..5164213 100644
--- a/include/asm-i386/mmzone.h
+++ b/include/asm-i386/mmzone.h
@@ -8,20 +8,15 @@
 
 #include <asm/smp.h>
 
-#if CONFIG_NUMA
+#ifdef CONFIG_NUMA
 extern struct pglist_data *node_data[];
 #define NODE_DATA(nid)	(node_data[nid])
 
-#ifdef CONFIG_NUMA
-	#ifdef CONFIG_X86_NUMAQ
-		#include <asm/numaq.h>
-	#else	/* summit or generic arch */
-		#include <asm/srat.h>
-	#endif
-#else /* !CONFIG_NUMA */
-	#define get_memcfg_numa get_memcfg_numa_flat
-	#define get_zholes_size(n) (0)
-#endif /* CONFIG_NUMA */
+#ifdef CONFIG_X86_NUMAQ
+	#include <asm/numaq.h>
+#else	/* summit or generic arch */
+	#include <asm/srat.h>
+#endif
 
 extern int get_memcfg_numa_flat(void );
 /*
@@ -42,6 +37,11 @@
 	get_memcfg_numa_flat();
 }
 
+extern int early_pfn_to_nid(unsigned long pfn);
+
+#else /* !CONFIG_NUMA */
+#define get_memcfg_numa get_memcfg_numa_flat
+#define get_zholes_size(n) (0)
 #endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -151,6 +151,4 @@
 
 #endif /* CONFIG_NEED_MULTIPLE_NODES */
 
-extern int early_pfn_to_nid(unsigned long pfn);
-
 #endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 6f0f93d..5d06e6b 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -694,4 +694,12 @@
 extern void enable_sep_cpu(void);
 extern int sysenter_setup(void);
 
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#endif
+
 #endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-ia64/sn/arch.h b/include/asm-ia64/sn/arch.h
index 635fdce..ab827d2 100644
--- a/include/asm-ia64/sn/arch.h
+++ b/include/asm-ia64/sn/arch.h
@@ -11,6 +11,7 @@
 #ifndef _ASM_IA64_SN_ARCH_H
 #define _ASM_IA64_SN_ARCH_H
 
+#include <linux/numa.h>
 #include <asm/types.h>
 #include <asm/percpu.h>
 #include <asm/sn/types.h>
diff --git a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h
index e51471f..e190dd4 100644
--- a/include/asm-ia64/sn/intr.h
+++ b/include/asm-ia64/sn/intr.h
@@ -9,6 +9,8 @@
 #ifndef _ASM_IA64_SN_INTR_H
 #define _ASM_IA64_SN_INTR_H
 
+#include <linux/rcupdate.h>
+
 #define SGI_UART_VECTOR		(0xe9)
 #define SGI_PCIBR_ERROR		(0x33)
 
@@ -33,7 +35,7 @@
 
 // The SN PROM irq struct
 struct sn_irq_info {
-	struct sn_irq_info *irq_next;	/* sharing irq list	     */
+	struct sn_irq_info *irq_next;	/* deprecated DO NOT USE     */
 	short		irq_nasid;	/* Nasid IRQ is assigned to  */
 	int		irq_slice;	/* slice IRQ is assigned to  */
 	int		irq_cpuid;	/* kernel logical cpuid	     */
@@ -47,6 +49,8 @@
 	int		irq_cookie;	/* unique cookie 	     */
 	int		irq_flags;	/* flags */
 	int		irq_share_cnt;	/* num devices sharing IRQ   */
+	struct list_head	list;	/* list of sn_irq_info structs */
+	struct rcu_head		rcu;	/* rcu callback list */
 };
 
 extern void sn_send_IPI_phys(int, long, int, int);
diff --git a/arch/ia64/sn/include/pci/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h
similarity index 94%
rename from arch/ia64/sn/include/pci/pcibr_provider.h
rename to include/asm-ia64/sn/pcibr_provider.h
index 1cd291d..f9b8d21 100644
--- a/arch/ia64/sn/include/pci/pcibr_provider.h
+++ b/include/asm-ia64/sn/pcibr_provider.h
@@ -8,6 +8,9 @@
 #ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
 #define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
 
+#include <asm/sn/intr.h>
+#include <asm/sn/pcibus_provider_defs.h>
+
 /* Workarounds */
 #define PV907516 (1 << 1) /* TIOCP: Don't write the write buffer flush reg */
 
@@ -20,7 +23,7 @@
 #define IS_PIC_SOFT(ps)     (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_PIC)
 
 
-/* 
+/*
  * The different PCI Bridge types supported on the SGI Altix platforms
  */
 #define PCIBR_BRIDGETYPE_UNKNOWN       -1
@@ -100,15 +103,16 @@
 
 	struct ate_resource     pbi_int_ate_resource;
 	uint64_t                pbi_int_ate_size;
-	
+
 	uint64_t                pbi_dir_xbase;
 	char                    pbi_hub_xid;
 
 	uint64_t                pbi_devreg[8];
-	spinlock_t              pbi_lock;
 
 	uint32_t		pbi_valid_devices;
 	uint32_t		pbi_enabled_devices;
+
+	spinlock_t              pbi_lock;
 };
 
 /*
@@ -148,4 +152,8 @@
 extern int 		pcibr_ate_alloc(struct pcibus_info *, int);
 extern void 		pcibr_ate_free(struct pcibus_info *, int);
 extern void 		ate_write(struct pcibus_info *, int, int, uint64_t);
+extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device,
+				 void *resp);
+extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device,
+				  int action, void *resp);
 #endif
diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h
index ed4031d..49711d0 100644
--- a/include/asm-ia64/sn/pcidev.h
+++ b/include/asm-ia64/sn/pcidev.h
@@ -10,11 +10,11 @@
 
 #include <linux/pci.h>
 
-extern struct sn_irq_info **sn_irq;
-
 #define SN_PCIDEV_INFO(pci_dev) \
         ((struct pcidev_info *)(pci_dev)->sysdata)
 
+#define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \
+	(struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
 /*
  * Given a pci_bus, return the sn pcibus_bussoft struct.  Note that
  * this only works for root busses, not for busses represented by PPB's.
@@ -23,6 +23,8 @@
 #define SN_PCIBUS_BUSSOFT(pci_bus) \
         ((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
 
+#define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \
+	(struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
 /*
  * Given a struct pci_dev, return the sn pcibus_bussoft struct.  Note
  * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due
@@ -50,9 +52,17 @@
 
 	struct sn_irq_info	*pdi_sn_irq_info;
 	struct sn_pcibus_provider *pdi_provider;	/* sn pci ops */
+	struct pci_dev 		*host_pci_dev;		/* host bus link */
 };
 
 extern void sn_irq_fixup(struct pci_dev *pci_dev,
 			 struct sn_irq_info *sn_irq_info);
-
+extern void sn_irq_unfixup(struct pci_dev *pci_dev);
+extern void sn_pci_controller_fixup(int segment, int busnum,
+ 				    struct pci_bus *bus);
+extern void sn_bus_store_sysdata(struct pci_dev *dev);
+extern void sn_bus_free_sysdata(void);
+extern void sn_pci_fixup_slot(struct pci_dev *dev);
+extern void sn_pci_unfixup_slot(struct pci_dev *dev);
+extern void sn_irq_lh_init(void);
 #endif				/* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/arch/ia64/sn/include/pci/pic.h b/include/asm-ia64/sn/pic.h
similarity index 97%
rename from arch/ia64/sn/include/pci/pic.h
rename to include/asm-ia64/sn/pic.h
index fd18ace..0de82e6 100644
--- a/arch/ia64/sn/include/pci/pic.h
+++ b/include/asm-ia64/sn/pic.h
@@ -15,7 +15,7 @@
  * PIC handles PCI/X busses.  PCI/X requires that the 'bridge' (i.e. PIC)
  * be designated as 'device 0'.   That is a departure from earlier SGI
  * PCI bridges.  Because of that we use config space 1 to access the
- * config space of the first actual PCI device on the bus. 
+ * config space of the first actual PCI device on the bus.
  * Here's what the PIC manual says:
  *
  *     The current PCI-X bus specification now defines that the parent
@@ -29,14 +29,14 @@
  *     correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc.
  *     PCI-X requires we start a 1, not 0 and currently the PX brick
  *     does associate our:
- * 
+ *
  *         device 0 with configuration space window 1,
- *         device 1 with configuration space window 2, 
+ *         device 1 with configuration space window 2,
  *         device 2 with configuration space window 3,
  *         device 3 with configuration space window 4.
  *
- * The net effect is that all config space access are off-by-one with 
- * relation to other per-slot accesses on the PIC.   
+ * The net effect is that all config space access are off-by-one with
+ * relation to other per-slot accesses on the PIC.
  * Here is a table that shows some of that:
  *
  *                               Internal Slot#
@@ -65,7 +65,7 @@
  *****************************************************************************/
 
 /* NOTE: PIC WAR. PV#854697.  PIC does not allow writes just to [31:0]
- * of a 64-bit register.  When writing PIC registers, always write the 
+ * of a 64-bit register.  When writing PIC registers, always write the
  * entire 64 bits.
  */
 
@@ -164,7 +164,7 @@
 	uint64_t	clear_all;			/* 0x000{438,,,5F8} */
     } p_buf_count[8];
 
-    
+
     /* 0x000600-0x0009FF -- PCI/X registers */
     uint64_t		p_pcix_bus_err_addr;		/* 0x000600 */
     uint64_t		p_pcix_bus_err_attr;		/* 0x000608 */
diff --git a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h
index 20b3001..d2c1d34 100644
--- a/include/asm-ia64/sn/sn_cpuid.h
+++ b/include/asm-ia64/sn/sn_cpuid.h
@@ -81,11 +81,6 @@
  *
  */
 
-#ifndef CONFIG_SMP
-#define cpu_physical_id(cpuid)			((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff)
-#endif
-
-
 #define get_node_number(addr)			NASID_GET(addr)
 
 /*
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index 1455375..27976d2 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -134,43 +134,28 @@
 
 #define SN_SAL_FAKE_PROM			   0x02009999
 
-
 /**
- * sn_sal_rev_major - get the major SGI SAL revision number
- *
- * The SGI PROM stores its version in sal_[ab]_rev_(major|minor).
- * This routine simply extracts the major value from the
- * @ia64_sal_systab structure constructed by ia64_sal_init().
- */
-static inline int
-sn_sal_rev_major(void)
+  * sn_sal_revision - get the SGI SAL revision number
+  *
+  * The SGI PROM stores its version in the sal_[ab]_rev_(major|minor).
+  * This routine simply extracts the major and minor values and
+  * presents them in a u32 format.
+  *
+  * For example, version 4.05 would be represented at 0x0405.
+  */
+static inline u32
+sn_sal_rev(void)
 {
 	struct ia64_sal_systab *systab = efi.sal_systab;
 
-	return (int)systab->sal_b_rev_major;
-}
-
-/**
- * sn_sal_rev_minor - get the minor SGI SAL revision number
- *
- * The SGI PROM stores its version in sal_[ab]_rev_(major|minor).
- * This routine simply extracts the minor value from the
- * @ia64_sal_systab structure constructed by ia64_sal_init().
- */
-static inline int
-sn_sal_rev_minor(void)
-{
-	struct ia64_sal_systab *systab = efi.sal_systab;
-	
-	return (int)systab->sal_b_rev_minor;
+	return (u32)(systab->sal_b_rev_major << 8 | systab->sal_b_rev_minor);
 }
 
 /*
  * Specify the minimum PROM revsion required for this kernel.
  * Note that they're stored in hex format...
  */
-#define SN_SAL_MIN_MAJOR	0x4  /* SN2 kernels need at least PROM 4.0 */
-#define SN_SAL_MIN_MINOR	0x0
+#define SN_SAL_MIN_VERSION	0x0404
 
 /*
  * Returns the master console nasid, if the call fails, return an illegal
diff --git a/arch/ia64/sn/include/pci/tiocp.h b/include/asm-ia64/sn/tiocp.h
similarity index 99%
rename from arch/ia64/sn/include/pci/tiocp.h
rename to include/asm-ia64/sn/tiocp.h
index f07c83b..5f2489c 100644
--- a/arch/ia64/sn/include/pci/tiocp.h
+++ b/include/asm-ia64/sn/tiocp.h
@@ -111,7 +111,7 @@
 	uint64_t	clear_all;			/* 0x000{438,,,5F8} */
     } cp_buf_count[8];
 
-    
+
     /* 0x000600-0x0009FF -- PCI/X registers */
     uint64_t		cp_pcix_bus_err_addr;		/* 0x000600 */
     uint64_t		cp_pcix_bus_err_attr;		/* 0x000608 */
diff --git a/include/asm-m32r/s1d13806.h b/include/asm-m32r/s1d13806.h
new file mode 100644
index 0000000..248d36a
--- /dev/null
+++ b/include/asm-m32r/s1d13806.h
@@ -0,0 +1,199 @@
+//----------------------------------------------------------------------------
+//
+//  File generated by S1D13806CFG.EXE
+//
+//  Copyright (c) 2000,2001 Epson Research and Development, Inc.
+//  All rights reserved.
+//
+//----------------------------------------------------------------------------
+
+// Panel:  (active)  640x480 77Hz STN Single 8-bit (PCLK=CLKI=25.175MHz)
+// Memory: Embedded SDRAM (MCLK=CLKI3=50.000MHz) (BUSCLK=33.333MHz)
+
+#define SWIVEL_VIEW		0	/* 0:none, 1:90 not completed */
+
+static struct s1d13xxxfb_regval s1d13xxxfb_initregs[] = {
+
+    {0x0001,0x00},   // Miscellaneous Register
+    {0x01FC,0x00},   // Display Mode Register
+#if defined(CONFIG_PLAT_MAPPI)
+    {0x0004,0x00},   // General IO Pins Configuration Register 0
+    {0x0005,0x00},   // General IO Pins Configuration Register 1
+    {0x0008,0x00},   // General IO Pins Control Register 0
+    {0x0009,0x00},   // General IO Pins Control Register 1
+    {0x0010,0x00},   // Memory Clock Configuration Register
+    {0x0014,0x00},   // LCD Pixel Clock Configuration Register
+    {0x0018,0x00},   // CRT/TV Pixel Clock Configuration Register
+    {0x001C,0x00},   // MediaPlug Clock Configuration Register
+/*
+ * .. 10MHz: 0x00
+ * .. 30MHz: 0x01
+ * 30MHz ..: 0x02
+ */
+    {0x001E,0x02},   // CPU To Memory Wait State Select Register
+    {0x0021,0x02},   // DRAM Refresh Rate Register
+    {0x002A,0x11},   // DRAM Timings Control Register 0
+    {0x002B,0x13},   // DRAM Timings Control Register 1
+    {0x0020,0x80},   // Memory Configuration Register
+    {0x0030,0x25},   // Panel Type Register
+    {0x0031,0x00},   // MOD Rate Register
+    {0x0032,0x4F},   // LCD Horizontal Display Width Register
+    {0x0034,0x12},   // LCD Horizontal Non-Display Period Register
+    {0x0035,0x01},   // TFT FPLINE Start Position Register
+    {0x0036,0x0B},   // TFT FPLINE Pulse Width Register
+    {0x0038,0xDF},   // LCD Vertical Display Height Register 0
+    {0x0039,0x01},   // LCD Vertical Display Height Register 1
+    {0x003A,0x2C},   // LCD Vertical Non-Display Period Register
+    {0x003B,0x0A},   // TFT FPFRAME Start Position Register
+    {0x003C,0x01},   // TFT FPFRAME Pulse Width Register
+
+    {0x0041,0x00},   // LCD Miscellaneous Register
+    {0x0042,0x00},   // LCD Display Start Address Register 0
+    {0x0043,0x00},   // LCD Display Start Address Register 1
+    {0x0044,0x00},   // LCD Display Start Address Register 2
+
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+    {0x0004,0x07},   // GPIO[0:7] direction
+    {0x0005,0x00},   // GPIO[8:12] direction
+    {0x0008,0x00},   // GPIO[0:7] data
+    {0x0009,0x00},   // GPIO[8:12] data
+    {0x0008,0x04},   // LCD panel Vcc on
+    {0x0008,0x05},   // LCD panel reset
+    {0x0010,0x01},   // Memory Clock Configuration Register
+    {0x0014,0x30},   // LCD Pixel Clock Configuration Register (CLKI 22MHz/4)
+    {0x0018,0x00},   // CRT/TV Pixel Clock Configuration Register
+    {0x001C,0x00},   // MediaPlug Clock Configuration Register(10MHz)
+    {0x001E,0x00},   // CPU To Memory Wait State Select Register
+    {0x0020,0x80},   // Memory Configuration Register
+    {0x0021,0x03},   // DRAM Refresh Rate Register
+    {0x002A,0x00},   // DRAM Timings Control Register 0
+    {0x002B,0x01},   // DRAM Timings Control Register 1
+    {0x0030,0x25},   // Panel Type Register
+    {0x0031,0x00},   // MOD Rate Register
+    {0x0032,0x1d},   // LCD Horizontal Display Width Register
+    {0x0034,0x05},   // LCD Horizontal Non-Display Period Register
+    {0x0035,0x01},   // TFT FPLINE Start Position Register
+    {0x0036,0x01},   // TFT FPLINE Pulse Width Register
+    {0x0038,0x3F},   // LCD Vertical Display Height Register 0
+    {0x0039,0x01},   // LCD Vertical Display Height Register 1
+    {0x003A,0x0b},   // LCD Vertical Non-Display Period Register
+    {0x003B,0x07},   // TFT FPFRAME Start Position Register
+    {0x003C,0x02},   // TFT FPFRAME Pulse Width Register
+
+    {0x0041,0x00},   // LCD Miscellaneous Register
+#if (SWIVEL_VIEW == 0)
+    {0x0042,0x00},   // LCD Display Start Address Register 0
+    {0x0043,0x00},   // LCD Display Start Address Register 1
+    {0x0044,0x00},   // LCD Display Start Address Register 2
+
+#elif (SWIVEL_VIEW == 1)
+    // 1024 - W(320) = 0x2C0
+    {0x0042,0xC0},   // LCD Display Start Address Register 0
+    {0x0043,0x02},   // LCD Display Start Address Register 1
+    {0x0044,0x00},   // LCD Display Start Address Register 2
+    // 1024
+    {0x0046,0x00},   // LCD Memory Address Offset Register 0
+    {0x0047,0x02},   // LCD Memory Address Offset Register 1
+#else
+#error unsupported SWIVEL_VIEW mode
+#endif
+#else
+#error no platform configuration
+#endif  /* CONFIG_PLAT_XXX */
+
+    {0x0048,0x00},   // LCD Pixel Panning Register
+    {0x004A,0x00},   // LCD Display FIFO High Threshold Control Register
+    {0x004B,0x00},   // LCD Display FIFO Low Threshold Control Register
+    {0x0050,0x4F},   // CRT/TV Horizontal Display Width Register
+    {0x0052,0x13},   // CRT/TV Horizontal Non-Display Period Register
+    {0x0053,0x01},   // CRT/TV HRTC Start Position Register
+    {0x0054,0x0B},   // CRT/TV HRTC Pulse Width Register
+    {0x0056,0xDF},   // CRT/TV Vertical Display Height Register 0
+    {0x0057,0x01},   // CRT/TV Vertical Display Height Register 1
+    {0x0058,0x2B},   // CRT/TV Vertical Non-Display Period Register
+    {0x0059,0x09},   // CRT/TV VRTC Start Position Register
+    {0x005A,0x01},   // CRT/TV VRTC Pulse Width Register
+    {0x005B,0x10},   // TV Output Control Register
+
+    {0x0062,0x00},   // CRT/TV Display Start Address Register 0
+    {0x0063,0x00},   // CRT/TV Display Start Address Register 1
+    {0x0064,0x00},   // CRT/TV Display Start Address Register 2
+
+    {0x0068,0x00},   // CRT/TV Pixel Panning Register
+    {0x006A,0x00},   // CRT/TV Display FIFO High Threshold Control Register
+    {0x006B,0x00},   // CRT/TV Display FIFO Low Threshold Control Register
+    {0x0070,0x00},   // LCD Ink/Cursor Control Register
+    {0x0071,0x01},   // LCD Ink/Cursor Start Address Register
+    {0x0072,0x00},   // LCD Cursor X Position Register 0
+    {0x0073,0x00},   // LCD Cursor X Position Register 1
+    {0x0074,0x00},   // LCD Cursor Y Position Register 0
+    {0x0075,0x00},   // LCD Cursor Y Position Register 1
+    {0x0076,0x00},   // LCD Ink/Cursor Blue Color 0 Register
+    {0x0077,0x00},   // LCD Ink/Cursor Green Color 0 Register
+    {0x0078,0x00},   // LCD Ink/Cursor Red Color 0 Register
+    {0x007A,0x1F},   // LCD Ink/Cursor Blue Color 1 Register
+    {0x007B,0x3F},   // LCD Ink/Cursor Green Color 1 Register
+    {0x007C,0x1F},   // LCD Ink/Cursor Red Color 1 Register
+    {0x007E,0x00},   // LCD Ink/Cursor FIFO Threshold Register
+    {0x0080,0x00},   // CRT/TV Ink/Cursor Control Register
+    {0x0081,0x01},   // CRT/TV Ink/Cursor Start Address Register
+    {0x0082,0x00},   // CRT/TV Cursor X Position Register 0
+    {0x0083,0x00},   // CRT/TV Cursor X Position Register 1
+    {0x0084,0x00},   // CRT/TV Cursor Y Position Register 0
+    {0x0085,0x00},   // CRT/TV Cursor Y Position Register 1
+    {0x0086,0x00},   // CRT/TV Ink/Cursor Blue Color 0 Register
+    {0x0087,0x00},   // CRT/TV Ink/Cursor Green Color 0 Register
+    {0x0088,0x00},   // CRT/TV Ink/Cursor Red Color 0 Register
+    {0x008A,0x1F},   // CRT/TV Ink/Cursor Blue Color 1 Register
+    {0x008B,0x3F},   // CRT/TV Ink/Cursor Green Color 1 Register
+    {0x008C,0x1F},   // CRT/TV Ink/Cursor Red Color 1 Register
+    {0x008E,0x00},   // CRT/TV Ink/Cursor FIFO Threshold Register
+    {0x0100,0x00},   // BitBlt Control Register 0
+    {0x0101,0x00},   // BitBlt Control Register 1
+    {0x0102,0x00},   // BitBlt ROP Code/Color Expansion Register
+    {0x0103,0x00},   // BitBlt Operation Register
+    {0x0104,0x00},   // BitBlt Source Start Address Register 0
+    {0x0105,0x00},   // BitBlt Source Start Address Register 1
+    {0x0106,0x00},   // BitBlt Source Start Address Register 2
+    {0x0108,0x00},   // BitBlt Destination Start Address Register 0
+    {0x0109,0x00},   // BitBlt Destination Start Address Register 1
+    {0x010A,0x00},   // BitBlt Destination Start Address Register 2
+    {0x010C,0x00},   // BitBlt Memory Address Offset Register 0
+    {0x010D,0x00},   // BitBlt Memory Address Offset Register 1
+    {0x0110,0x00},   // BitBlt Width Register 0
+    {0x0111,0x00},   // BitBlt Width Register 1
+    {0x0112,0x00},   // BitBlt Height Register 0
+    {0x0113,0x00},   // BitBlt Height Register 1
+    {0x0114,0x00},   // BitBlt Background Color Register 0
+    {0x0115,0x00},   // BitBlt Background Color Register 1
+    {0x0118,0x00},   // BitBlt Foreground Color Register 0
+    {0x0119,0x00},   // BitBlt Foreground Color Register 1
+    {0x01E0,0x00},   // Look-Up Table Mode Register
+    {0x01E2,0x00},   // Look-Up Table Address Register
+    {0x01F0,0x10},   // Power Save Configuration Register
+    {0x01F1,0x00},   // Power Save Status Register
+    {0x01F4,0x00},   // CPU-to-Memory Access Watchdog Timer Register
+#if (SWIVEL_VIEW == 0)
+    {0x01FC,0x01},   // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
+#elif (SWIVEL_VIEW == 1)
+    {0x01FC,0x41},   // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
+#else
+#error unsupported SWIVEL_VIEW mode
+#endif  /* SWIVEL_VIEW */
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+    {0x0008,0x07},   // LCD panel Vdd & Vg on
+#endif
+
+    {0x0040,0x05},   // LCD Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+#if defined(CONFIG_PLAT_MAPPI)
+    {0x0046,0x80},   // LCD Memory Address Offset Register 0
+    {0x0047,0x02},   // LCD Memory Address Offset Register 1
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+    {0x0046,0xf0},   // LCD Memory Address Offset Register 0
+    {0x0047,0x00},   // LCD Memory Address Offset Register 1
+#endif
+    {0x0060,0x05},   // CRT/TV Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+    {0x0066,0x80},   // CRT/TV Memory Address Offset Register 0	// takeo
+    {0x0067,0x02},   // CRT/TV Memory Address Offset Register 1
+};
diff --git a/include/asm-ppc/macio.h b/include/asm-ppc/macio.h
index 2cafc99..a481b77 100644
--- a/include/asm-ppc/macio.h
+++ b/include/asm-ppc/macio.h
@@ -1,6 +1,7 @@
 #ifndef __MACIO_ASIC_H__
 #define __MACIO_ASIC_H__
 
+#include <linux/mod_devicetable.h>
 #include <asm/of_device.h>
 
 extern struct bus_type macio_bus_type;
@@ -120,10 +121,10 @@
 struct macio_driver
 {
 	char			*name;
-	struct of_match		*match_table;
+	struct of_device_id	*match_table;
 	struct module		*owner;
 
-	int	(*probe)(struct macio_dev* dev, const struct of_match *match);
+	int	(*probe)(struct macio_dev* dev, const struct of_device_id *match);
 	int	(*remove)(struct macio_dev* dev);
 
 	int	(*suspend)(struct macio_dev* dev, pm_message_t state);
diff --git a/include/asm-ppc/of_device.h b/include/asm-ppc/of_device.h
index 7229735..4b264cf 100644
--- a/include/asm-ppc/of_device.h
+++ b/include/asm-ppc/of_device.h
@@ -24,20 +24,8 @@
 };
 #define	to_of_device(d) container_of(d, struct of_device, dev)
 
-/*
- * Struct used for matching a device
- */
-struct of_match
-{
-	char	*name;
-	char	*type;
-	char	*compatible;
-	void	*data;
-};
-#define OF_ANY_MATCH		((char *)-1L)
-
-extern const struct of_match *of_match_device(
-	const struct of_match *matches, const struct of_device *dev);
+extern const struct of_device_id *of_match_device(
+	const struct of_device_id *matches, const struct of_device *dev);
 
 extern struct of_device *of_dev_get(struct of_device *dev);
 extern void of_dev_put(struct of_device *dev);
@@ -49,10 +37,10 @@
 struct of_platform_driver
 {
 	char			*name;
-	struct of_match		*match_table;
+	struct of_device_id	*match_table;
 	struct module		*owner;
 
-	int	(*probe)(struct of_device* dev, const struct of_match *match);
+	int	(*probe)(struct of_device* dev, const struct of_device_id *match);
 	int	(*remove)(struct of_device* dev);
 
 	int	(*suspend)(struct of_device* dev, pm_message_t state);
diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
index e8b7922..a7894e0 100644
--- a/include/asm-ppc/unistd.h
+++ b/include/asm-ppc/unistd.h
@@ -262,7 +262,7 @@
 #define __NR_rtas		255
 #define __NR_sys_debug_setcontext 256
 /* Number 257 is reserved for vserver */
-/* Number 258 is reserved for new sys_remap_file_pages */
+/* 258 currently unused */
 /* Number 259 is reserved for new sys_mbind */
 /* Number 260 is reserved for new sys_get_mempolicy */
 /* Number 261 is reserved for new sys_set_mempolicy */
diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h
index cbbfbec..d67fa9e 100644
--- a/include/asm-ppc64/cputable.h
+++ b/include/asm-ppc64/cputable.h
@@ -138,6 +138,7 @@
 #define CPU_FTR_COHERENT_ICACHE  	ASM_CONST(0x0000020000000000)
 #define CPU_FTR_LOCKLESS_TLBIE		ASM_CONST(0x0000040000000000)
 #define CPU_FTR_MMCRA_SIHV		ASM_CONST(0x0000080000000000)
+#define CPU_FTR_CTRL			ASM_CONST(0x0000100000000000)
 
 /* Platform firmware features */
 #define FW_FTR_				ASM_CONST(0x0000000000000001)
@@ -148,7 +149,7 @@
 
 #define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \
                                  CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \
-                                 CPU_FTR_NODSISRALIGN)
+                                 CPU_FTR_NODSISRALIGN | CPU_FTR_CTRL)
 
 /* iSeries doesn't support large pages */
 #ifdef CONFIG_PPC_ISERIES
diff --git a/include/asm-ppc64/hvconsole.h b/include/asm-ppc64/hvconsole.h
index d89d94c..6da93ce 100644
--- a/include/asm-ppc64/hvconsole.h
+++ b/include/asm-ppc64/hvconsole.h
@@ -29,12 +29,21 @@
  */
 #define MAX_NR_HVC_CONSOLES	16
 
+/* implemented by a low level driver */
+struct hv_ops {
+	int (*get_chars)(uint32_t vtermno, char *buf, int count);
+	int (*put_chars)(uint32_t vtermno, const char *buf, int count);
+};
 extern int hvc_get_chars(uint32_t vtermno, char *buf, int count);
 extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count);
 
-/* Early discovery of console adapters. */
-extern int hvc_find_vtys(void);
+struct hvc_struct;
 
-/* Implemented by a console driver */
-extern int hvc_instantiate(uint32_t vtermno, int index);
+/* Register a vterm and a slot index for use as a console (console_init) */
+extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
+/* register a vterm for hvc tty operation (module_init or hotplug add) */
+extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
+						 struct hv_ops *ops);
+/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
+extern int __devexit hvc_remove(struct hvc_struct *hp);
 #endif /* _PPC64_HVCONSOLE_H */
diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
index 9cdad3e..1e6ad48 100644
--- a/include/asm-ppc64/machdep.h
+++ b/include/asm-ppc64/machdep.h
@@ -140,8 +140,13 @@
 						unsigned long size,
 						pgprot_t vma_prot);
 
+	/* Idle loop for this platform, leave empty for default idle loop */
+	int		(*idle_loop)(void);
 };
 
+extern int default_idle(void);
+extern int native_idle(void);
+
 extern struct machdep_calls ppc_md;
 extern char cmd_line[COMMAND_LINE_SIZE];
 
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
index af28aa5..352306c 100644
--- a/include/asm-ppc64/processor.h
+++ b/include/asm-ppc64/processor.h
@@ -20,6 +20,7 @@
 #include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/systemcfg.h>
+#include <asm/cputable.h>
 
 /* Machine State Register (MSR) Fields */
 #define MSR_SF_LG	63              /* Enable 64 bit mode */
@@ -501,24 +502,37 @@
 {
 	unsigned long ctrl;
 
-	ctrl = mfspr(SPRN_CTRLF);
-	ctrl |= CTRL_RUNLATCH;
-	mtspr(SPRN_CTRLT, ctrl);
+	if (cpu_has_feature(CPU_FTR_CTRL)) {
+		ctrl = mfspr(SPRN_CTRLF);
+		ctrl |= CTRL_RUNLATCH;
+		mtspr(SPRN_CTRLT, ctrl);
+	}
 }
 
 static inline void ppc64_runlatch_off(void)
 {
 	unsigned long ctrl;
 
-	ctrl = mfspr(SPRN_CTRLF);
-	ctrl &= ~CTRL_RUNLATCH;
-	mtspr(SPRN_CTRLT, ctrl);
+	if (cpu_has_feature(CPU_FTR_CTRL)) {
+		ctrl = mfspr(SPRN_CTRLF);
+		ctrl &= ~CTRL_RUNLATCH;
+		mtspr(SPRN_CTRLT, ctrl);
+	}
 }
 
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
 
+#ifdef __KERNEL__
+#define RUNLATCH_ON(REG)			\
+BEGIN_FTR_SECTION				\
+	mfspr	(REG),SPRN_CTRLF;		\
+	ori	(REG),(REG),CTRL_RUNLATCH;	\
+	mtspr	SPRN_CTRLT,(REG);		\
+END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
+#endif
+
 /*
  * Number of entries in the SLB. If this ever changes we should handle
  * it with a use a cpu feature fixup.
diff --git a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
index 605d91e..4a94acf 100644
--- a/include/asm-ppc64/unistd.h
+++ b/include/asm-ppc64/unistd.h
@@ -268,7 +268,7 @@
 #define __NR_rtas		255
 /* Number 256 is reserved for sys_debug_setcontext */
 /* Number 257 is reserved for vserver */
-/* Number 258 is reserved for new sys_remap_file_pages */
+/* 258 currently unused */
 #define __NR_mbind		259
 #define __NR_get_mempolicy	260
 #define __NR_set_mempolicy	261
@@ -283,8 +283,10 @@
 #define __NR_request_key	270
 #define __NR_keyctl		271
 #define __NR_waitid		272
+#define __NR_ioprio_set		273
+#define __NR_ioprio_get		274
 
-#define __NR_syscalls		273
+#define __NR_syscalls		275
 #ifdef __KERNEL__
 #define NR_syscalls	__NR_syscalls
 #endif
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index 8467084..aee17d7 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -212,7 +212,7 @@
 #define __NR_epoll_create       193 /* Linux Specific                              */
 #define __NR_epoll_ctl          194 /* Linux Specific                              */
 #define __NR_epoll_wait         195 /* Linux Specific                              */
-/* #define __NR_ulimit          196    Linux Specific                              */
+#define __NR_ioprio_set         196 /* Linux Specific                              */
 #define __NR_getppid            197 /* Linux Specific                              */
 #define __NR_sigaction          198 /* Linux Specific                              */
 #define __NR_sgetmask           199 /* Linux Specific                              */
@@ -234,7 +234,7 @@
 #define __NR_ipc                215 /* Linux Specific                              */
 #define __NR_sigreturn          216 /* Linux Specific                              */
 #define __NR_clone              217 /* Linux Specific                              */
-/* #define __NR_modify_ldt      218    Linux Specific - i386 specific, unused      */
+#define __NR_ioprio_get         218 /* Linux Specific                              */
 #define __NR_adjtimex           219 /* Linux Specific                              */
 #define __NR_sigprocmask        220 /* Linux Specific                              */
 #define __NR_create_module      221 /* Linux Specific                              */
diff --git a/include/asm-sparc64/param.h b/include/asm-sparc64/param.h
index 6a12f3a..a1cd497 100644
--- a/include/asm-sparc64/param.h
+++ b/include/asm-sparc64/param.h
@@ -1,9 +1,10 @@
-/* $Id: param.h,v 1.2 2000/10/30 21:01:41 davem Exp $ */
 #ifndef _ASMSPARC64_PARAM_H
 #define _ASMSPARC64_PARAM_H
 
+#include <linux/config.h>
+
 #ifdef __KERNEL__
-# define HZ		1000	/* Internal kernel timer frequency */
+# define HZ		CONFIG_HZ	/* Internal kernel timer frequency */
 # define USER_HZ	100	/* .. some user interfaces are in "ticks" */
 # define CLOCKS_PER_SEC (USER_HZ)
 #endif
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index b7e6355..56b5197 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -27,12 +27,12 @@
 
 static __inline__ void enable_dma(unsigned int dmanr)
 {
+	ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1);
+
 	if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info,
 			     sparc_ebus_dmas[dmanr].addr,
 			     sparc_ebus_dmas[dmanr].count))
 		BUG();
-
-	ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1);
 }
 
 static __inline__ void disable_dma(unsigned int dmanr)
diff --git a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h
index 0cd6529..a1d25c0 100644
--- a/include/asm-sparc64/thread_info.h
+++ b/include/asm-sparc64/thread_info.h
@@ -220,8 +220,8 @@
 #define TIF_NEWSIGNALS		6	/* wants new-style signals */
 #define TIF_32BIT		7	/* 32-bit binary */
 #define TIF_NEWCHILD		8	/* just-spawned child process */
-/* TIF_* value 9 is available */
-#define TIF_POLLING_NRFLAG	10
+#define TIF_SECCOMP		9	/* secure computing */
+#define TIF_SYSCALL_AUDIT	10	/* syscall auditing active */
 #define TIF_SYSCALL_SUCCESS	11
 /* NOTE: Thread flags >= 12 should be ones we have no interest
  *       in using in assembly, else we can't use the mask as
@@ -229,6 +229,7 @@
  */
 #define TIF_ABI_PENDING		12
 #define TIF_MEMDIE		13
+#define TIF_POLLING_NRFLAG	14
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -239,9 +240,11 @@
 #define _TIF_NEWSIGNALS		(1<<TIF_NEWSIGNALS)
 #define _TIF_32BIT		(1<<TIF_32BIT)
 #define _TIF_NEWCHILD		(1<<TIF_NEWCHILD)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
+#define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SYSCALL_SUCCESS	(1<<TIF_SYSCALL_SUCCESS)
+#define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
+#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_USER_WORK_MASK	((0xff << TI_FLAG_WSAVED_SHIFT) | \
 				 (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index 5b8dcf5..f59144c 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -212,7 +212,7 @@
 #define __NR_epoll_create       193 /* Linux Specific                              */
 #define __NR_epoll_ctl          194 /* Linux Specific                              */
 #define __NR_epoll_wait         195 /* Linux Specific                              */
-/* #define __NR_ulimit          196    Linux Specific                              */
+#define __NR_ioprio_set         196 /* Linux Specific                              */
 #define __NR_getppid            197 /* Linux Specific                              */
 #define __NR_sigaction          198 /* Linux Specific                              */
 #define __NR_sgetmask           199 /* Linux Specific                              */
@@ -234,7 +234,7 @@
 #define __NR_ipc                215 /* Linux Specific                              */
 #define __NR_sigreturn          216 /* Linux Specific                              */
 #define __NR_clone              217 /* Linux Specific                              */
-/* #define __NR_modify_ldt      218    Linux Specific - i386 specific, unused      */
+#define __NR_ioprio_get         218 /* Linux Specific                              */
 #define __NR_adjtimex           219 /* Linux Specific                              */
 #define __NR_sigprocmask        220 /* Linux Specific                              */
 #define __NR_create_module      221 /* Linux Specific                              */
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index 89bff31..7529c9c 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -7,7 +7,9 @@
 #define __UM_MMU_CONTEXT_H
 
 #include "linux/sched.h"
+#include "linux/config.h"
 #include "choose-mode.h"
+#include "um_mmu.h"
 
 #define get_mmu_context(task) do ; while(0)
 #define activate_context(tsk) do ; while(0)
@@ -18,8 +20,6 @@
 {
 }
 
-extern void switch_mm_skas(int mm_fd);
-
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
 			     struct task_struct *tsk)
 {
@@ -30,7 +30,7 @@
 		cpu_set(cpu, next->cpu_vm_mask);
 		if(next != &init_mm)
 			CHOOSE_MODE((void) 0, 
-				    switch_mm_skas(next->context.skas.mm_fd));
+				    switch_mm_skas(&next->context.skas.id));
 	}
 }
 
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index f2f0736..6c813eb 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -15,6 +15,13 @@
 extern void early_idt_handler(void);
 
 extern void mcheck_init(struct cpuinfo_x86 *c);
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#endif
 extern void init_memory_mapping(unsigned long start, unsigned long end);
 
 extern void system_call(void); 
diff --git a/include/asm-xtensa/ipc.h b/include/asm-xtensa/ipc.h
deleted file mode 100644
index a9eed4e..0000000
--- a/include/asm-xtensa/ipc.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * include/asm-xtensa/ipc.h
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file "COPYING" in the main directory of
- * this archive for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_IPC_H
-#define _XTENSA_IPC_H
-
-#include <asm-generic/ipc.h>
-
-#endif	/* _XTENSA_IPC_H */
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
index 64c64dd..6b39d66 100644
--- a/include/asm-xtensa/unistd.h
+++ b/include/asm-xtensa/unistd.h
@@ -13,42 +13,31 @@
 
 #include <linux/linkage.h>
 
-//#define __NR_setup		  0 /* used only by init, to get system going */
 #define __NR_spill		  0
 #define __NR_exit		  1
-#define __NR_fork		  2
 #define __NR_read		  3
 #define __NR_write		  4
 #define __NR_open		  5
 #define __NR_close		  6
-#define __NR_waitpid		  7
 #define __NR_creat		  8
 #define __NR_link		  9
 #define __NR_unlink		 10
 #define __NR_execve		 11
 #define __NR_chdir		 12
-#define __NR_time		 13
 #define __NR_mknod		 14
 #define __NR_chmod		 15
 #define __NR_lchown		 16
 #define __NR_break		 17
-#define __NR_oldstat		 18
 #define __NR_lseek		 19
 #define __NR_getpid		 20
 #define __NR_mount		 21
-#define __NR_oldumount		 22
 #define __NR_setuid		 23
 #define __NR_getuid		 24
-#define __NR_stime		 25
 #define __NR_ptrace		 26
-#define __NR_alarm		 27
-#define __NR_oldfstat		 28
-#define __NR_pause		 29
 #define __NR_utime		 30
 #define __NR_stty		 31
 #define __NR_gtty		 32
 #define __NR_access		 33
-#define __NR_nice		 34
 #define __NR_ftime		 35
 #define __NR_sync		 36
 #define __NR_kill		 37
@@ -66,24 +55,18 @@
 #define __NR_geteuid		 49
 #define __NR_getegid		 50
 #define __NR_acct		 51
-#define __NR_umount		 52
 #define __NR_lock		 53
 #define __NR_ioctl		 54
 #define __NR_fcntl		 55
-#define __NR_mpx		 56
 #define __NR_setpgid		 57
 #define __NR_ulimit		 58
-#define __NR_oldolduname	 59
 #define __NR_umask		 60
 #define __NR_chroot		 61
 #define __NR_ustat		 62
 #define __NR_dup2		 63
 #define __NR_getppid		 64
-#define __NR_getpgrp		 65
 #define __NR_setsid		 66
 #define __NR_sigaction		 67
-#define __NR_sgetmask		 68
-#define __NR_ssetmask		 69
 #define __NR_setreuid		 70
 #define __NR_setregid		 71
 #define __NR_sigsuspend		 72
@@ -98,13 +81,10 @@
 #define __NR_setgroups		 81
 #define __NR_select		 82
 #define __NR_symlink		 83
-#define __NR_oldlstat		 84
 #define __NR_readlink		 85
 #define __NR_uselib		 86
 #define __NR_swapon		 87
 #define __NR_reboot		 88
-#define __NR_readdir		 89
-#define __NR_mmap		 90
 #define __NR_munmap		 91
 #define __NR_truncate		 92
 #define __NR_ftruncate		 93
@@ -116,22 +96,18 @@
 #define __NR_statfs		 99
 #define __NR_fstatfs		100
 #define __NR_ioperm		101
-#define __NR_socketcall		102
 #define __NR_syslog		103
 #define __NR_setitimer		104
 #define __NR_getitimer		105
 #define __NR_stat		106
 #define __NR_lstat		107
 #define __NR_fstat		108
-#define __NR_olduname		109
 #define __NR_iopl		110
 #define __NR_vhangup		111
 #define __NR_idle		112
-#define __NR_vm86		113
 #define __NR_wait4		114
 #define __NR_swapoff		115
 #define __NR_sysinfo		116
-#define __NR_ipc		117
 #define __NR_fsync		118
 #define __NR_sigreturn		119
 #define __NR_clone		120
@@ -140,18 +116,15 @@
 #define __NR_modify_ldt		123
 #define __NR_adjtimex		124
 #define __NR_mprotect		125
-#define __NR_sigprocmask	126
 #define __NR_create_module	127
 #define __NR_init_module	128
 #define __NR_delete_module	129
-#define __NR_get_kernel_syms	130
 #define __NR_quotactl		131
 #define __NR_getpgid		132
 #define __NR_fchdir		133
 #define __NR_bdflush		134
 #define __NR_sysfs		135
 #define __NR_personality	136
-#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
 #define __NR_setfsuid		138
 #define __NR_setfsgid		139
 #define __NR__llseek		140
@@ -222,8 +195,6 @@
 #define __NR_capset		205
 #define __NR_sigaltstack	206
 #define __NR_sendfile		207
-#define __NR_streams1		208	/* some people actually want it */
-#define __NR_streams2		209	/* some people actually want it */
 #define __NR_mmap2		210
 #define __NR_truncate64		211
 #define __NR_ftruncate64	212
@@ -234,7 +205,6 @@
 #define __NR_mincore		217
 #define __NR_madvise		218
 #define __NR_getdents64		219
-#define __NR_vfork		220
 
 /* Keep this last; should always equal the last valid call number. */
 #define __NR_Linux_syscalls     220
@@ -448,55 +418,7 @@
 
 
 #ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/syscalls.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-
-#define __NR__exit __NR_exit
-
-static __inline__ _syscall0(int,pause)
-//static __inline__ _syscall1(int,setup,int,magic) FIXME
-static __inline__ _syscall0(int,sync)
-static __inline__ _syscall0(pid_t,setsid)
-static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static __inline__ _syscall1(int,dup,int,fd)
 static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp)
-static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode)
-static __inline__ _syscall1(int,close,int,fd)
-static __inline__ _syscall1(int,_exit,int,exitcode)
-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static __inline__ _syscall1(int,delete_module,const char *,name)
-
-struct stat;
-static __inline__ _syscall2(int,fstat,int,fd,struct stat *,buf)
-static __inline__ _syscall0(pid_t,getpid)
-static __inline__ _syscall2(int,kill,int,pid,int,sig)
-static __inline__ _syscall2(int,stat,const char *, path,struct stat *,buf)
-static __inline__ _syscall1(int,unlink,char *,pathname)
-
-
-
-extern pid_t waitpid(int, int*, int );
-static __inline__ pid_t wait(int * wait_stat)
-{
-	return waitpid(-1,wait_stat,0);
-}
 #endif
 
 /*
@@ -508,30 +430,10 @@
 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
 
 #ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_OLD_STAT
 #define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
 #define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
-
-
 #endif	/* _XTENSA_UNISTD_H */
diff --git a/include/linux/audit.h b/include/linux/audit.h
index bf2ad3b..68aba0c 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -165,7 +165,7 @@
 #define AUDIT_ARCH_SH64		(EM_SH|__AUDIT_ARCH_64BIT)
 #define AUDIT_ARCH_SHEL64	(EM_SH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
 #define AUDIT_ARCH_SPARC	(EM_SPARC)
-#define AUDIT_ARCH_SPARC64	(EM_SPARC64|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_SPARC64	(EM_SPARCV9|__AUDIT_ARCH_64BIT)
 #define AUDIT_ARCH_V850		(EM_V850|__AUDIT_ARCH_LE)
 #define AUDIT_ARCH_X86_64	(EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
 
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 802c91e..9082849 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -19,6 +19,9 @@
 	BH_Dirty,	/* Is dirty */
 	BH_Lock,	/* Is locked */
 	BH_Req,		/* Has been submitted for I/O */
+	BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise
+			  * IO completion of other buffers in the page
+			  */
 
 	BH_Mapped,	/* Has a disk mapping */
 	BH_New,		/* Disk mapping was newly created by get_block */
diff --git a/include/linux/cache.h b/include/linux/cache.h
index 4d767b9..f6b5a46 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -13,6 +13,12 @@
 #define SMP_CACHE_BYTES L1_CACHE_BYTES
 #endif
 
+#if defined(CONFIG_X86) || defined(CONFIG_SPARC64)
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#else
+#define __read_mostly
+#endif
+
 #ifndef ____cacheline_aligned
 #define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
 #endif
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 927daa8..ff7f80f 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -201,7 +201,7 @@
 
 	/* optional */
 	int	(*exit)		(struct cpufreq_policy *policy);
-	int	(*suspend)	(struct cpufreq_policy *policy, u32 state);
+	int	(*suspend)	(struct cpufreq_policy *policy, pm_message_t pmsg);
 	int	(*resume)	(struct cpufreq_policy *policy);
 	struct freq_attr	**attr;
 };
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 387da6a..5e2bcc6 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -61,6 +61,15 @@
 #define CRYPTO_DIR_DECRYPT		0
 
 struct scatterlist;
+struct crypto_tfm;
+
+struct cipher_desc {
+	struct crypto_tfm *tfm;
+	void (*crfn)(void *ctx, u8 *dst, const u8 *src);
+	unsigned int (*prfn)(const struct cipher_desc *desc, u8 *dst,
+			     const u8 *src, unsigned int nbytes);
+	void *info;
+};
 
 /*
  * Algorithms: modular crypto algorithm implementations, managed
@@ -73,6 +82,19 @@
 	                  unsigned int keylen, u32 *flags);
 	void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src);
 	void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src);
+
+	unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
+					u8 *dst, const u8 *src,
+					unsigned int nbytes);
+	unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
+					u8 *dst, const u8 *src,
+					unsigned int nbytes);
+	unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
+					u8 *dst, const u8 *src,
+					unsigned int nbytes);
+	unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
+					u8 *dst, const u8 *src,
+					unsigned int nbytes);
 };
 
 struct digest_alg {
@@ -102,6 +124,7 @@
 	u32 cra_flags;
 	unsigned int cra_blocksize;
 	unsigned int cra_ctxsize;
+	unsigned int cra_alignmask;
 	const char cra_name[CRYPTO_MAX_ALG_NAME];
 
 	union {
@@ -136,7 +159,6 @@
  * and core processing logic.  Managed via crypto_alloc_tfm() and
  * crypto_free_tfm(), as well as the various helpers below.
  */
-struct crypto_tfm;
 
 struct cipher_tfm {
 	void *cit_iv;
@@ -266,6 +288,16 @@
 	return tfm->__crt_alg->cra_digest.dia_digestsize;
 }
 
+static inline unsigned int crypto_tfm_alg_alignmask(struct crypto_tfm *tfm)
+{
+	return tfm->__crt_alg->cra_alignmask;
+}
+
+static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
+{
+	return (void *)&tfm[1];
+}
+
 /*
  * API wrappers.
  */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 047bde3..302ec20 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1435,6 +1435,7 @@
 extern ino_t iunique(struct super_block *, ino_t);
 extern int inode_needs_sync(struct inode *inode);
 extern void generic_delete_inode(struct inode *inode);
+extern void generic_drop_inode(struct inode *inode);
 
 extern struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
 		int (*test)(struct inode *, void *), void *data);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 8d6bf60..7c74001 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -12,8 +12,8 @@
  * GFP bitmasks..
  */
 /* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */
-#define __GFP_DMA	0x01
-#define __GFP_HIGHMEM	0x02
+#define __GFP_DMA	0x01u
+#define __GFP_HIGHMEM	0x02u
 
 /*
  * Action modifiers - doesn't change the zoning
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 390e760..0c31ef0 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -148,7 +148,6 @@
 struct ip_mc_socklist
 {
 	struct ip_mc_socklist	*next;
-	int			count;
 	struct ip_mreqn		multi;
 	unsigned int		sfmode;		/* MCAST_{INCLUDE,EXCLUDE} */
 	struct ip_sf_socklist	*sflist;
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
index 8a453a0..88d5961 100644
--- a/include/linux/ioprio.h
+++ b/include/linux/ioprio.h
@@ -34,9 +34,6 @@
  */
 #define IOPRIO_BE_NR	(8)
 
-asmlinkage int sys_ioprio_set(int, int, int);
-asmlinkage int sys_ioprio_get(int, int);
-
 enum {
 	IOPRIO_WHO_PROCESS = 1,
 	IOPRIO_WHO_PGRP,
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 9b6d051..dce53ac 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -174,6 +174,17 @@
 	__u8 proto;
 };
 
+/*
+ * Struct used for matching a device
+ */
+struct of_device_id
+{
+	char	name[32];
+	char	type[32];
+	char	compatible[128];
+	void	*data;
+};
+
 
 /* PCMCIA */
 
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 8b8d3b9..74b4727 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -34,7 +34,7 @@
 	int mnt_expiry_mark;		/* true if marked for expiry */
 	char *mnt_devname;		/* Name of device e.g. /dev/dsk/hda1 */
 	struct list_head mnt_list;
-	struct list_head mnt_fslink;	/* link in fs-specific expiry list */
+	struct list_head mnt_expire;	/* link in fs-specific expiry list */
 	struct namespace *mnt_namespace; /* containing namespace */
 };
 
@@ -47,7 +47,7 @@
 
 extern void __mntput(struct vfsmount *mnt);
 
-static inline void _mntput(struct vfsmount *mnt)
+static inline void mntput_no_expire(struct vfsmount *mnt)
 {
 	if (mnt) {
 		if (atomic_dec_and_test(&mnt->mnt_count))
@@ -59,7 +59,7 @@
 {
 	if (mnt) {
 		mnt->mnt_expiry_mark = 0;
-		_mntput(mnt);
+		mntput_no_expire(mnt);
 	}
 }
 
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index 697991b..0e5a86f 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -17,7 +17,8 @@
 
 static inline void put_namespace(struct namespace *namespace)
 {
-	if (atomic_dec_and_test(&namespace->count))
+	if (atomic_dec_and_lock(&namespace->count, &vfsmount_lock))
+		/* releases vfsmount_lock */
 		__put_namespace(namespace);
 }
 
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 5791dfd..6d5a24f 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -124,6 +124,7 @@
 
 int		nfsd_notify_change(struct inode *, struct iattr *);
 int		nfsd_permission(struct svc_export *, struct dentry *, int);
+void		nfsd_sync_dir(struct dentry *dp);
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 #ifdef CONFIG_NFSD_V2_ACL
@@ -230,6 +231,7 @@
 #define	nfserr_reclaim_bad	__constant_htonl(NFSERR_RECLAIM_BAD)
 #define	nfserr_badname		__constant_htonl(NFSERR_BADNAME)
 #define	nfserr_cb_path_down	__constant_htonl(NFSERR_CB_PATH_DOWN)
+#define	nfserr_locked		__constant_htonl(NFSERR_LOCKED)
 
 /* error codes for internal use */
 /* if a request fails due to kmalloc failure, it gets dropped.
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index a84a3fa..8bf23cf 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -203,7 +203,9 @@
 	int			so_is_open_owner; /* 1=openowner,0=lockowner */
 	u32                     so_id;
 	struct nfs4_client *    so_client;
-	u32                     so_seqid;    
+	/* after increment in ENCODE_SEQID_OP_TAIL, represents the next
+	 * sequence id expected from the client: */
+	u32                     so_seqid;
 	struct xdr_netobj       so_owner;     /* open owner name */
 	int                     so_confirmed; /* successful OPEN_CONFIRM? */
 	struct nfs4_replay	so_replay;
@@ -235,6 +237,10 @@
 *       st_perlockowner: (open stateid) list of lock nfs4_stateowners
 * 	st_access_bmap: used only for open stateid
 * 	st_deny_bmap: used only for open stateid
+*	st_openstp: open stateid lock stateid was derived from
+*
+* XXX: open stateids and lock stateids have diverged sufficiently that
+* we should consider defining separate structs for the two cases.
 */
 
 struct nfs4_stateid {
@@ -248,6 +254,7 @@
 	struct file                 * st_vfs_file;
 	unsigned long                 st_access_bmap;
 	unsigned long                 st_deny_bmap;
+	struct nfs4_stateid         * st_openstp;
 };
 
 /* flags for preprocess_seqid_op() */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 14b9504..5d4a990 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -300,20 +300,26 @@
 #include <asm/system.h>
 
 extern void	       __kfree_skb(struct sk_buff *skb);
-extern struct sk_buff *alloc_skb(unsigned int size, int priority);
+extern struct sk_buff *alloc_skb(unsigned int size,
+				 unsigned int __nocast priority);
 extern struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
-					    unsigned int size, int priority);
+					    unsigned int size,
+					    unsigned int __nocast priority);
 extern void	       kfree_skbmem(struct sk_buff *skb);
-extern struct sk_buff *skb_clone(struct sk_buff *skb, int priority);
-extern struct sk_buff *skb_copy(const struct sk_buff *skb, int priority);
-extern struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask);
+extern struct sk_buff *skb_clone(struct sk_buff *skb,
+				 unsigned int __nocast priority);
+extern struct sk_buff *skb_copy(const struct sk_buff *skb,
+				unsigned int __nocast priority);
+extern struct sk_buff *pskb_copy(struct sk_buff *skb,
+				 unsigned int __nocast gfp_mask);
 extern int	       pskb_expand_head(struct sk_buff *skb,
-					int nhead, int ntail, int gfp_mask);
+					int nhead, int ntail,
+					unsigned int __nocast gfp_mask);
 extern struct sk_buff *skb_realloc_headroom(struct sk_buff *skb,
 					    unsigned int headroom);
 extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
 				       int newheadroom, int newtailroom,
-				       int priority);
+				       unsigned int __nocast priority);
 extern struct sk_buff *		skb_pad(struct sk_buff *skb, int pad);
 #define dev_kfree_skb(a)	kfree_skb(a)
 extern void	      skb_over_panic(struct sk_buff *skb, int len,
@@ -464,7 +470,8 @@
  *
  *	NULL is returned on a memory allocation failure.
  */
-static inline struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
+static inline struct sk_buff *skb_share_check(struct sk_buff *skb,
+					      unsigned int __nocast pri)
 {
 	might_sleep_if(pri & __GFP_WAIT);
 	if (skb_shared(skb)) {
@@ -1001,7 +1008,7 @@
  *	%NULL is returned in there is no free memory.
  */
 static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
-					      int gfp_mask)
+					      unsigned int __nocast gfp_mask)
 {
 	struct sk_buff *skb = alloc_skb(length + 16, gfp_mask);
 	if (likely(skb))
@@ -1114,8 +1121,8 @@
  *	If there is no free memory -ENOMEM is returned, otherwise zero
  *	is returned and the old skb data released.
  */
-extern int __skb_linearize(struct sk_buff *skb, int gfp);
-static inline int skb_linearize(struct sk_buff *skb, int gfp)
+extern int __skb_linearize(struct sk_buff *skb, unsigned int __nocast gfp);
+static inline int skb_linearize(struct sk_buff *skb, unsigned int __nocast gfp)
 {
 	return __skb_linearize(skb, gfp);
 }
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 76cf7e6..4c8e552 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -65,7 +65,7 @@
 extern void kmem_cache_free(kmem_cache_t *, void *);
 extern unsigned int kmem_cache_size(kmem_cache_t *);
 extern const char *kmem_cache_name(kmem_cache_t *);
-extern kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags);
+extern kmem_cache_t *kmem_find_general_cachep(size_t size, unsigned int __nocast gfpflags);
 
 /* Size description struct for general caches. */
 struct cache_sizes {
@@ -105,7 +105,7 @@
 
 #ifdef CONFIG_NUMA
 extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node);
-extern void *kmalloc_node(size_t size, int flags, int node);
+extern void *kmalloc_node(size_t size, unsigned int __nocast flags, int node);
 #else
 static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node)
 {
diff --git a/include/linux/string.h b/include/linux/string.h
index 93994c6..dab2652ac 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -88,7 +88,7 @@
 extern void * memchr(const void *,int,__kernel_size_t);
 #endif
 
-extern char *kstrdup(const char *s, int gfp);
+extern char *kstrdup(const char *s, unsigned int __nocast gfp);
 
 #ifdef __cplusplus
 }
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 2343f99..c75954f 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -148,7 +148,7 @@
 #define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
 
 /* linux/mm/oom_kill.c */
-extern void out_of_memory(unsigned int __nocast gfp_mask);
+extern void out_of_memory(unsigned int __nocast gfp_mask, int order);
 
 /* linux/mm/memory.c */
 extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 52830b6..425f58c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -506,4 +506,7 @@
 asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3,
 			   unsigned long arg4, unsigned long arg5);
 
+asmlinkage long sys_ioprio_set(int which, int who, int ioprio);
+asmlinkage long sys_ioprio_get(int which, int who);
+
 #endif
diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h
index 71d6af8..92c8280 100644
--- a/include/net/irda/irda_device.h
+++ b/include/net/irda/irda_device.h
@@ -224,7 +224,7 @@
 /* Interface for internal use */
 static inline int irda_device_txqueue_empty(const struct net_device *dev)
 {
-	return (skb_queue_len(&dev->qdisc->q) == 0);
+	return skb_queue_empty(&dev->qdisc->q);
 }
 int  irda_device_set_raw_mode(struct net_device* self, int status);
 struct net_device *alloc_irdadev(int sizeof_priv);
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 47727c7..7435528 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -582,7 +582,6 @@
 void sctp_chunk_fail(struct sctp_chunk *, int error);
 int sctp_chunk_abandoned(struct sctp_chunk *);
 
-
 /* RFC2960 1.4 Key Terms
  *
  * o Chunk: A unit of information within an SCTP packet, consisting of
@@ -592,13 +591,8 @@
  * each chunk as well as a few other header pointers...
  */
 struct sctp_chunk {
-	/* These first three elements MUST PRECISELY match the first
-	 * three elements of struct sk_buff.  This allows us to reuse
-	 * all the skb_* queue management functions.
-	 */
-	struct sctp_chunk *next;
-	struct sctp_chunk *prev;
-	struct sk_buff_head *list;
+	struct list_head list;
+
 	atomic_t refcnt;
 
 	/* This is our link to the per-transport transmitted list.  */
@@ -717,7 +711,7 @@
 	__u32 vtag;
 
 	/* This contains the payload chunks.  */
-	struct sk_buff_head chunks;
+	struct list_head chunk_list;
 
 	/* This is the overhead of the sctp and ip headers. */
 	size_t overhead;
@@ -974,7 +968,7 @@
 	/* This is actually a queue of sctp_chunk each
 	 * containing a partially decoded packet.
 	 */
-	struct sk_buff_head in;
+	struct list_head in_chunk_list;
 	/* This is the packet which is currently off the in queue and is
 	 * being worked on through the inbound chunk processing.
 	 */
@@ -1017,7 +1011,7 @@
 	struct sctp_association *asoc;
 
 	/* Data pending that has never been transmitted.  */
-	struct sk_buff_head out;
+	struct list_head out_chunk_list;
 
 	unsigned out_qlen;	/* Total length of queued data chunks. */
 
@@ -1025,7 +1019,7 @@
 	unsigned error;
 
 	/* These are control chunks we want to send.  */
-	struct sk_buff_head control;
+	struct list_head control_chunk_list;
 
 	/* These are chunks that have been sacked but are above the
 	 * CTSN, or cumulative tsn ack point.
@@ -1672,7 +1666,7 @@
 	 *  which already resides in sctp_outq.	 Please move this
 	 *  queue and its supporting logic down there.	--piggy]
 	 */
-	struct sk_buff_head addip_chunks;
+	struct list_head addip_chunk_list;
 
 	/* ADDIP Section 4.1 ASCONF Chunk Procedures
 	 *
diff --git a/include/net/sock.h b/include/net/sock.h
index 7b76f89..a1042d0 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -684,16 +684,17 @@
 #define bh_lock_sock(__sk)	spin_lock(&((__sk)->sk_lock.slock))
 #define bh_unlock_sock(__sk)	spin_unlock(&((__sk)->sk_lock.slock))
 
-extern struct sock		*sk_alloc(int family, int priority,
+extern struct sock		*sk_alloc(int family,
+					  unsigned int __nocast priority,
 					  struct proto *prot, int zero_it);
 extern void			sk_free(struct sock *sk);
 
 extern struct sk_buff		*sock_wmalloc(struct sock *sk,
 					      unsigned long size, int force,
-					      int priority);
+					      unsigned int __nocast priority);
 extern struct sk_buff		*sock_rmalloc(struct sock *sk,
 					      unsigned long size, int force,
-					      int priority);
+					      unsigned int __nocast priority);
 extern void			sock_wfree(struct sk_buff *skb);
 extern void			sock_rfree(struct sk_buff *skb);
 
@@ -708,7 +709,8 @@
 						     unsigned long size,
 						     int noblock,
 						     int *errcode);
-extern void *sock_kmalloc(struct sock *sk, int size, int priority);
+extern void *sock_kmalloc(struct sock *sk, int size,
+			  unsigned int __nocast priority);
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
 extern void sk_send_sigurg(struct sock *sk);
 
@@ -1132,7 +1134,8 @@
 }
 
 static inline struct sk_buff *sk_stream_alloc_pskb(struct sock *sk,
-						   int size, int mem, int gfp)
+						   int size, int mem,
+						   unsigned int __nocast gfp)
 {
 	struct sk_buff *skb;
 	int hdr_len;
@@ -1155,7 +1158,8 @@
 }
 
 static inline struct sk_buff *sk_stream_alloc_skb(struct sock *sk,
-						  int size, int gfp)
+						  int size,
+						  unsigned int __nocast gfp)
 {
 	return sk_stream_alloc_pskb(sk, size, 0, gfp);
 }
@@ -1188,7 +1192,7 @@
 	return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf / 2);
 }
 
-static inline int gfp_any(void)
+static inline unsigned int __nocast gfp_any(void)
 {
 	return in_softirq() ? GFP_ATOMIC : GFP_KERNEL;
 }
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a166918..f4f9aba 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -860,7 +860,8 @@
 extern void tcp_send_partial(struct sock *);
 extern int  tcp_write_wakeup(struct sock *);
 extern void tcp_send_fin(struct sock *sk);
-extern void tcp_send_active_reset(struct sock *sk, int priority);
+extern void tcp_send_active_reset(struct sock *sk,
+                                  unsigned int __nocast priority);
 extern int  tcp_send_synack(struct sock *);
 extern void tcp_push_one(struct sock *, unsigned int mss_now);
 extern void tcp_send_ack(struct sock *sk);
@@ -991,7 +992,7 @@
 
 static inline void tcp_fast_path_check(struct sock *sk, struct tcp_sock *tp)
 {
-	if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
+	if (skb_queue_empty(&tp->out_of_order_queue) &&
 	    tp->rcv_wnd &&
 	    atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
 	    !tp->urg_data)
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index b42ddc0..2cab39f 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -68,21 +68,9 @@
 #define RES_ALLOCATED			0x20
 #define RES_REMOVED			0x40
 
-typedef struct servinfo_t {
-    char	Signature[2];
-    u_int	Count;
-    u_int	Revision;
-    u_int	CSLevel;
-    char	*VendorString;
-} servinfo_t;
-
 typedef struct event_callback_args_t {
-    client_handle_t client_handle;
-    void	*info;
-    void	*mtdrequest;
-    void	*buffer;
-    void	*misc;
-    void	*client_data;
+	struct pcmcia_device	*client_handle;
+	void			*client_data;
 } event_callback_args_t;
 
 /* for GetConfigurationInfo */
@@ -393,25 +381,25 @@
 
 struct pcmcia_socket;
 
-int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
-int pcmcia_deregister_client(client_handle_t handle);
-int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg);
+int pcmcia_deregister_client(struct pcmcia_device *p_dev);
+int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config);
 int pcmcia_get_first_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_next_window(window_handle_t *win, win_req_t *req);
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status);
+int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status);
 int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
 int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
-int pcmcia_modify_configuration(client_handle_t handle, modconf_t *mod);
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
 int pcmcia_register_client(client_handle_t *handle, client_reg_t *req);
-int pcmcia_release_configuration(client_handle_t handle);
-int pcmcia_release_io(client_handle_t handle, io_req_t *req);
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req);
+int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req);
 int pcmcia_release_window(window_handle_t win);
-int pcmcia_request_configuration(client_handle_t handle, config_req_t *req);
-int pcmcia_request_io(client_handle_t handle, io_req_t *req);
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req);
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh);
-int pcmcia_reset_card(client_handle_t handle, client_req_t *req);
+int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req);
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh);
+int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req);
 int pcmcia_suspend_card(struct pcmcia_socket *skt);
 int pcmcia_resume_card(struct pcmcia_socket *skt);
 int pcmcia_eject_card(struct pcmcia_socket *skt);
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
index 7881d40..c1d1629 100644
--- a/include/pcmcia/cs_types.h
+++ b/include/pcmcia/cs_types.h
@@ -34,8 +34,8 @@
 typedef u_char	cisdata_t;
 typedef u_short	page_t;
 
-struct client_t;
-typedef struct client_t *client_handle_t;
+struct pcmcia_device;
+typedef struct pcmcia_device *client_handle_t;
 
 struct window_t;
 typedef struct window_t *window_handle_t;
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 2b52553..0190e76 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -49,7 +49,6 @@
 } mtd_info_t;
 
 typedef union ds_ioctl_arg_t {
-    servinfo_t		servinfo;
     adjust_t		adjust;
     config_info_t	config;
     tuple_t		tuple;
@@ -65,7 +64,6 @@
     cisdump_t		cisdump;
 } ds_ioctl_arg_t;
 
-#define DS_GET_CARD_SERVICES_INFO	_IOR ('d', 1, servinfo_t)
 #define DS_ADJUST_RESOURCE_INFO		_IOWR('d', 2, adjust_t)
 #define DS_GET_CONFIGURATION_INFO	_IOWR('d', 3, config_info_t)
 #define DS_GET_FIRST_TUPLE		_IOWR('d', 4, tuple_t)
@@ -133,6 +131,8 @@
 
 struct pcmcia_driver {
 	dev_link_t		*(*attach)(void);
+	int (*event)		(event_t event, int priority,
+				 event_callback_args_t *);
 	void			(*detach)(dev_link_t *);
 	struct module		*owner;
 	struct pcmcia_device_id	*id_table;
@@ -159,16 +159,8 @@
 	/* deprecated, a cleaned up version will be moved into this
 	   struct soon */
 	dev_link_t		*instance;
-	struct client_t {
-		u_short			client_magic;
-		struct pcmcia_socket	*Socket;
-		u_char			Function;
-		u_int			state;
-		event_t			EventMask;
-		int (*event_handler)	(event_t event, int priority,
-					 event_callback_args_t *);
-		event_callback_args_t 	event_callback_args;
-	}			client;
+	event_callback_args_t 	event_callback_args;
+	u_int			state;
 
 	/* information about this device */
 	u8			has_manf_id:1;
@@ -193,8 +185,8 @@
 #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
 #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
 
-#define handle_to_pdev(handle) container_of(handle, struct pcmcia_device, client);
-#define handle_to_dev(handle) ((container_of(handle, struct pcmcia_device, client))->dev)
+#define handle_to_pdev(handle) (handle)
+#define handle_to_dev(handle) (handle->dev)
 
 /* error reporting */
 void cs_error(client_handle_t handle, int func, int ret);
diff --git a/include/pcmcia/version.h b/include/pcmcia/version.h
index eb88263..5ad9c5e 100644
--- a/include/pcmcia/version.h
+++ b/include/pcmcia/version.h
@@ -1,4 +1,3 @@
 /* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */
 
-#define CS_RELEASE "3.1.22"
-#define CS_RELEASE_CODE 0x3116
+/* This file will be removed, please don't include it */
diff --git a/init/Kconfig b/init/Kconfig
index b1091d7..75755ef 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -174,7 +174,7 @@
 
 config AUDITSYSCALL
 	bool "Enable system-call auditing support"
-	depends on AUDIT && (X86 || PPC || PPC64 || ARCH_S390 || IA64 || UML)
+	depends on AUDIT && (X86 || PPC || PPC64 || ARCH_S390 || IA64 || UML || SPARC64)
 	default y if SECURITY_SELINUX
 	help
 	  Enable low-overhead system-call auditing infrastructure that
diff --git a/ipc/compat.c b/ipc/compat.c
index 70e4e4e..3881d56 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -572,6 +572,7 @@
 	err |= __put_user(smi->shmmni, &up->shmmni);
 	err |= __put_user(smi->shmseg, &up->shmseg);
 	err |= __put_user(smi->shmall, &up->shmall);
+	return err;
 }
 
 static inline int put_compat_shm_info(struct shm_info __user *ip,
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index fb8de63..c51a4d9 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -234,6 +234,16 @@
 {
 	int error;
 
+	if (!swsusp_resume_device) {
+		if (!strlen(resume_file))
+			return -ENOENT;
+		swsusp_resume_device = name_to_dev_t(resume_file);
+		pr_debug("swsusp: Resume From Partition %s\n", resume_file);
+	} else {
+		pr_debug("swsusp: Resume From Partition %d:%d\n",
+			 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+	}
+
 	if (noresume) {
 		/**
 		 * FIXME: If noresume is specified, we need to find the partition
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 0a08664..3bd0d26 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -59,6 +59,7 @@
 	int todo;
 	unsigned long start_time;
 	struct task_struct *g, *p;
+	unsigned long flags;
 
 	printk( "Stopping tasks: " );
 	start_time = jiffies;
@@ -66,12 +67,9 @@
 		todo = 0;
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
-			unsigned long flags;
 			if (!freezeable(p))
 				continue;
-			if ((frozen(p)) ||
-			    (p->state == TASK_TRACED) ||
-			    (p->state == TASK_STOPPED))
+			if (frozen(p))
 				continue;
 
 			freeze(p);
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index c285fc5..7d7801c 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -869,13 +869,6 @@
 
 asmlinkage int swsusp_save(void)
 {
-	int error = 0;
-
-	if ((error = swsusp_swap_check())) {
-		printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
-				"swapon -a!\n");
-		return error;
-	}
 	return suspend_prepare_image();
 }
 
@@ -892,14 +885,20 @@
 	 * at resume time, and evil weirdness ensues.
 	 */
 	if ((error = device_power_down(PMSG_FREEZE))) {
-		printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
 		local_irq_enable();
-		swsusp_free();
 		return error;
 	}
+
+	if ((error = swsusp_swap_check())) {
+		printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
+				"swapon -a!\n");
+		local_irq_enable();
+		return error;
+	}
+
 	save_processor_state();
 	if ((error = swsusp_arch_suspend()))
-		swsusp_free();
+		printk("Error %d suspending\n", error);
 	/* Restore control flow magically appears here */
 	restore_processor_state();
 	BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -1166,9 +1165,9 @@
 static const char * sanity_check(void)
 {
 	dump_info();
-	if(swsusp_info.version_code != LINUX_VERSION_CODE)
+	if (swsusp_info.version_code != LINUX_VERSION_CODE)
 		return "kernel version";
-	if(swsusp_info.num_physpages != num_physpages)
+	if (swsusp_info.num_physpages != num_physpages)
 		return "memory size";
 	if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
 		return "system type";
@@ -1356,16 +1355,6 @@
 {
 	int error;
 
-	if (!swsusp_resume_device) {
-		if (!strlen(resume_file))
-			return -ENOENT;
-		swsusp_resume_device = name_to_dev_t(resume_file);
-		pr_debug("swsusp: Resume From Partition %s\n", resume_file);
-	} else {
-		pr_debug("swsusp: Resume From Partition %d:%d\n",
-			 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
-	}
-
 	resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
 	if (!IS_ERR(resume_bdev)) {
 		set_blocksize(resume_bdev, PAGE_SIZE);
diff --git a/kernel/profile.c b/kernel/profile.c
index ad8cbb7..f89248e 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -35,11 +35,11 @@
 #define NR_PROFILE_GRP		(NR_PROFILE_HIT/PROFILE_GRPSZ)
 
 /* Oprofile timer tick hook */
-int (*timer_hook)(struct pt_regs *);
+int (*timer_hook)(struct pt_regs *) __read_mostly;
 
 static atomic_t *prof_buffer;
 static unsigned long prof_len, prof_shift;
-static int prof_on;
+static int prof_on __read_mostly;
 static cpumask_t prof_cpu_mask = CPU_MASK_ALL;
 #ifdef CONFIG_SMP
 static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
diff --git a/kernel/sched.c b/kernel/sched.c
index 5f2182d..4107db0 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3877,6 +3877,13 @@
 
 static inline void __cond_resched(void)
 {
+	/*
+	 * The BKS might be reacquired before we have dropped
+	 * PREEMPT_ACTIVE, which could trigger a second
+	 * cond_resched() call.
+	 */
+	if (unlikely(preempt_count()))
+		return;
 	do {
 		add_preempt_count(PREEMPT_ACTIVE);
 		schedule();
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 04d6643..10bed1c 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -58,7 +58,7 @@
 #define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
 #define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2)
 
-static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH];
+static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH] __read_mostly;
 
 /*
  * Radix tree node cache.
diff --git a/mm/mempool.c b/mm/mempool.c
index 9a72f7d..65f2957 100644
--- a/mm/mempool.c
+++ b/mm/mempool.c
@@ -205,7 +205,7 @@
 	void *element;
 	unsigned long flags;
 	wait_queue_t wait;
-	int gfp_temp;
+	unsigned int gfp_temp;
 
 	might_sleep_if(gfp_mask & __GFP_WAIT);
 
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 59666d9..1e56076 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -253,14 +253,16 @@
  * OR try to be smart about which process to kill. Note that we
  * don't have to be perfect here, we just have to be good.
  */
-void out_of_memory(unsigned int __nocast gfp_mask)
+void out_of_memory(unsigned int __nocast gfp_mask, int order)
 {
 	struct mm_struct *mm = NULL;
 	task_t * p;
 
-	printk("oom-killer: gfp_mask=0x%x\n", gfp_mask);
-	/* print memory stats */
-	show_mem();
+	if (printk_ratelimit()) {
+		printk("oom-killer: gfp_mask=0x%x, order=%d\n",
+			gfp_mask, order);
+		show_mem();
+	}
 
 	read_lock(&tasklist_lock);
 retry:
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3c9f7f8..1d6ba6a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -897,12 +897,6 @@
 	cond_resched();
 
 	if (likely(did_some_progress)) {
-		/*
-		 * Go through the zonelist yet one more time, keep
-		 * very high watermark here, this is only to catch
-		 * a parallel oom killing, we must fail if we're still
-		 * under heavy pressure.
-		 */
 		for (i = 0; (z = zones[i]) != NULL; i++) {
 			if (!zone_watermark_ok(z, order, z->pages_min,
 					       classzone_idx, can_try_harder,
@@ -936,7 +930,7 @@
 				goto got_pg;
 		}
 
-		out_of_memory(gfp_mask);
+		out_of_memory(gfp_mask, order);
 		goto restart;
 	}
 
diff --git a/mm/slab.c b/mm/slab.c
index 122d031..c9e706d 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -584,7 +584,8 @@
 	return cachep->array[smp_processor_id()];
 }
 
-static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags)
+static inline kmem_cache_t *__find_general_cachep(size_t size,
+						unsigned int __nocast gfpflags)
 {
 	struct cache_sizes *csizep = malloc_sizes;
 
@@ -608,7 +609,8 @@
 	return csizep->cs_cachep;
 }
 
-kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags)
+kmem_cache_t *kmem_find_general_cachep(size_t size,
+		unsigned int __nocast gfpflags)
 {
 	return __find_general_cachep(size, gfpflags);
 }
@@ -2100,7 +2102,7 @@
 #if DEBUG
 static void *
 cache_alloc_debugcheck_after(kmem_cache_t *cachep,
-			unsigned long flags, void *objp, void *caller)
+			unsigned int __nocast flags, void *objp, void *caller)
 {
 	if (!objp)	
 		return objp;
@@ -2372,6 +2374,9 @@
 	struct slab *slabp;
 	kmem_bufctl_t next;
 
+	if (nodeid == -1)
+		return kmem_cache_alloc(cachep, flags);
+
 	for (loop = 0;;loop++) {
 		struct list_head *q;
 
@@ -2439,7 +2444,7 @@
 }
 EXPORT_SYMBOL(kmem_cache_alloc_node);
 
-void *kmalloc_node(size_t size, int flags, int node)
+void *kmalloc_node(size_t size, unsigned int __nocast flags, int node)
 {
 	kmem_cache_t *cachep;
 
@@ -3091,7 +3096,7 @@
  * @s: the string to duplicate
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
  */
-char *kstrdup(const char *s, int gfp)
+char *kstrdup(const char *s, unsigned int __nocast gfp)
 {
 	size_t len;
 	char *buf;
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index 2e341de..901eff7 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -213,7 +213,7 @@
 	return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
-static int cmtp_process_transmit(struct cmtp_session *session)
+static void cmtp_process_transmit(struct cmtp_session *session)
 {
 	struct sk_buff *skb, *nskb;
 	unsigned char *hdr;
@@ -223,7 +223,7 @@
 
 	if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
 		BT_ERR("Can't allocate memory for new frame");
-		return -ENOMEM;
+		return;
 	}
 
 	while ((skb = skb_dequeue(&session->transmit))) {
@@ -275,8 +275,6 @@
 	cmtp_send_frame(session, nskb->data, nskb->len);
 
 	kfree_skb(nskb);
-
-	return skb_queue_len(&session->transmit);
 }
 
 static int cmtp_session(void *arg)
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index affbc55..de8af5f 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -428,7 +428,7 @@
 	return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
-static int hidp_process_transmit(struct hidp_session *session)
+static void hidp_process_transmit(struct hidp_session *session)
 {
 	struct sk_buff *skb;
 
@@ -453,9 +453,6 @@
 		hidp_set_timer(session);
 		kfree_skb(skb);
 	}
-
-	return skb_queue_len(&session->ctrl_transmit) +
-				skb_queue_len(&session->intr_transmit);
 }
 
 static int hidp_session(void *arg)
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index f3f6355..63a123c 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -590,8 +590,11 @@
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
-		if (skb_queue_len(&sk->sk_receive_queue) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) ||
-				signal_pending(current) || !timeo)
+		if (!skb_queue_empty(&sk->sk_receive_queue) ||
+		    sk->sk_err ||
+		    (sk->sk_shutdown & RCV_SHUTDOWN) ||
+		    signal_pending(current) ||
+		    !timeo)
 			break;
 
 		set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 6d68920..6304590 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -781,7 +781,7 @@
 
 	BT_DBG("tty %p dev %p", tty, dev);
 
-	if (skb_queue_len(&dlc->tx_queue))
+	if (!skb_queue_empty(&dlc->tx_queue))
 		return dlc->mtu;
 
 	return 0;
diff --git a/net/core/dev.c b/net/core/dev.c
index 7f5f62c..ff9dc02 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1127,7 +1127,7 @@
 extern void skb_release_data(struct sk_buff *);
 
 /* Keep head the same: replace data */
-int __skb_linearize(struct sk_buff *skb, int gfp_mask)
+int __skb_linearize(struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
 	unsigned int size;
 	u8 *data;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 733deee..d9f7b06 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -129,7 +129,7 @@
  *	Buffers may only be allocated from interrupts using a @gfp_mask of
  *	%GFP_ATOMIC.
  */
-struct sk_buff *alloc_skb(unsigned int size, int gfp_mask)
+struct sk_buff *alloc_skb(unsigned int size, unsigned int __nocast gfp_mask)
 {
 	struct sk_buff *skb;
 	u8 *data;
@@ -182,7 +182,8 @@
  *	%GFP_ATOMIC.
  */
 struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
-				     unsigned int size, int gfp_mask)
+				     unsigned int size,
+				     unsigned int __nocast gfp_mask)
 {
 	struct sk_buff *skb;
 	u8 *data;
@@ -322,7 +323,7 @@
  *	%GFP_ATOMIC.
  */
 
-struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
+struct sk_buff *skb_clone(struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
 	struct sk_buff *n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
 
@@ -460,7 +461,7 @@
  *	header is going to be modified. Use pskb_copy() instead.
  */
 
-struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
+struct sk_buff *skb_copy(const struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
 	int headerlen = skb->data - skb->head;
 	/*
@@ -499,7 +500,7 @@
  *	The returned buffer has a reference count of 1.
  */
 
-struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask)
+struct sk_buff *pskb_copy(struct sk_buff *skb, unsigned int __nocast gfp_mask)
 {
 	/*
 	 *	Allocate the copy buffer
@@ -557,7 +558,8 @@
  *	reloaded after call to this function.
  */
 
-int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask)
+int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
+		     unsigned int __nocast gfp_mask)
 {
 	int i;
 	u8 *data;
@@ -647,7 +649,8 @@
  *	only by netfilter in the cases when checksum is recalculated? --ANK
  */
 struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
-				int newheadroom, int newtailroom, int gfp_mask)
+				int newheadroom, int newtailroom,
+				unsigned int __nocast gfp_mask)
 {
 	/*
 	 *	Allocate the copy buffer
diff --git a/net/core/sock.c b/net/core/sock.c
index a6ec3ad..8b35ccd 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -622,7 +622,8 @@
  *	@prot: struct proto associated with this new sock instance
  *	@zero_it: if we should zero the newly allocated sock
  */
-struct sock *sk_alloc(int family, int priority, struct proto *prot, int zero_it)
+struct sock *sk_alloc(int family, unsigned int __nocast priority,
+		      struct proto *prot, int zero_it)
 {
 	struct sock *sk = NULL;
 	kmem_cache_t *slab = prot->slab;
@@ -750,7 +751,8 @@
 /*
  * Allocate a skb from the socket's send buffer.
  */
-struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
+struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
+			     unsigned int __nocast priority)
 {
 	if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
 		struct sk_buff * skb = alloc_skb(size, priority);
@@ -765,7 +767,8 @@
 /*
  * Allocate a skb from the socket's receive buffer.
  */ 
-struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
+struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force,
+			     unsigned int __nocast priority)
 {
 	if (force || atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) {
 		struct sk_buff *skb = alloc_skb(size, priority);
@@ -780,7 +783,7 @@
 /* 
  * Allocate a memory block from the socket's option memory buffer.
  */ 
-void *sock_kmalloc(struct sock *sk, int size, int priority)
+void *sock_kmalloc(struct sock *sk, int size, unsigned int __nocast priority)
 {
 	if ((unsigned)size <= sysctl_optmem_max &&
 	    atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) {
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 29bb3cd..96a0280 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -536,7 +536,7 @@
 	 * we are double checking that we are not sending too
 	 * many of these keepalive frames.
 	 */
-	if (skb_queue_len(&scp->other_xmit_queue) == 0)
+	if (skb_queue_empty(&scp->other_xmit_queue))
 		dn_nsp_send_link(sk, DN_NOCHANGE, 0);
 }
 
@@ -1191,7 +1191,7 @@
 	struct dn_scp *scp = DN_SK(sk);
 	int mask = datagram_poll(file, sock, wait);
 
-	if (skb_queue_len(&scp->other_receive_queue))
+	if (!skb_queue_empty(&scp->other_receive_queue))
 		mask |= POLLRDBAND;
 
 	return mask;
@@ -1214,7 +1214,7 @@
 
 	case SIOCATMARK:
 		lock_sock(sk);
-		val = (skb_queue_len(&scp->other_receive_queue) != 0);
+		val = !skb_queue_empty(&scp->other_receive_queue);
 		if (scp->state != DN_RUN)
 			val = -ENOTCONN;
 		release_sock(sk);
@@ -1630,7 +1630,7 @@
 	int len = 0;
 
 	if (flags & MSG_OOB)
-		return skb_queue_len(q) ? 1 : 0;
+		return !skb_queue_empty(q) ? 1 : 0;
 
 	while(skb != (struct sk_buff *)q) {
 		struct dn_skb_cb *cb = DN_SKB_CB(skb);
@@ -1707,7 +1707,7 @@
 		if (sk->sk_err)
 			goto out;
 
-		if (skb_queue_len(&scp->other_receive_queue)) {
+		if (!skb_queue_empty(&scp->other_receive_queue)) {
 			if (!(flags & MSG_OOB)) {
 				msg->msg_flags |= MSG_OOB;
 				if (!scp->other_report) {
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 42abbf3..8cce1fd 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -342,7 +342,8 @@
 
 	dn_nsp_output(sk);
 
-	if (skb_queue_len(&scp->data_xmit_queue) || skb_queue_len(&scp->other_xmit_queue))
+	if (!skb_queue_empty(&scp->data_xmit_queue) ||
+	    !skb_queue_empty(&scp->other_xmit_queue))
 		scp->persist = dn_nsp_persist(sk);
 
 	return 0;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index cb75948..279f57a 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -970,7 +970,8 @@
 		 *	RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently
 		 *	  discarded if to broadcast/multicast.
 		 */
-		if (icmph->type == ICMP_ECHO &&
+		if ((icmph->type == ICMP_ECHO ||
+		     icmph->type == ICMP_TIMESTAMP) &&
 		    sysctl_icmp_echo_ignore_broadcasts) {
 			goto error;
 		}
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 1f31831..5088f90 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1615,9 +1615,10 @@
 {
 	int err;
 	u32 addr = imr->imr_multiaddr.s_addr;
-	struct ip_mc_socklist *iml, *i;
+	struct ip_mc_socklist *iml=NULL, *i;
 	struct in_device *in_dev;
 	struct inet_sock *inet = inet_sk(sk);
+	int ifindex;
 	int count = 0;
 
 	if (!MULTICAST(addr))
@@ -1633,37 +1634,30 @@
 		goto done;
 	}
 
-	iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
-
 	err = -EADDRINUSE;
+	ifindex = imr->imr_ifindex;
 	for (i = inet->mc_list; i; i = i->next) {
-		if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {
-			/* New style additions are reference counted */
-			if (imr->imr_address.s_addr == 0) {
-				i->count++;
-				err = 0;
-			}
+		if (i->multi.imr_multiaddr.s_addr == addr &&
+		    i->multi.imr_ifindex == ifindex)
 			goto done;
-		}
 		count++;
 	}
 	err = -ENOBUFS;
-	if (iml == NULL || count >= sysctl_igmp_max_memberships)
+	if (count >= sysctl_igmp_max_memberships)
 		goto done;
+	iml = (struct ip_mc_socklist *)sock_kmalloc(sk,sizeof(*iml),GFP_KERNEL);
+	if (iml == NULL)
+		goto done;
+
 	memcpy(&iml->multi, imr, sizeof(*imr));
 	iml->next = inet->mc_list;
-	iml->count = 1;
 	iml->sflist = NULL;
 	iml->sfmode = MCAST_EXCLUDE;
 	inet->mc_list = iml;
 	ip_mc_inc_group(in_dev, addr);
-	iml = NULL;
 	err = 0;
-
 done:
 	rtnl_shunlock();
-	if (iml)
-		sock_kfree_s(sk, iml, sizeof(*iml));
 	return err;
 }
 
@@ -1693,30 +1687,25 @@
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct ip_mc_socklist *iml, **imlp;
+	struct in_device *in_dev;
+	u32 group = imr->imr_multiaddr.s_addr;
+	u32 ifindex;
 
 	rtnl_lock();
+	in_dev = ip_mc_find_dev(imr);
+	if (!in_dev) {
+		rtnl_unlock();
+		return -ENODEV;
+	}
+	ifindex = imr->imr_ifindex;
 	for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
-		if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr &&
-		    iml->multi.imr_address.s_addr==imr->imr_address.s_addr &&
-		    (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) {
-			struct in_device *in_dev;
-
-			in_dev = inetdev_by_index(iml->multi.imr_ifindex);
-			if (in_dev)
-				(void) ip_mc_leave_src(sk, iml, in_dev);
-			if (--iml->count) {
-				rtnl_unlock();
-				if (in_dev)
-					in_dev_put(in_dev);
-				return 0;
-			}
+		if (iml->multi.imr_multiaddr.s_addr == group &&
+		    iml->multi.imr_ifindex == ifindex) {
+			(void) ip_mc_leave_src(sk, iml, in_dev);
 
 			*imlp = iml->next;
 
-			if (in_dev) {
-				ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr);
-				in_dev_put(in_dev);
-			}
+			ip_mc_dec_group(in_dev, group);
 			rtnl_unlock();
 			sock_kfree_s(sk, iml, sizeof(*iml));
 			return 0;
@@ -1736,6 +1725,7 @@
 	struct in_device *in_dev = NULL;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ip_sf_socklist *psl;
+	int leavegroup = 0;
 	int i, j, rv;
 
 	if (!MULTICAST(addr))
@@ -1755,15 +1745,20 @@
 	err = -EADDRNOTAVAIL;
 
 	for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
-		if (memcmp(&pmc->multi, mreqs, 2*sizeof(__u32)) == 0)
+		if (pmc->multi.imr_multiaddr.s_addr == imr.imr_multiaddr.s_addr
+		    && pmc->multi.imr_ifindex == imr.imr_ifindex)
 			break;
 	}
-	if (!pmc)		/* must have a prior join */
+	if (!pmc) {		/* must have a prior join */
+		err = -EINVAL;
 		goto done;
+	}
 	/* if a source filter was set, must be the same mode as before */
 	if (pmc->sflist) {
-		if (pmc->sfmode != omode)
+		if (pmc->sfmode != omode) {
+			err = -EINVAL;
 			goto done;
+		}
 	} else if (pmc->sfmode != omode) {
 		/* allow mode switches for empty-set filters */
 		ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 0, NULL, 0);
@@ -1775,7 +1770,7 @@
 	psl = pmc->sflist;
 	if (!add) {
 		if (!psl)
-			goto done;
+			goto done;	/* err = -EADDRNOTAVAIL */
 		rv = !0;
 		for (i=0; i<psl->sl_count; i++) {
 			rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
@@ -1784,7 +1779,13 @@
 				break;
 		}
 		if (rv)		/* source not found */
+			goto done;	/* err = -EADDRNOTAVAIL */
+
+		/* special case - (INCLUDE, empty) == LEAVE_GROUP */
+		if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {
+			leavegroup = 1;
 			goto done;
+		}
 
 		/* update the interface filter */
 		ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, 
@@ -1842,18 +1843,21 @@
 		&mreqs->imr_sourceaddr, 1);
 done:
 	rtnl_shunlock();
+	if (leavegroup)
+		return ip_mc_leave_group(sk, &imr);
 	return err;
 }
 
 int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
 {
-	int err;
+	int err = 0;
 	struct ip_mreqn	imr;
 	u32 addr = msf->imsf_multiaddr;
 	struct ip_mc_socklist *pmc;
 	struct in_device *in_dev;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ip_sf_socklist *newpsl, *psl;
+	int leavegroup = 0;
 
 	if (!MULTICAST(addr))
 		return -EINVAL;
@@ -1872,15 +1876,22 @@
 		err = -ENODEV;
 		goto done;
 	}
-	err = -EADDRNOTAVAIL;
+
+	/* special case - (INCLUDE, empty) == LEAVE_GROUP */
+	if (msf->imsf_fmode == MCAST_INCLUDE && msf->imsf_numsrc == 0) {
+		leavegroup = 1;
+		goto done;
+	}
 
 	for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
 		if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
 		    pmc->multi.imr_ifindex == imr.imr_ifindex)
 			break;
 	}
-	if (!pmc)		/* must have a prior join */
+	if (!pmc) {		/* must have a prior join */
+		err = -EINVAL;
 		goto done;
+	}
 	if (msf->imsf_numsrc) {
 		newpsl = (struct ip_sf_socklist *)sock_kmalloc(sk,
 				IP_SFLSIZE(msf->imsf_numsrc), GFP_KERNEL);
@@ -1909,8 +1920,11 @@
 			0, NULL, 0);
 	pmc->sflist = newpsl;
 	pmc->sfmode = msf->imsf_fmode;
+	err = 0;
 done:
 	rtnl_shunlock();
+	if (leavegroup)
+		err = ip_mc_leave_group(sk, &imr);
 	return err;
 }
 
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index f8b172f..fc7c481 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -677,11 +677,11 @@
 				mreq.imr_address.s_addr = mreqs.imr_interface;
 				mreq.imr_ifindex = 0;
 				err = ip_mc_join_group(sk, &mreq);
-				if (err)
+				if (err && err != -EADDRINUSE)
 					break;
 				omode = MCAST_INCLUDE;
 				add = 1;
-			} else /*IP_DROP_SOURCE_MEMBERSHIP */ {
+			} else /* IP_DROP_SOURCE_MEMBERSHIP */ {
 				omode = MCAST_INCLUDE;
 				add = 0;
 			}
@@ -754,7 +754,7 @@
 				mreq.imr_address.s_addr = 0;
 				mreq.imr_ifindex = greqs.gsr_interface;
 				err = ip_mc_join_group(sk, &mreq);
-				if (err)
+				if (err && err != -EADDRINUSE)
 					break;
 				greqs.gsr_interface = mreq.imr_ifindex;
 				omode = MCAST_INCLUDE;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 29894c7..ddb6ce4 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1105,7 +1105,7 @@
 	struct sk_buff *skb;
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	NET_ADD_STATS_USER(LINUX_MIB_TCPPREQUEUED, skb_queue_len(&tp->ucopy.prequeue));
+	NET_INC_STATS_USER(LINUX_MIB_TCPPREQUEUED);
 
 	/* RX process wants to run with disabled BHs, though it is not
 	 * necessary */
@@ -1369,7 +1369,7 @@
 			 * is not empty. It is more elegant, but eats cycles,
 			 * unfortunately.
 			 */
-			if (skb_queue_len(&tp->ucopy.prequeue))
+			if (!skb_queue_empty(&tp->ucopy.prequeue))
 				goto do_prequeue;
 
 			/* __ Set realtime policy in scheduler __ */
@@ -1394,7 +1394,7 @@
 			}
 
 			if (tp->rcv_nxt == tp->copied_seq &&
-			    skb_queue_len(&tp->ucopy.prequeue)) {
+			    !skb_queue_empty(&tp->ucopy.prequeue)) {
 do_prequeue:
 				tcp_prequeue_process(sk);
 
@@ -1476,7 +1476,7 @@
 	} while (len > 0);
 
 	if (user_recv) {
-		if (skb_queue_len(&tp->ucopy.prequeue)) {
+		if (!skb_queue_empty(&tp->ucopy.prequeue)) {
 			int chunk;
 
 			tp->ucopy.len = copied > 0 ? len : 0;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 8de2f10..53a8a53 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2802,7 +2802,7 @@
 	int this_sack;
 
 	/* Empty ofo queue, hence, all the SACKs are eaten. Clear. */
-	if (skb_queue_len(&tp->out_of_order_queue) == 0) {
+	if (skb_queue_empty(&tp->out_of_order_queue)) {
 		tp->rx_opt.num_sacks = 0;
 		tp->rx_opt.eff_sacks = tp->rx_opt.dsack;
 		return;
@@ -2935,13 +2935,13 @@
 		if(th->fin)
 			tcp_fin(skb, sk, th);
 
-		if (skb_queue_len(&tp->out_of_order_queue)) {
+		if (!skb_queue_empty(&tp->out_of_order_queue)) {
 			tcp_ofo_queue(sk);
 
 			/* RFC2581. 4.2. SHOULD send immediate ACK, when
 			 * gap in queue is filled.
 			 */
-			if (!skb_queue_len(&tp->out_of_order_queue))
+			if (skb_queue_empty(&tp->out_of_order_queue))
 				tp->ack.pingpong = 0;
 		}
 
@@ -3249,9 +3249,8 @@
 	 * This must not ever occur. */
 
 	/* First, purge the out_of_order queue. */
-	if (skb_queue_len(&tp->out_of_order_queue)) {
-		NET_ADD_STATS_BH(LINUX_MIB_OFOPRUNED, 
-				 skb_queue_len(&tp->out_of_order_queue));
+	if (!skb_queue_empty(&tp->out_of_order_queue)) {
+		NET_INC_STATS_BH(LINUX_MIB_OFOPRUNED);
 		__skb_queue_purge(&tp->out_of_order_queue);
 
 		/* Reset SACK state.  A conforming SACK implementation will
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e041d05..e3f8ea1 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1613,7 +1613,7 @@
  * was unread data in the receive queue.  This behavior is recommended
  * by draft-ietf-tcpimpl-prob-03.txt section 3.10.  -DaveM
  */
-void tcp_send_active_reset(struct sock *sk, int priority)
+void tcp_send_active_reset(struct sock *sk, unsigned int __nocast priority)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index b127b44..0084227 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -231,11 +231,10 @@
 	}
 	tp->ack.pending &= ~TCP_ACK_TIMER;
 
-	if (skb_queue_len(&tp->ucopy.prequeue)) {
+	if (!skb_queue_empty(&tp->ucopy.prequeue)) {
 		struct sk_buff *skb;
 
-		NET_ADD_STATS_BH(LINUX_MIB_TCPSCHEDULERFAILED, 
-				 skb_queue_len(&tp->ucopy.prequeue));
+		NET_INC_STATS_BH(LINUX_MIB_TCPSCHEDULERFAILED);
 
 		while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
 			sk->sk_backlog_rcv(sk, skb);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 562fcd1..29fed6e 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -281,7 +281,7 @@
 	}
 	write_unlock_bh(&ipv6_sk_mc_lock);
 
-	return -ENOENT;
+	return -EADDRNOTAVAIL;
 }
 
 static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
@@ -386,12 +386,16 @@
 		if (ipv6_addr_equal(&pmc->addr, group))
 			break;
 	}
-	if (!pmc)		/* must have a prior join */
+	if (!pmc) {		/* must have a prior join */
+		err = -EINVAL;
 		goto done;
+	}
 	/* if a source filter was set, must be the same mode as before */
 	if (pmc->sflist) {
-		if (pmc->sfmode != omode)
+		if (pmc->sfmode != omode) {
+			err = -EINVAL;
 			goto done;
+		}
 	} else if (pmc->sfmode != omode) {
 		/* allow mode switches for empty-set filters */
 		ip6_mc_add_src(idev, group, omode, 0, NULL, 0);
@@ -402,7 +406,7 @@
 	psl = pmc->sflist;
 	if (!add) {
 		if (!psl)
-			goto done;
+			goto done;	/* err = -EADDRNOTAVAIL */
 		rv = !0;
 		for (i=0; i<psl->sl_count; i++) {
 			rv = memcmp(&psl->sl_addr[i], source,
@@ -411,7 +415,7 @@
 				break;
 		}
 		if (rv)		/* source not found */
-			goto done;
+			goto done;	/* err = -EADDRNOTAVAIL */
 
 		/* special case - (INCLUDE, empty) == LEAVE_GROUP */
 		if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {
@@ -488,6 +492,7 @@
 	struct inet6_dev *idev;
 	struct ipv6_pinfo *inet6 = inet6_sk(sk);
 	struct ip6_sf_socklist *newpsl, *psl;
+	int leavegroup = 0;
 	int i, err;
 
 	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
@@ -503,7 +508,12 @@
 	if (!idev)
 		return -ENODEV;
 	dev = idev->dev;
-	err = -EADDRNOTAVAIL;
+
+	err = 0;
+	if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
+		leavegroup = 1;
+		goto done;
+	}
 
 	for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
 		if (pmc->ifindex != gsf->gf_interface)
@@ -511,8 +521,10 @@
 		if (ipv6_addr_equal(&pmc->addr, group))
 			break;
 	}
-	if (!pmc)		/* must have a prior join */
+	if (!pmc) {		/* must have a prior join */
+		err = -EINVAL;
 		goto done;
+	}
 	if (gsf->gf_numsrc) {
 		newpsl = (struct ip6_sf_socklist *)sock_kmalloc(sk,
 				IP6_SFLSIZE(gsf->gf_numsrc), GFP_ATOMIC);
@@ -544,10 +556,13 @@
 		(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
 	pmc->sflist = newpsl;
 	pmc->sfmode = gsf->gf_fmode;
+	err = 0;
 done:
 	read_unlock_bh(&idev->lock);
 	in6_dev_put(idev);
 	dev_put(dev);
+	if (leavegroup)
+		err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
 	return err;
 }
 
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 046ad07..7029618 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -445,9 +445,8 @@
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	/* Don't disconnect until all data frames are successfully sent */
-	if (skb_queue_len(&self->txq) > 0) {
+	if (!skb_queue_empty(&self->txq)) {
 		self->disconnect_pending = TRUE;
-
 		return;
 	}
 
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 1cd89f5..a505b54 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -191,7 +191,7 @@
 	 * Send out the RR frames faster if our own transmit queue is empty, or
 	 * if the peer is busy. The effect is a much faster conversation
 	 */
-	if ((skb_queue_len(&self->txq) == 0) || (self->remote_busy)) {
+	if (skb_queue_empty(&self->txq) || self->remote_busy) {
 		if (self->fast_RR == TRUE) {
 			/*
 			 *  Assert that the fast poll timer has not reached the
@@ -263,7 +263,7 @@
 		IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,
 			   skb_queue_len(&self->txq));
 
-		if (skb_queue_len(&self->txq)) {
+		if (!skb_queue_empty(&self->txq)) {
 			/* Prevent race conditions with irlap_data_request() */
 			self->local_busy = TRUE;
 
@@ -1074,7 +1074,7 @@
 #else	/* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/* Window has been adjusted for the max packet
 			 * size, so much simpler... - Jean II */
-			nextfit = (skb_queue_len(&self->txq) > 0);
+			nextfit = !skb_queue_empty(&self->txq);
 #endif	/* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/*
 			 *  Send data with poll bit cleared only if window > 1
@@ -1814,7 +1814,7 @@
 #else	/* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/* Window has been adjusted for the max packet
 			 * size, so much simpler... - Jean II */
-			nextfit = (skb_queue_len(&self->txq) > 0);
+			nextfit = !skb_queue_empty(&self->txq);
 #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 			/*
 			 *  Send data with final bit cleared only if window > 1
@@ -1937,7 +1937,7 @@
 				irlap_data_indication(self, skb, FALSE);
 
 				/* Any pending data requests?  */
-				if ((skb_queue_len(&self->txq) > 0) &&
+				if (!skb_queue_empty(&self->txq) &&
 				    (self->window > 0))
 				{
 					self->ack_required = TRUE;
@@ -2038,7 +2038,7 @@
 			/*
 			 *  Any pending data requests?
 			 */
-			if ((skb_queue_len(&self->txq) > 0) &&
+			if (!skb_queue_empty(&self->txq) &&
 			    (self->window > 0) && !self->remote_busy)
 			{
 				irlap_data_indication(self, skb, TRUE);
@@ -2069,7 +2069,7 @@
 		 */
 		nr_status = irlap_validate_nr_received(self, info->nr);
 		if (nr_status == NR_EXPECTED) {
-			if ((skb_queue_len( &self->txq) > 0) &&
+			if (!skb_queue_empty(&self->txq) &&
 			    (self->window > 0)) {
 				self->remote_busy = FALSE;
 
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 040abe7..6dafbb4 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -1018,11 +1018,10 @@
 	/*
 	 *  We can now fill the window with additional data frames
 	 */
-	while (skb_queue_len( &self->txq) > 0) {
+	while (!skb_queue_empty(&self->txq)) {
 
 		IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__);
-		if ((skb_queue_len( &self->txq) > 0) &&
-		    (self->window > 0)) {
+		if (self->window > 0) {
 			skb = skb_dequeue( &self->txq);
 			IRDA_ASSERT(skb != NULL, return;);
 
@@ -1031,8 +1030,7 @@
 			 *  bit cleared
 			 */
 			if ((self->window > 1) &&
-			    skb_queue_len(&self->txq) > 0)
-			{
+			    !skb_queue_empty(&self->txq)) {
 				irlap_send_data_primary(self, skb);
 			} else {
 				irlap_send_data_primary_poll(self, skb);
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index d091ccf..6602d90 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -1513,7 +1513,7 @@
 	/*
 	 *  Check if there is still data segments in the transmit queue
 	 */
-	if (skb_queue_len(&self->tx_queue) > 0) {
+	if (!skb_queue_empty(&self->tx_queue)) {
 		if (priority == P_HIGH) {
 			/*
 			 *  No need to send the queued data, if we are
diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
index cd130c3..d5bdb53 100644
--- a/net/llc/llc_c_ev.c
+++ b/net/llc/llc_c_ev.c
@@ -84,7 +84,7 @@
 	if (llc->dev->flags & IFF_LOOPBACK)
 		goto out;
 	rc = 1;
-	if (!skb_queue_len(&llc->pdu_unack_q))
+	if (skb_queue_empty(&llc->pdu_unack_q))
 		goto out;
 	skb = skb_peek(&llc->pdu_unack_q);
 	pdu = llc_pdu_sn_hdr(skb);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index fc456a7..3405fdf 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -858,7 +858,7 @@
 {
 	struct netlink_sock *nlk = nlk_sk(sk);
 
-	if (!skb_queue_len(&sk->sk_receive_queue))
+	if (skb_queue_empty(&sk->sk_receive_queue))
 		clear_bit(0, &nlk->state);
 	if (!test_bit(0, &nlk->state))
 		wake_up_interruptible(&nlk->wait);
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 664d0e4..7845d04 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -385,7 +385,7 @@
 	memcpy(q->Stab, RTA_DATA(tb[TCA_RED_STAB-1]), 256);
 
 	q->qcount = -1;
-	if (skb_queue_len(&sch->q) == 0)
+	if (skb_queue_empty(&sch->q))
 		PSCHED_SET_PASTPERFECT(q->qidlestart);
 	sch_tree_unlock(sch);
 	return 0;
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 7ae6aa7..4b47dd6 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -203,7 +203,7 @@
 	 */
 	asoc->addip_serial = asoc->c.initial_tsn;
 
-	skb_queue_head_init(&asoc->addip_chunks);
+	INIT_LIST_HEAD(&asoc->addip_chunk_list);
 
 	/* Make an empty list of remote transport addresses.  */
 	INIT_LIST_HEAD(&asoc->peer.transport_addr_list);
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 339f7ac..5e085e0 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -115,6 +115,17 @@
 	atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc);
 }
 
+struct sctp_input_cb {
+	union {
+		struct inet_skb_parm	h4;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+		struct inet6_skb_parm	h6;
+#endif
+	} header;
+	struct sctp_chunk *chunk;
+};
+#define SCTP_INPUT_CB(__skb)	((struct sctp_input_cb *)&((__skb)->cb[0]))
+
 /*
  * This is the routine which IP calls when receiving an SCTP packet.
  */
@@ -243,6 +254,7 @@
 		ret = -ENOMEM;
 		goto discard_release;
 	}
+	SCTP_INPUT_CB(skb)->chunk = chunk;
 
 	sctp_rcv_set_owner_r(skb,sk);
 
@@ -265,9 +277,9 @@
 	sctp_bh_lock_sock(sk);
 
 	if (sock_owned_by_user(sk))
-		sk_add_backlog(sk, (struct sk_buff *) chunk);
+		sk_add_backlog(sk, skb);
 	else
-		sctp_backlog_rcv(sk, (struct sk_buff *) chunk);
+		sctp_backlog_rcv(sk, skb);
 
 	/* Release the sock and any reference counts we took in the
 	 * lookup calls.
@@ -302,14 +314,8 @@
  */
 int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
-	struct sctp_chunk *chunk;
-	struct sctp_inq *inqueue;
-
-	/* One day chunk will live inside the skb, but for
-	 * now this works.
-	 */
-	chunk = (struct sctp_chunk *) skb;
-	inqueue = &chunk->rcvr->inqueue;
+	struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
+	struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
 
 	sctp_inq_push(inqueue, chunk);
         return 0;
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index cedf435..2d33922 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -50,7 +50,7 @@
 /* Initialize an SCTP inqueue.  */
 void sctp_inq_init(struct sctp_inq *queue)
 {
-	skb_queue_head_init(&queue->in);
+	INIT_LIST_HEAD(&queue->in_chunk_list);
 	queue->in_progress = NULL;
 
 	/* Create a task for delivering data.  */
@@ -62,11 +62,13 @@
 /* Release the memory associated with an SCTP inqueue.  */
 void sctp_inq_free(struct sctp_inq *queue)
 {
-	struct sctp_chunk *chunk;
+	struct sctp_chunk *chunk, *tmp;
 
 	/* Empty the queue.  */
-	while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL)
+	list_for_each_entry_safe(chunk, tmp, &queue->in_chunk_list, list) {
+		list_del_init(&chunk->list);
 		sctp_chunk_free(chunk);
+	}
 
 	/* If there is a packet which is currently being worked on,
 	 * free it as well.
@@ -92,7 +94,7 @@
 	 * Eventually, we should clean up inqueue to not rely
 	 * on the BH related data structures.
 	 */
-	skb_queue_tail(&(q->in), (struct sk_buff *) packet);
+	list_add_tail(&packet->list, &q->in_chunk_list);
 	q->immediate.func(q->immediate.data);
 }
 
@@ -131,12 +133,16 @@
 
 	/* Do we need to take the next packet out of the queue to process? */
 	if (!chunk) {
+		struct list_head *entry;
+
 		/* Is the queue empty?  */
-        	if (skb_queue_empty(&queue->in))
+		if (list_empty(&queue->in_chunk_list))
 			return NULL;
 
+		entry = queue->in_chunk_list.next;
 		chunk = queue->in_progress =
-			(struct sctp_chunk *) skb_dequeue(&queue->in);
+			list_entry(entry, struct sctp_chunk, list);
+		list_del_init(entry);
 
 		/* This is the first chunk in the packet.  */
 		chunk->singleton = 1;
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 84b5b37..9313716 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -108,7 +108,7 @@
 	packet->transport = transport;
 	packet->source_port = sport;
 	packet->destination_port = dport;
-	skb_queue_head_init(&packet->chunks);
+	INIT_LIST_HEAD(&packet->chunk_list);
 	if (asoc) {
 		struct sctp_sock *sp = sctp_sk(asoc->base.sk);	
 		overhead = sp->pf->af->net_header_len; 
@@ -129,12 +129,14 @@
 /* Free a packet.  */
 void sctp_packet_free(struct sctp_packet *packet)
 {
-	struct sctp_chunk *chunk;
+	struct sctp_chunk *chunk, *tmp;
 
 	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
 
-        while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL)
+	list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
+		list_del_init(&chunk->list);
 		sctp_chunk_free(chunk);
+	}
 
 	if (packet->malloced)
 		kfree(packet);
@@ -276,7 +278,7 @@
 		packet->has_sack = 1;
 
 	/* It is OK to send this chunk.  */
-	__skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
+	list_add_tail(&chunk->list, &packet->chunk_list);
 	packet->size += chunk_len;
 	chunk->transport = packet->transport;
 finish:
@@ -295,7 +297,7 @@
 	struct sctphdr *sh;
 	__u32 crc32;
 	struct sk_buff *nskb;
-	struct sctp_chunk *chunk;
+	struct sctp_chunk *chunk, *tmp;
 	struct sock *sk;
 	int err = 0;
 	int padding;		/* How much padding do we need?  */
@@ -305,11 +307,11 @@
 	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
 
 	/* Do NOT generate a chunkless packet. */
-	chunk = (struct sctp_chunk *)skb_peek(&packet->chunks);
-	if (unlikely(!chunk))
+	if (list_empty(&packet->chunk_list))
 		return err;
 
 	/* Set up convenience variables... */
+	chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list);
 	sk = chunk->skb->sk;
 
 	/* Allocate the new skb.  */
@@ -370,7 +372,8 @@
 	 * [This whole comment explains WORD_ROUND() below.]
 	 */
 	SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
-	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {
+	list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
+		list_del_init(&chunk->list);
 		if (sctp_chunk_is_data(chunk)) {
 
 			if (!chunk->has_tsn) {
@@ -511,7 +514,8 @@
 	 * will get resent or dropped later.
 	 */
 
-	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {
+	list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
+		list_del_init(&chunk->list);
 		if (!sctp_chunk_is_data(chunk))
     			sctp_chunk_free(chunk);
 	}
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 4eb81a1..efb72fa 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -75,7 +75,7 @@
 static inline void sctp_outq_head_data(struct sctp_outq *q,
 					struct sctp_chunk *ch)
 {
-	__skb_queue_head(&q->out, (struct sk_buff *)ch);
+	list_add(&ch->list, &q->out_chunk_list);
 	q->out_qlen += ch->skb->len;
 	return;
 }
@@ -83,17 +83,22 @@
 /* Take data from the front of the queue. */
 static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q)
 {
-	struct sctp_chunk *ch;
-	ch = (struct sctp_chunk *)__skb_dequeue(&q->out);
-	if (ch)
+	struct sctp_chunk *ch = NULL;
+
+	if (!list_empty(&q->out_chunk_list)) {
+		struct list_head *entry = q->out_chunk_list.next;
+
+		ch = list_entry(entry, struct sctp_chunk, list);
+		list_del_init(entry);
 		q->out_qlen -= ch->skb->len;
+	}
 	return ch;
 }
 /* Add data chunk to the end of the queue. */
 static inline void sctp_outq_tail_data(struct sctp_outq *q,
 				       struct sctp_chunk *ch)
 {
-	__skb_queue_tail(&q->out, (struct sk_buff *)ch);
+	list_add_tail(&ch->list, &q->out_chunk_list);
 	q->out_qlen += ch->skb->len;
 	return;
 }
@@ -197,8 +202,8 @@
 void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
 {
 	q->asoc = asoc;
-	skb_queue_head_init(&q->out);
-	skb_queue_head_init(&q->control);
+	INIT_LIST_HEAD(&q->out_chunk_list);
+	INIT_LIST_HEAD(&q->control_chunk_list);
 	INIT_LIST_HEAD(&q->retransmit);
 	INIT_LIST_HEAD(&q->sacked);
 	INIT_LIST_HEAD(&q->abandoned);
@@ -217,7 +222,7 @@
 {
 	struct sctp_transport *transport;
 	struct list_head *lchunk, *pos, *temp;
-	struct sctp_chunk *chunk;
+	struct sctp_chunk *chunk, *tmp;
 
 	/* Throw away unacknowledged chunks. */
 	list_for_each(pos, &q->asoc->peer.transport_addr_list) {
@@ -269,8 +274,10 @@
 	q->error = 0;
 
 	/* Throw away any leftover control chunks. */
-	while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL)
+	list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+		list_del_init(&chunk->list);
 		sctp_chunk_free(chunk);
+	}
 }
 
 /* Free the outqueue structure and any related pending chunks.  */
@@ -333,7 +340,7 @@
 			break;
 		};
 	} else {
-		__skb_queue_tail(&q->control, (struct sk_buff *) chunk);
+		list_add_tail(&chunk->list, &q->control_chunk_list);
 		SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
 	}
 
@@ -650,10 +657,9 @@
 	__u16 sport = asoc->base.bind_addr.port;
 	__u16 dport = asoc->peer.port;
 	__u32 vtag = asoc->peer.i.init_tag;
-	struct sk_buff_head *queue;
 	struct sctp_transport *transport = NULL;
 	struct sctp_transport *new_transport;
-	struct sctp_chunk *chunk;
+	struct sctp_chunk *chunk, *tmp;
 	sctp_xmit_t status;
 	int error = 0;
 	int start_timer = 0;
@@ -675,8 +681,9 @@
 	 *   ...
 	 */
 
-	queue = &q->control;
-	while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) {
+	list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+		list_del_init(&chunk->list);
+
 		/* Pick the right transport to use. */
 		new_transport = chunk->transport;
 
@@ -814,8 +821,6 @@
 
 		/* Finally, transmit new packets.  */
 		start_timer = 0;
-		queue = &q->out;
-
 		while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
 			/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
 			 * stream identifier.
@@ -1149,8 +1154,9 @@
 	/* See if all chunks are acked.
 	 * Make sure the empty queue handler will get run later.
 	 */
-	q->empty = skb_queue_empty(&q->out) && skb_queue_empty(&q->control) &&
-			list_empty(&q->retransmit);
+	q->empty = (list_empty(&q->out_chunk_list) &&
+		    list_empty(&q->control_chunk_list) &&
+		    list_empty(&q->retransmit));
 	if (!q->empty)
 		goto finish;
 
@@ -1679,9 +1685,9 @@
 		if (TSN_lte(tsn, ctsn)) {
 			list_del_init(lchunk);
 			if (!chunk->tsn_gap_acked) {
-			chunk->transport->flight_size -=
-						 sctp_data_size(chunk);
-			q->outstanding_bytes -= sctp_data_size(chunk);
+				chunk->transport->flight_size -=
+					sctp_data_size(chunk);
+				q->outstanding_bytes -= sctp_data_size(chunk);
 			}
 			sctp_chunk_free(chunk);
 		} else {
@@ -1729,7 +1735,7 @@
 					      nskips, &ftsn_skip_arr[0]); 
 
 	if (ftsn_chunk) {
-		__skb_queue_tail(&q->control, (struct sk_buff *)ftsn_chunk);
+		list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);
 		SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
 	}
 }
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 5baed9b..773cd93 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1003,6 +1003,7 @@
 		SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);
 	}
 
+	INIT_LIST_HEAD(&retval->list);
 	retval->skb		= skb;
 	retval->asoc		= (struct sctp_association *)asoc;
 	retval->resent  	= 0;
@@ -1116,8 +1117,7 @@
 /* Possibly, free the chunk.  */
 void sctp_chunk_free(struct sctp_chunk *chunk)
 {
-	/* Make sure that we are not on any list.  */
-	skb_unlink((struct sk_buff *) chunk);
+	BUG_ON(!list_empty(&chunk->list));
 	list_del_init(&chunk->transmitted_list);
 
 	/* Release our reference on the message tracker. */
@@ -2739,8 +2739,12 @@
 	asoc->addip_last_asconf = NULL;
 
 	/* Send the next asconf chunk from the addip chunk queue. */
-	asconf = (struct sctp_chunk *)__skb_dequeue(&asoc->addip_chunks);
-	if (asconf) {
+	if (!list_empty(&asoc->addip_chunk_list)) {
+		struct list_head *entry = asoc->addip_chunk_list.next;
+		asconf = list_entry(entry, struct sctp_chunk, list);
+
+		list_del_init(entry);
+
 		/* Hold the chunk until an ASCONF_ACK is received. */
 		sctp_chunk_hold(asconf);
 		if (sctp_primitive_ASCONF(asoc, asconf))
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index aad55dc..091a66f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -406,7 +406,7 @@
 	 * transmission.
 	 */	
 	if (asoc->addip_last_asconf) {
-		__skb_queue_tail(&asoc->addip_chunks, (struct sk_buff *)chunk);
+		list_add_tail(&chunk->list, &asoc->addip_chunk_list);
 		goto out;	
 	}
 
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 269f217..3c654e0 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -145,8 +145,6 @@
 	if (test_and_set_bit(XPRT_LOCKED, &xprt->sockstate)) {
 		if (task == xprt->snd_task)
 			return 1;
-		if (task == NULL)
-			return 0;
 		goto out_sleep;
 	}
 	if (xprt->nocong || __xprt_get_cong(xprt, task)) {
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c420eba..d403e34 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -302,7 +302,7 @@
  * may receive messages only from that peer. */
 static void unix_dgram_disconnected(struct sock *sk, struct sock *other)
 {
-	if (skb_queue_len(&sk->sk_receive_queue)) {
+	if (!skb_queue_empty(&sk->sk_receive_queue)) {
 		skb_queue_purge(&sk->sk_receive_queue);
 		wake_up_interruptible_all(&unix_sk(sk)->peer_wait);
 
@@ -1619,7 +1619,7 @@
 	for (;;) {
 		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 
-		if (skb_queue_len(&sk->sk_receive_queue) ||
+		if (!skb_queue_empty(&sk->sk_receive_queue) ||
 		    sk->sk_err ||
 		    (sk->sk_shutdown & RCV_SHUTDOWN) ||
 		    signal_pending(current) ||
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 908bff6..5180405 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -25,6 +25,8 @@
 #include <stdint.h>
 #endif
 
+#include <ctype.h>
+
 typedef uint32_t	__u32;
 typedef uint16_t	__u16;
 typedef unsigned char	__u8;
@@ -323,6 +325,22 @@
 
 
 
+static int do_of_entry (const char *filename, struct of_device_id *of, char *alias)
+{
+    char *tmp;
+    sprintf (alias, "of:N%sT%sC%s",
+                    of->name[0] ? of->name : "*",
+                    of->type[0] ? of->type : "*",
+                    of->compatible[0] ? of->compatible : "*");
+
+    /* Replace all whitespace with underscores */
+    for (tmp = alias; tmp && *tmp; tmp++)
+        if (isspace (*tmp))
+            *tmp = '_';
+
+    return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -401,6 +419,10 @@
 	else if (sym_is(symname, "__mod_pcmcia_device_table"))
 		do_table(symval, sym->st_size, sizeof(struct pcmcia_device_id),
 			 do_pcmcia_entry, mod);
+        else if (sym_is(symname, "__mod_of_device_table"))
+		do_table(symval, sym->st_size, sizeof(struct of_device_id),
+			 do_of_entry, mod);
+
 }
 
 /* Now add out buffered information to the generated C source */
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 90a551e..a1f6bac 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -129,7 +129,7 @@
 	int loop, ret;
 
 	const unsigned limit =
-		(PAGE_SIZE - sizeof(*klist)) / sizeof(struct key);
+		(PAGE_SIZE - sizeof(*klist)) / sizeof(struct key *);
 
 	ret = 0;
 
@@ -150,7 +150,7 @@
 			max = limit;
 
 		ret = -ENOMEM;
-		size = sizeof(*klist) + sizeof(struct key) * max;
+		size = sizeof(*klist) + sizeof(struct key *) * max;
 		klist = kmalloc(size, GFP_KERNEL);
 		if (!klist)
 			goto error;
@@ -163,7 +163,7 @@
 		klist->nkeys = sklist->nkeys;
 		memcpy(klist->keys,
 		       sklist->keys,
-		       sklist->nkeys * sizeof(struct key));
+		       sklist->nkeys * sizeof(struct key *));
 
 		for (loop = klist->nkeys - 1; loop >= 0; loop--)
 			atomic_inc(&klist->keys[loop]->usage);
@@ -783,7 +783,7 @@
 		ret = -ENFILE;
 		if (max > 65535)
 			goto error3;
-		size = sizeof(*klist) + sizeof(*key) * max;
+		size = sizeof(*klist) + sizeof(struct key *) * max;
 		if (size > PAGE_SIZE)
 			goto error3;
 
@@ -895,7 +895,8 @@
 
 key_is_present:
 	/* we need to copy the key list for RCU purposes */
-	nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys,
+	nklist = kmalloc(sizeof(*klist) +
+			 sizeof(struct key *) * klist->maxkeys,
 			 GFP_KERNEL);
 	if (!nklist)
 		goto nomem;
@@ -905,12 +906,12 @@
 	if (loop > 0)
 		memcpy(&nklist->keys[0],
 		       &klist->keys[0],
-		       loop * sizeof(klist->keys[0]));
+		       loop * sizeof(struct key *));
 
 	if (loop < nklist->nkeys)
 		memcpy(&nklist->keys[loop],
 		       &klist->keys[loop + 1],
-		       (nklist->nkeys - loop) * sizeof(klist->keys[0]));
+		       (nklist->nkeys - loop) * sizeof(struct key *));
 
 	/* adjust the user's quota */
 	key_payload_reserve(keyring,
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
index 9e42a1a..cb998e8 100644
--- a/sound/oss/cs46xx.c
+++ b/sound/oss/cs46xx.c
@@ -4174,7 +4174,7 @@
 				list_for_each(entry, &cs46xx_devs)
 				{
 					card = list_entry(entry, struct cs_card, list);
-					cs46xx_suspend(card, 0);
+					cs46xx_suspend(card, PMSG_ON);
 				}
 
 			}
@@ -5749,7 +5749,7 @@
 			case PM_SUSPEND:
 				CS_DBGOUT(CS_PM, 2, printk(KERN_INFO
 					"cs46xx: PM suspend request\n"));
-				if(cs46xx_suspend(card, 0))
+				if(cs46xx_suspend(card, PMSG_SUSPEND))
 				{
 				    CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
 					"cs46xx: PM suspend request refused\n"));
@@ -5779,7 +5779,7 @@
 	struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
 		printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
-	cs46xx_suspend(s, 0);
+	cs46xx_suspend(s, state);
 	return 0;
 }
 
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 909fef8..c5557ea 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -798,13 +798,15 @@
 	{0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */
 };
 
+static struct pci_driver driver;
+
 /* return the rate of the card, or a negative value if it's blacklisted */
 static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
 {
 	int i;
 	const struct pci_device_id *supported;
 
-	supported = pci_match_device(driver, pci);
+	supported = pci_match_device(&driver, pci);
 	if (supported)
 		return supported->driver_data;
 
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 2d4f8e2..d6918b4 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -22,7 +22,6 @@
 #include <sound/core.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
-#include <pcmcia/version.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/cisreg.h>
 #include "pdaudiocf.h"
@@ -171,14 +170,6 @@
 
 	/* Register with Card Services */
 	client_reg.dev_info = &dev_info;
-	client_reg.EventMask = 
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
-#ifdef CONFIG_PM
-		| CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
-		| CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
-#endif
-		;
-	client_reg.event_handler = &pdacf_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 
@@ -387,12 +378,13 @@
 MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
 
 static struct pcmcia_driver pdacf_cs_driver = {
-	.owner          = THIS_MODULE,
-	.drv            = {
-		.name   = "snd-pdaudiocf",
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "snd-pdaudiocf",
 	},
-	.attach         = snd_pdacf_attach,
-	.detach         = snd_pdacf_detach,
+	.attach		= snd_pdacf_attach,
+	.event		= pdacf_event,
+	.detach		= snd_pdacf_detach,
 	.id_table	= snd_pdacf_ids,
 };
 
diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c
index 332bbca..df7a39b 100644
--- a/sound/pcmcia/vx/vx_entry.c
+++ b/sound/pcmcia/vx/vx_entry.c
@@ -35,7 +35,6 @@
  * prototypes
  */
 static void vxpocket_config(dev_link_t *link);
-static int vxpocket_event(event_t event, int priority, event_callback_args_t *args);
 
 
 static void vxpocket_release(dev_link_t *link)
@@ -169,14 +168,6 @@
 	/* Register with Card Services */
 	memset(&client_reg, 0, sizeof(client_reg));
 	client_reg.dev_info = hw->dev_info;
-	client_reg.EventMask = 
-		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
-#ifdef CONFIG_PM
-		| CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
-		| CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
-#endif
-		;
-	client_reg.event_handler = &vxpocket_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 
@@ -321,7 +312,7 @@
 /*
  * event callback
  */
-static int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
+int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
 {
 	dev_link_t *link = args->client_data;
 	vx_core_t *chip = link->priv;
@@ -380,4 +371,5 @@
  */
 EXPORT_SYMBOL(snd_vxpocket_ops);
 EXPORT_SYMBOL(snd_vxpocket_attach);
+EXPORT_SYMBOL(vxpocket_event);
 EXPORT_SYMBOL(snd_vxpocket_detach);
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 5f4c132..62d6fa1 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
-#include <pcmcia/version.h>
 #include "vxpocket.h"
 #include <sound/initval.h>