Auto merge with /home/aegl/GIT/linus
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 302b319..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
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/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/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/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/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/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/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..3540d8b 100644
--- a/arch/xtensa/kernel/syscalls.c
+++ b/arch/xtensa/kernel/syscalls.c
@@ -46,8 +46,6 @@
 
 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 +70,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 +93,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 +135,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 +268,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/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/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/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/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/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/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/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/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/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/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/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_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/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/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/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/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/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/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/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 0621779..aae0686 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"
 
@@ -1438,6 +1441,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-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-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/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-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/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/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..2b66a36 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -13,6 +13,12 @@
 #define SMP_CACHE_BYTES L1_CACHE_BYTES
 #endif
 
+#ifdef CONFIG_X86
+#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/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/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/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/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/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/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 e57abd4..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;
@@ -2442,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;
 
@@ -3094,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/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/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/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>