Switch to kernel 3.3.8(solo2)
authorkos <kos@dev3>
Wed, 8 May 2013 02:26:12 +0000 (11:26 +0900)
committerkos <kos@dev3>
Wed, 8 May 2013 02:28:03 +0000 (11:28 +0900)
Increase PR of some pkgs to rebuild kernel modules
Update driver
20130506
 - Support dual tuner blindscan(duo2, uno, ultimo)
 - Switching to kernel 3.3.8(solo2, Needs a kernel update)
 - Fix SD video output problem when transcoding enabled(solo2)
 - Enhance demux filtering(solo2)
 - Official duo2 driver release
 - Support DTS-HD
 - Add redundant interface to zapping mode

18 files changed:
meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/bmips-no-array-bounds.patch [new file with mode: 0644]
meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/brcm_3.3.patch [new file with mode: 0644]
meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/brcm_mtd_mac.patch [new file with mode: 0644]
meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/dvb_backport.patch [new file with mode: 0644]
meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/dvb_core_5.5.patch [new file with mode: 0644]
meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/fix_cpu_proc.patch [new file with mode: 0644]
meta-bsp/common/recipes/linux/linux-vuplus_3.3.8.bb [new file with mode: 0644]
meta-bsp/common/recipes/vuplus/vuplus-dvb-modules.bb
meta-bsp/vusolo2/conf/machine/vusolo2.conf
meta-bsp/vusolo2/recipes/linux/linux-vuplus-3.3.8/vusolo2_defconfig [new file with mode: 0644]
meta-bsp/vusolo2/recipes/linux/linux-vuplus_3.3.8.bbappend [new file with mode: 0644]
meta-bsp/vusolo2/recipes/vuplus/vuplus-dvb-modules.bbappend
meta-openvuplus/recipes-connectivity/ralink/rt3070_2.5.0.3.bb
meta-openvuplus/recipes-connectivity/realtek/r8192cu_3.4.4.4749.20121105.bb
meta-openvuplus/recipes-connectivity/tasks/task-vuplus-wlan.bb
meta-openvuplus/recipes-core/tasks/task-core-boot.inc
meta-openvuplus/recipes-vuplus/tasks/task-vuplus-enigma2.inc
meta-openvuplus/recipes-vuplus/tasks/task-vuplus-essential.bb

diff --git a/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/bmips-no-array-bounds.patch b/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/bmips-no-array-bounds.patch
new file mode 100644 (file)
index 0000000..c372fd3
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/arch/mips/Makefile b/arch/mips/Makefile
+index 4fedf5a..e7f3f34 100644
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -157,7 +157,7 @@ ifeq (,$(findstring march=octeon, $(cflags-$(CONFIG_CPU_CAVIUM_OCTEON))))
+ cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon
+ endif
+ cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1
+-cflags-$(CONFIG_CPU_BMIPS)    += -march=mips32 -Wa,-mips32 -Wa,--trap
++cflags-$(CONFIG_CPU_BMIPS)    += -march=mips32 -Wa,-mips32 -Wa,--trap -Wno-array-bounds
+ cflags-$(CONFIG_CPU_R4000_WORKAROUNDS)        += $(call cc-option,-mfix-r4000,)
+ cflags-$(CONFIG_CPU_R4400_WORKAROUNDS)        += $(call cc-option,-mfix-r4400,)
diff --git a/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/brcm_3.3.patch b/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/brcm_3.3.patch
new file mode 100644 (file)
index 0000000..f8a2371
--- /dev/null
@@ -0,0 +1,64 @@
+diff --git a/Makefile b/Makefile
+index 002da9a..03831b6 100644
+--- a/Makefile
++++ b/Makefile
+@@ -193,7 +193,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ # Default value for CROSS_COMPILE is not to prefix executables
+ # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+ export KBUILD_BUILDHOST := $(SUBARCH)
+-ARCH          ?= $(SUBARCH)
++ARCH          ?= mips
+ CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
+ # Architecture as present in compile.h
+diff --git a/drivers/brcmstb/bchip.c b/drivers/brcmstb/bchip.c
+index b4c5b0b..4f871cd 100644
+--- a/drivers/brcmstb/bchip.c
++++ b/drivers/brcmstb/bchip.c
+@@ -450,9 +450,14 @@ void __init bchip_early_setup(void)
+               genet_pdata[0].phy_id = BRCM_PHY_ID_AUTO;
+       }
+ #else
++#if defined(CONFIG_BCMGENET_0_GPHY)
++        genet_pdata[0].phy_type = BRCM_PHY_TYPE_EXT_RGMII;
++        genet_pdata[0].phy_id = BRCM_PHY_ID_AUTO;
++#else
+       genet_pdata[0].phy_type = BRCM_PHY_TYPE_INT;
+       genet_pdata[0].phy_id = 1;
+ #endif
++#endif
+ #endif
+diff --git a/drivers/net/ethernet/broadcom/genet/Kconfig b/drivers/net/ethernet/broadcom/genet/Kconfig
+index c1ed960..8e87443 100644
+--- a/drivers/net/ethernet/broadcom/genet/Kconfig
++++ b/drivers/net/ethernet/broadcom/genet/Kconfig
+@@ -1,5 +1,27 @@
+ menu "BCMGENET options"
++config BCMGENET_0_GPHY
++        bool "GENET0 is connected to GPHY via RGMII"
++        depends on BCMGENET && BRCM_HAS_GENET_0
++        default n
++        help
++          Say Y to use an external GPHY for GENET_0.  By default this will
++          use RGMII mode and disable the internal 10/100 PHY (if present);
++          the pinmux must be set up properly in arch/mips/brcmstb/board.c .
++
++          If unsure, say N.
++
++config BCMGENET_1_GPHY
++        bool "GENET1 is connected to GPHY via RGMII"
++        depends on BCMGENET && BRCM_HAS_GENET_1
++        default n
++        help
++          Say Y to use an external GPHY for GENET_1.  By default this will
++          use RGMII mode and disable the internal 10/100 PHY (if present);
++          the pinmux must be set up properly in arch/mips/brcmstb/board.c .
++
++          If unsure, say N.
++
+ config BCMGENET_RX_DESC_THROTTLE 
+       bool "use hardware rx descriptor throttling"
+       depends on BCMGENET
diff --git a/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/brcm_mtd_mac.patch b/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/brcm_mtd_mac.patch
new file mode 100644 (file)
index 0000000..a175212
--- /dev/null
@@ -0,0 +1,74 @@
+diff --git a/arch/mips/brcmstb/prom.c b/arch/mips/brcmstb/prom.c
+index c575425..b9dfff2 100644
+--- a/arch/mips/brcmstb/prom.c
++++ b/arch/mips/brcmstb/prom.c
+@@ -224,6 +224,8 @@ static void __init __maybe_unused cfe_read_configuration(void)
+       FETCH("LINUX_FFS_SIZE", parse_hex, &brcm_mtd_rootfs_len);
+       FETCH("LINUX_PART_STARTAD", parse_hex, &brcm_mtd_kernel_start);
+       FETCH("LINUX_PART_SIZE", parse_hex, &brcm_mtd_kernel_len);
++      FETCH("LINUX_MACADDR_STARTAD", parse_hex, &brcm_mtd_macaddr_start);
++      FETCH("LINUX_MACADDR_SIZE", parse_hex, &brcm_mtd_macaddr_len);
+       FETCH("OCAP_PART_STARTAD", parse_hex, &brcm_mtd_ocap_start);
+       FETCH("OCAP_PART_SIZE", parse_hex, &brcm_mtd_ocap_len);
+       FETCH("FLASH_SIZE", parse_ulong, &brcm_mtd_flash_size_mb);
+diff --git a/drivers/brcmstb/board.c b/drivers/brcmstb/board.c
+index 4a823ef..7ae6cd2 100644
+--- a/drivers/brcmstb/board.c
++++ b/drivers/brcmstb/board.c
+@@ -34,6 +34,8 @@ unsigned long brcm_mtd_rootfs_start;
+ unsigned long brcm_mtd_rootfs_len;
+ unsigned long brcm_mtd_kernel_start;
+ unsigned long brcm_mtd_kernel_len;
++unsigned long brcm_mtd_macaddr_start;
++unsigned long brcm_mtd_macaddr_len;
+ unsigned long brcm_mtd_ocap_start;
+ unsigned long brcm_mtd_ocap_len;
+ unsigned long brcm_mtd_flash_size_mb;
+@@ -535,6 +537,9 @@ int __init board_get_partition_map(struct mtd_partition **p)
+       nr_parts = 2;
+       if (brcm_mtd_kernel_len != 0)
+               nr_parts++;
++      if (brcm_mtd_macaddr_len != 0)
++              nr_parts++;
++
+       ret = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL);
+       if (!ret)
+@@ -544,15 +549,21 @@ int __init board_get_partition_map(struct mtd_partition **p)
+       ret[0].size = brcm_mtd_rootfs_len;
+       ret[0].name = "rootfs";
+-      ret[1].offset = 0;
+-      ret[1].size = MTDPART_SIZ_FULL;
+-      ret[1].name = "entire_device";
++        ret[1].offset = brcm_mtd_rootfs_start;
++        ret[1].size = brcm_mtd_rootfs_len;
++        ret[1].name = "rootfs(redundant)";
+       if (brcm_mtd_kernel_len != 0) {
+               ret[2].offset = brcm_mtd_kernel_start;
+               ret[2].size = brcm_mtd_kernel_len;
+               ret[2].name = "kernel";
+       }
++        if (brcm_mtd_macaddr_len != 0) {
++                ret[3].offset = brcm_mtd_macaddr_start;
++                ret[3].size = brcm_mtd_macaddr_len;
++                ret[3].name = "mac";
++        }
++
+       *p = ret;
+       return nr_parts;
+diff --git a/include/linux/brcmstb/brcmstb.h b/include/linux/brcmstb/brcmstb.h
+index 9885e59..62b5515 100644
+--- a/include/linux/brcmstb/brcmstb.h
++++ b/include/linux/brcmstb/brcmstb.h
+@@ -733,6 +733,8 @@ extern unsigned long brcm_mtd_rootfs_start;
+ extern unsigned long brcm_mtd_rootfs_len;
+ extern unsigned long brcm_mtd_kernel_start;
+ extern unsigned long brcm_mtd_kernel_len;
++extern unsigned long brcm_mtd_macaddr_start;
++extern unsigned long brcm_mtd_macaddr_len;
+ extern unsigned long brcm_mtd_ocap_start;
+ extern unsigned long brcm_mtd_ocap_len;
+ extern unsigned long brcm_mtd_flash_size_mb;
diff --git a/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/dvb_backport.patch b/meta-bsp/common/recipes/linux/linux-vuplus-3.3.8/dvb_backport.patch
new file mode 100644 (file)
index 0000000..9082392
--- /dev/null
@@ -0,0 +1,1120888 @@
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index e9c1893..2477aba 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -1292,6 +1292,37 @@ module_exit(i2c_exit);
+  * the functional interface to the i2c busses.
+  * ----------------------------------------------------
+  */
++/**
++ * __i2c_transfer - unlocked flavor of i2c_transfer
++ * @adap: Handle to I2C bus
++ * @msgs: One or more messages to execute before STOP is issued to
++ *      terminate the operation; each message begins with a START.
++ * @num: Number of messages to be executed.
++ *
++ * Returns negative errno, else the number of messages executed.
++ *
++ * Adapter lock must be held when calling this function. No debug logging
++ * takes place. adap->algo->master_xfer existence isn't checked.
++ */
++int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
++{
++        unsigned long orig_jiffies;
++        int ret, try;
++
++        /* Retry automatically on arbitration loss */
++        orig_jiffies = jiffies;
++        for (ret = 0, try = 0; try <= adap->retries; try++) {
++                ret = adap->algo->master_xfer(adap, msgs, num);
++                if (ret != -EAGAIN)
++                        break;
++                if (time_after(jiffies, orig_jiffies + adap->timeout))
++                        break;
++        }
++
++        return ret;
++}
++EXPORT_SYMBOL(__i2c_transfer);
++
+ /**
+  * i2c_transfer - execute a single or combined I2C message
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index 9575db4..84d85b9 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -6,20 +6,82 @@ menuconfig MEDIA_SUPPORT
+       tristate "Multimedia support"
+       depends on HAS_IOMEM
+       help
+-        If you want to use Video for Linux, DVB for Linux, or DAB adapters,
++        If you want to use Webcams, Video grabber devices and/or TV devices
+         enable this option and other options below.
++        Additional info and docs are available on the web at
++        <http://linuxtv.org>
+ if MEDIA_SUPPORT
+ comment "Multimedia core support"
+ #
++# Multimedia support - automatically enable V4L2 and DVB core
++#
++config MEDIA_CAMERA_SUPPORT
++      bool "Cameras/video grabbers support"
++      ---help---
++        Enable support for webcams and video grabbers.
++
++        Say Y when you have a webcam or a video capture grabber board.
++
++config MEDIA_ANALOG_TV_SUPPORT
++      bool "Analog TV support"
++      ---help---
++        Enable analog TV support.
++
++        Say Y when you have a TV board with analog support or with a
++        hybrid analog/digital TV chipset.
++
++        Note: There are several DVB cards that are based on chips that
++              support both analog and digital TV. Disabling this option
++              will disable support for them.
++
++config MEDIA_DIGITAL_TV_SUPPORT
++      bool "Digital TV support"
++      ---help---
++        Enable digital TV support.
++
++        Say Y when you have a board with digital support or a board with
++        hybrid digital TV and analog TV.
++
++config MEDIA_RADIO_SUPPORT
++      bool "AM/FM radio receivers/transmitters support"
++      ---help---
++        Enable AM/FM radio support.
++
++        Additional info and docs are available on the web at
++        <http://linuxtv.org>
++
++        Say Y when you have a board with radio support.
++
++        Note: There are several TV cards that are based on chips that
++              support radio reception. Disabling this option will
++              disable support for them.
++
++config MEDIA_RC_SUPPORT
++      bool "Remote Controller support"
++      depends on INPUT
++      ---help---
++        Enable support for Remote Controllers on Linux. This is
++        needed in order to support several video capture adapters,
++        standalone IR receivers/transmitters, and RF receivers.
++
++        Enable this option if you have a video capture board even
++        if you don't need IR, as otherwise, you may not be able to
++        compile the driver for your adapter.
++
++        Say Y when you have a TV or an IR device.
++
++#
+ # Media controller
++#     Selectable only for webcam/grabbers, as other drivers don't use it
+ #
+ config MEDIA_CONTROLLER
+       bool "Media Controller API (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
++      depends on MEDIA_CAMERA_SUPPORT
+       ---help---
+         Enable the media controller API used to query media devices internal
+         topology and configure it dynamically.
+@@ -27,31 +89,15 @@ config MEDIA_CONTROLLER
+         This API is mostly used by camera interfaces in embedded platforms.
+ #
+-# V4L core and enabled API's
++# Video4Linux support
++#     Only enables if one of the V4L2 types (ATV, webcam, radio) is selected
+ #
+ config VIDEO_DEV
+-      tristate "Video For Linux"
+-      ---help---
+-        V4L core support for video capture and overlay devices, webcams and
+-        AM/FM radio cards.
+-
+-        This kernel includes support for the new Video for Linux Two API,
+-        (V4L2).
+-
+-        Additional info and docs are available on the web at
+-        <http://linuxtv.org>
+-
+-        Documentation for V4L2 is also available on the web at
+-        <http://bytesex.org/v4l/>.
+-
+-        To compile this driver as a module, choose M here: the
+-        module will be called videodev.
+-
+-config VIDEO_V4L2_COMMON
+       tristate
+-      depends on (I2C || I2C=n) && VIDEO_DEV
+-      default (I2C || I2C=n) && VIDEO_DEV
++      depends on MEDIA_SUPPORT
++      depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT
++      default y
+ config VIDEO_V4L2_SUBDEV_API
+       bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
+@@ -62,27 +108,19 @@ config VIDEO_V4L2_SUBDEV_API
+         This API is mostly used by camera interfaces in embedded platforms.
++source "drivers/media/v4l2-core/Kconfig"
++
+ #
+ # DVB Core
++#     Only enables if one of DTV is selected
+ #
+ config DVB_CORE
+-      tristate "DVB for Linux"
++      tristate
++      depends on MEDIA_SUPPORT
++      depends on MEDIA_DIGITAL_TV_SUPPORT
++      default y
+       select CRC32
+-      help
+-        DVB core utility functions for device handling, software fallbacks etc.
+-
+-        Enable this if you own a DVB/ATSC adapter and want to use it or if
+-        you compile Linux for a digital SetTopBox.
+-
+-        Say Y when you have a DVB or an ATSC card and want to use it.
+-
+-        API specs and user tools are available from <http://www.linuxtv.org/>.
+-
+-        Please report problems regarding this support to the LinuxDVB
+-        mailing list.
+-
+-        If unsure say N.
+ config DVB_NET
+       bool "DVB Network Support"
+@@ -97,33 +135,63 @@ config DVB_NET
+         You may want to disable the network support on embedded devices. If
+         unsure say Y.
+-config VIDEO_MEDIA
+-      tristate
+-      default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV)
++# This Kconfig option is used by both PCI and USB drivers
++config TTPCI_EEPROM
++        tristate
++        depends on I2C
++        default n
+-comment "Multimedia drivers"
++source "drivers/media/dvb-core/Kconfig"
+-source "drivers/media/common/Kconfig"
++comment "Media drivers"
+ source "drivers/media/rc/Kconfig"
+ #
+-# Tuner drivers for DVB and V4L
++# V4L platform/mem2mem drivers
+ #
+-source "drivers/media/common/tuners/Kconfig"
++source "drivers/media/usb/Kconfig"
++source "drivers/media/pci/Kconfig"
++source "drivers/media/platform/Kconfig"
++source "drivers/media/mmc/Kconfig"
++source "drivers/media/parport/Kconfig"
++source "drivers/media/radio/Kconfig"
+-#
+-# Video/Radio/Hybrid adapters
+-#
++comment "Supported FireWire (IEEE 1394) Adapters"
++      depends on DVB_CORE && FIREWIRE
++source "drivers/media/firewire/Kconfig"
+-source "drivers/media/video/Kconfig"
++# Common driver options
++source "drivers/media/common/Kconfig"
+-source "drivers/media/radio/Kconfig"
++comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
+ #
+-# DVB adapters
++# Ancillary drivers (tuners, i2c, frontends)
+ #
+-source "drivers/media/dvb/Kconfig"
++config MEDIA_SUBDRV_AUTOSELECT
++      bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)"
++      depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT
++      default y
++      help
++        By default, a media driver auto-selects all possible ancillary
++        devices such as tuners, sensors, video encoders/decoders and
++        frontends, that are used by any of the supported devices.
++
++        This is generally the right thing to do, except when there
++        are strict constraints with regards to the kernel size,
++        like on embedded systems.
++
++        Use this option with care, as deselecting ancillary drivers which
++        are, in fact, necessary will result in the lack of the needed
++        functionality for your device (it may not tune or may not have
++        the needed demodulators).
++
++        If unsure say Y.
++
++source "drivers/media/i2c/Kconfig"
++source "drivers/media/tuners/Kconfig"
++source "drivers/media/dvb-frontends/Kconfig"
+ endif # MEDIA_SUPPORT
+diff --git a/drivers/media/Makefile b/drivers/media/Makefile
+index 64755c9..620f275 100644
+--- a/drivers/media/Makefile
++++ b/drivers/media/Makefile
+@@ -4,11 +4,30 @@
+ media-objs    := media-device.o media-devnode.o media-entity.o
++#
++# I2C drivers should come before other drivers, otherwise they'll fail
++# when compiled as builtin drivers
++#
++obj-y += i2c/ tuners/
++obj-$(CONFIG_DVB_CORE)  += dvb-frontends/
++
++#
++# Now, let's link-in the media core
++#
+ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+   obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+ endif
+-obj-y += common/ rc/ video/
++obj-$(CONFIG_VIDEO_DEV) += v4l2-core/
++obj-$(CONFIG_DVB_CORE)  += dvb-core/
++# There are both core and drivers at RC subtree - merge before drivers
++obj-y += rc/
++
++#
++# Finally, merge the drivers that require the core
++#
++
++obj-y += common/ platform/ pci/ usb/ mmc/ firewire/ parport/
+ obj-$(CONFIG_VIDEO_DEV) += radio/
+-obj-$(CONFIG_DVB_CORE)  += dvb/
++
+diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
+index 769c6f8..d2a436c 100644
+--- a/drivers/media/common/Kconfig
++++ b/drivers/media/common/Kconfig
+@@ -1,9 +1,10 @@
+-config VIDEO_SAA7146
+-      tristate
+-      depends on I2C && PCI
++# Used by common drivers, when they need to ask questions
++config MEDIA_COMMON_OPTIONS
++      bool
+-config VIDEO_SAA7146_VV
+-      tristate
+-      depends on VIDEO_V4L2
+-      select VIDEOBUF_DMA_SG
+-      select VIDEO_SAA7146
++comment "common driver options"
++      depends on MEDIA_COMMON_OPTIONS
++
++source "drivers/media/common/b2c2/Kconfig"
++source "drivers/media/common/saa7146/Kconfig"
++source "drivers/media/common/siano/Kconfig"
+diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
+index e3ec963..b8e2e3a 100644
+--- a/drivers/media/common/Makefile
++++ b/drivers/media/common/Makefile
+@@ -1,6 +1 @@
+-saa7146-objs    := saa7146_i2c.o saa7146_core.o
+-saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+-
+-obj-y += tuners/
+-obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
+-obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
++obj-y += b2c2/ saa7146/ siano/
+diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig
+new file mode 100644
+index 0000000..a8c6cdf
+--- /dev/null
++++ b/drivers/media/common/b2c2/Kconfig
+@@ -0,0 +1,23 @@
++config DVB_B2C2_FLEXCOP
++      tristate
++      depends on DVB_CORE && I2C
++      depends on DVB_B2C2_FLEXCOP_PCI || DVB_B2C2_FLEXCOP_USB
++      default y
++      select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_BCM3510 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_TUNER_ITD1000 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT
++      select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT
++
++# Selected via the PCI or USB flexcop drivers
++config DVB_B2C2_FLEXCOP_DEBUG
++      bool
+diff --git a/drivers/media/common/b2c2/Makefile b/drivers/media/common/b2c2/Makefile
+new file mode 100644
+index 0000000..24993a5
+--- /dev/null
++++ b/drivers/media/common/b2c2/Makefile
+@@ -0,0 +1,8 @@
++b2c2-flexcop-objs += flexcop.o flexcop-fe-tuner.o flexcop-i2c.o
++b2c2-flexcop-objs += flexcop-sram.o flexcop-eeprom.o flexcop-misc.o
++b2c2-flexcop-objs += flexcop-hw-filter.o
++obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
++
++ccflags-y += -Idrivers/media/dvb-core/
++ccflags-y += -Idrivers/media/dvb-frontends/
++ccflags-y += -Idrivers/media/tuners/
+diff --git a/drivers/media/common/b2c2/flexcop-common.h b/drivers/media/common/b2c2/flexcop-common.h
+new file mode 100644
+index 0000000..437912e
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-common.h
+@@ -0,0 +1,185 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-common.h - common header file for device-specific source files
++ * see flexcop.c for copyright information
++ */
++#ifndef __FLEXCOP_COMMON_H__
++#define __FLEXCOP_COMMON_H__
++
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/mutex.h>
++
++#include "flexcop-reg.h"
++
++#include "dmxdev.h"
++#include "dvb_demux.h"
++#include "dvb_filter.h"
++#include "dvb_net.h"
++#include "dvb_frontend.h"
++
++#define FC_MAX_FEED 256
++
++#ifndef FC_LOG_PREFIX
++#warning please define a log prefix for your file, using a default one
++#define FC_LOG_PREFIX "b2c2-undef"
++#endif
++
++/* Steal from usb.h */
++#undef err
++#define err(format, arg...) \
++      printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
++#undef info
++#define info(format, arg...) \
++      printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
++#undef warn
++#define warn(format, arg...) \
++      printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
++
++struct flexcop_dma {
++      struct pci_dev *pdev;
++
++      u8 *cpu_addr0;
++      dma_addr_t dma_addr0;
++      u8 *cpu_addr1;
++      dma_addr_t dma_addr1;
++      u32 size; /* size of each address in bytes */
++};
++
++struct flexcop_i2c_adapter {
++      struct flexcop_device *fc;
++      struct i2c_adapter i2c_adap;
++
++      u8 no_base_addr;
++      flexcop_i2c_port_t port;
++};
++
++/* Control structure for data definitions that are common to
++ * the B2C2-based PCI and USB devices.
++ */
++struct flexcop_device {
++      /* general */
++      struct device *dev; /* for firmware_class */
++
++#define FC_STATE_DVB_INIT 0x01
++#define FC_STATE_I2C_INIT 0x02
++#define FC_STATE_FE_INIT  0x04
++      int init_state;
++
++      /* device information */
++      int has_32_hw_pid_filter;
++      flexcop_revision_t rev;
++      flexcop_device_type_t dev_type;
++      flexcop_bus_t bus_type;
++
++      /* dvb stuff */
++      struct dvb_adapter dvb_adapter;
++      struct dvb_frontend *fe;
++      struct dvb_net dvbnet;
++      struct dvb_demux demux;
++      struct dmxdev dmxdev;
++      struct dmx_frontend hw_frontend;
++      struct dmx_frontend mem_frontend;
++      int (*fe_sleep) (struct dvb_frontend *);
++
++      struct flexcop_i2c_adapter fc_i2c_adap[3];
++      struct mutex i2c_mutex;
++      struct module *owner;
++
++      /* options and status */
++      int extra_feedcount;
++      int feedcount;
++      int pid_filtering;
++      int fullts_streaming_state;
++
++      /* bus specific callbacks */
++      flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
++                      flexcop_ibi_register);
++      int (*write_ibi_reg) (struct flexcop_device *,
++                      flexcop_ibi_register, flexcop_ibi_value);
++      int (*i2c_request) (struct flexcop_i2c_adapter *,
++              flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
++      int (*stream_control) (struct flexcop_device *, int);
++      int (*get_mac_addr) (struct flexcop_device *fc, int extended);
++      void *bus_specific;
++};
++
++/* exported prototypes */
++
++/* from flexcop.c */
++void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
++void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
++
++struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
++void flexcop_device_kfree(struct flexcop_device *);
++
++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);
++
++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_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);
++
++/* from flexcop-eeprom.c */
++/* the PCI part uses this call to get the MAC address, the USB part has its own */
++int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
++
++/* from flexcop-i2c.c */
++/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
++ * one. We have it in flexcop-i2c.c, because it is going via the actual
++ * I2C-channel of the flexcop.
++ */
++int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
++      u8 chipaddr, u8 addr, u8 *buf, u16 len);
++
++/* from flexcop-sram.c */
++int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
++      flexcop_sram_dest_target_t target);
++void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
++void flexcop_sram_ctrl(struct flexcop_device *fc,
++              int usb_wan, int sramdma, int maximumfill);
++
++/* global prototypes for the flexcop-chip */
++/* from flexcop-fe-tuner.c */
++int flexcop_frontend_init(struct flexcop_device *fc);
++void flexcop_frontend_exit(struct flexcop_device *fc);
++
++/* from flexcop-i2c.c */
++int flexcop_i2c_init(struct flexcop_device *fc);
++void flexcop_i2c_exit(struct flexcop_device *fc);
++
++/* from flexcop-sram.c */
++int flexcop_sram_init(struct flexcop_device *fc);
++
++/* 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);
++void flexcop_hw_filter_init(struct flexcop_device *fc);
++
++void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
++
++void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
++void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff);
++
++#endif
+diff --git a/drivers/media/common/b2c2/flexcop-eeprom.c b/drivers/media/common/b2c2/flexcop-eeprom.c
+new file mode 100644
+index 0000000..a25373a
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-eeprom.c
+@@ -0,0 +1,147 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
++ * see flexcop.c for copyright information
++ */
++#include "flexcop.h"
++
++#if 0
++/*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_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 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;
++}
++
++static int flexcop_eeprom_read(struct flexcop_device *fc,
++              u16 addr, u8 *buf, u16 len)
++{
++      return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
++}
++
++#endif
++
++static u8 calc_lrc(u8 *buf, int len)
++{
++      int i;
++      u8 sum = 0;
++      for (i = 0; i < len; i++)
++              sum = sum ^ buf[i];
++      return sum;
++}
++
++static int flexcop_eeprom_request(struct flexcop_device *fc,
++      flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
++{
++      int i,ret = 0;
++      u8 chipaddr =  0x50 | ((addr >> 8) & 3);
++      for (i = 0; i < retries; i++) {
++              ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
++                      addr & 0xff, buf, len);
++              if (ret == 0)
++                      break;
++      }
++      return ret;
++}
++
++static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr,
++              u8 *buf, u16 len, int retries)
++{
++      int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
++      if (ret == 0)
++              if (calc_lrc(buf, len - 1) != buf[len - 1])
++                      ret = -EINVAL;
++      return ret;
++}
++
++/* JJ's comment about extended == 1: it is not presently used anywhere but was
++ * added to the low-level functions for possible support of EUI64 */
++int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
++{
++      u8 buf[8];
++      int ret = 0;
++
++      if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
++              if (extended != 0) {
++                      err("TODO: extended (EUI64) MAC addresses aren't "
++                              "completely supported yet");
++                      ret = -EINVAL;
++              } else
++                      memcpy(fc->dvb_adapter.proposed_mac,buf,6);
++      }
++      return ret;
++}
++EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
+diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c
+new file mode 100644
+index 0000000..850a6c6
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c
+@@ -0,0 +1,678 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
++ * see flexcop.c for copyright information
++ */
++#include <media/tuner.h>
++#include "flexcop.h"
++#include "mt312.h"
++#include "stv0299.h"
++#include "s5h1420.h"
++#include "itd1000.h"
++#include "cx24113.h"
++#include "cx24123.h"
++#include "isl6421.h"
++#include "mt352.h"
++#include "bcm3510.h"
++#include "nxt200x.h"
++#include "dvb-pll.h"
++#include "lgdt330x.h"
++#include "tuner-simple.h"
++#include "stv0297.h"
++
++
++/* Can we use the specified front-end?  Remember that if we are compiled
++ * into the kernel we can't call code that's in modules.  */
++#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
++      (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
++
++/* lnb control */
++#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
++static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++{
++      struct flexcop_device *fc = fe->dvb->priv;
++      flexcop_ibi_value v;
++      deb_tuner("polarity/voltage = %u\n", voltage);
++
++      v = fc->read_ibi_reg(fc, misc_204);
++      switch (voltage) {
++      case SEC_VOLTAGE_OFF:
++              v.misc_204.ACPI1_sig = 1;
++              break;
++      case SEC_VOLTAGE_13:
++              v.misc_204.ACPI1_sig = 0;
++              v.misc_204.LNB_L_H_sig = 0;
++              break;
++      case SEC_VOLTAGE_18:
++              v.misc_204.ACPI1_sig = 0;
++              v.misc_204.LNB_L_H_sig = 1;
++              break;
++      default:
++              err("unknown SEC_VOLTAGE value");
++              return -EINVAL;
++      }
++      return fc->write_ibi_reg(fc, misc_204, v);
++}
++#endif
++
++#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
++static int flexcop_sleep(struct dvb_frontend* fe)
++{
++      struct flexcop_device *fc = fe->dvb->priv;
++      if (fc->fe_sleep)
++              return fc->fe_sleep(fe);
++      return 0;
++}
++#endif
++
++/* SkyStar2 DVB-S rev 2.3 */
++#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
++static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
++{
++/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
++      struct flexcop_device *fc = fe->dvb->priv;
++      flexcop_ibi_value v;
++      u16 ax;
++      v.raw = 0;
++      deb_tuner("tone = %u\n",tone);
++
++      switch (tone) {
++      case SEC_TONE_ON:
++              ax = 0x01ff;
++              break;
++      case SEC_TONE_OFF:
++              ax = 0;
++              break;
++      default:
++              err("unknown SEC_TONE value");
++              return -EINVAL;
++      }
++
++      v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
++      v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
++      v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
++      return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
++}
++
++static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
++{
++      flexcop_set_tone(fe, SEC_TONE_ON);
++      udelay(data ? 500 : 1000);
++      flexcop_set_tone(fe, SEC_TONE_OFF);
++      udelay(data ? 1000 : 500);
++}
++
++static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
++{
++      int i, par = 1, d;
++      for (i = 7; i >= 0; i--) {
++              d = (data >> i) & 1;
++              par ^= d;
++              flexcop_diseqc_send_bit(fe, d);
++      }
++      flexcop_diseqc_send_bit(fe, par);
++}
++
++static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
++      int len, u8 *msg, unsigned long burst)
++{
++      int i;
++
++      flexcop_set_tone(fe, SEC_TONE_OFF);
++      mdelay(16);
++
++      for (i = 0; i < len; i++)
++              flexcop_diseqc_send_byte(fe,msg[i]);
++      mdelay(16);
++
++      if (burst != -1) {
++              if (burst)
++                      flexcop_diseqc_send_byte(fe, 0xff);
++              else {
++                      flexcop_set_tone(fe, SEC_TONE_ON);
++                      mdelay(12);
++                      udelay(500);
++                      flexcop_set_tone(fe, SEC_TONE_OFF);
++              }
++              msleep(20);
++      }
++      return 0;
++}
++
++static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
++      struct dvb_diseqc_master_cmd *cmd)
++{
++      return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
++}
++
++static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
++      fe_sec_mini_cmd_t minicmd)
++{
++      return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
++}
++
++static struct mt312_config skystar23_samsung_tbdu18132_config = {
++      .demod_address = 0x0e,
++};
++
++static int skystar2_rev23_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      struct dvb_frontend_ops *ops;
++
++      fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
++      if (!fc->fe)
++              return 0;
++
++      if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
++                      DVB_PLL_SAMSUNG_TBDU18132))
++              return 0;
++
++      ops = &fc->fe->ops;
++      ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
++      ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
++      ops->set_tone               = flexcop_set_tone;
++      ops->set_voltage            = flexcop_set_voltage;
++      fc->fe_sleep                = ops->sleep;
++      ops->sleep                  = flexcop_sleep;
++      return 1;
++}
++#else
++#define skystar2_rev23_attach NULL
++#endif
++
++/* SkyStar2 DVB-S rev 2.6 */
++#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
++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 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,
++      .skip_reinit = 0,
++      .lock_output = STV0299_LOCKOUTPUT_LK,
++      .volt13_op0_op1 = STV0299_VOLT13_OP1,
++      .min_delay_ms = 100,
++      .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
++};
++
++static int skystar2_rev26_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
++      if (!fc->fe)
++              return 0;
++
++      if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
++                      DVB_PLL_SAMSUNG_TBMU24112))
++              return 0;
++
++      fc->fe->ops.set_voltage = flexcop_set_voltage;
++      fc->fe_sleep = fc->fe->ops.sleep;
++      fc->fe->ops.sleep = flexcop_sleep;
++      return 1;
++
++}
++#else
++#define skystar2_rev26_attach NULL
++#endif
++
++/* SkyStar2 DVB-S rev 2.7 */
++#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
++static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
++      .demod_address = 0x53,
++      .invert = 1,
++      .repeated_start_workaround = 1,
++      .serial_mpeg = 1,
++};
++
++static struct itd1000_config skystar2_rev2_7_itd1000_config = {
++      .i2c_address = 0x61,
++};
++
++static int skystar2_rev27_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      flexcop_ibi_value r108;
++      struct i2c_adapter *i2c_tuner;
++
++      /* enable no_base_addr - no repeated start when reading */
++      fc->fc_i2c_adap[0].no_base_addr = 1;
++      fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
++                          i2c);
++      if (!fc->fe)
++              goto fail;
++
++      i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
++      if (!i2c_tuner)
++              goto fail;
++
++      fc->fe_sleep = fc->fe->ops.sleep;
++      fc->fe->ops.sleep = flexcop_sleep;
++
++      /* enable no_base_addr - no repeated start when reading */
++      fc->fc_i2c_adap[2].no_base_addr = 1;
++      if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
++                      0x08, 1, 1)) {
++              err("ISL6421 could NOT be attached");
++              goto fail_isl;
++      }
++      info("ISL6421 successfully attached");
++
++      /* the ITD1000 requires a lower i2c clock - is it a problem ? */
++      r108.raw = 0x00000506;
++      fc->write_ibi_reg(fc, tw_sm_c_108, r108);
++      if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
++                      &skystar2_rev2_7_itd1000_config)) {
++              err("ITD1000 could NOT be attached");
++              /* Should i2c clock be restored? */
++              goto fail_isl;
++      }
++      info("ITD1000 successfully attached");
++
++      return 1;
++
++fail_isl:
++      fc->fc_i2c_adap[2].no_base_addr = 0;
++fail:
++      /* for the next devices we need it again */
++      fc->fc_i2c_adap[0].no_base_addr = 0;
++      return 0;
++}
++#else
++#define skystar2_rev27_attach NULL
++#endif
++
++/* SkyStar2 rev 2.8 */
++#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
++static struct cx24123_config skystar2_rev2_8_cx24123_config = {
++      .demod_address = 0x55,
++      .dont_use_pll = 1,
++      .agc_callback = cx24113_agc_callback,
++};
++
++static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
++      .i2c_addr = 0x54,
++      .xtal_khz = 10111,
++};
++
++static int skystar2_rev28_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      struct i2c_adapter *i2c_tuner;
++
++      fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
++                          i2c);
++      if (!fc->fe)
++              return 0;
++
++      i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
++      if (!i2c_tuner)
++              return 0;
++
++      if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
++                      i2c_tuner)) {
++              err("CX24113 could NOT be attached");
++              return 0;
++      }
++      info("CX24113 successfully attached");
++
++      fc->fc_i2c_adap[2].no_base_addr = 1;
++      if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
++                      0x08, 0, 0)) {
++              err("ISL6421 could NOT be attached");
++              fc->fc_i2c_adap[2].no_base_addr = 0;
++              return 0;
++      }
++      info("ISL6421 successfully attached");
++      /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
++       * IR-receiver (PIC16F818) - but the card has no input for that ??? */
++      return 1;
++}
++#else
++#define skystar2_rev28_attach NULL
++#endif
++
++/* AirStar DVB-T */
++#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
++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 struct mt352_config samsung_tdtc9251dh0_config = {
++      .demod_address = 0x0f,
++      .demod_init    = samsung_tdtc9251dh0_demod_init,
++};
++
++static int airstar_dvbt_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
++      if (!fc->fe)
++              return 0;
++
++      return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
++                          DVB_PLL_SAMSUNG_TDTC9251DH0);
++}
++#else
++#define airstar_dvbt_attach NULL
++#endif
++
++/* AirStar ATSC 1st generation */
++#if FE_SUPPORTED(BCM3510)
++static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
++      const struct firmware **fw, char* name)
++{
++      struct flexcop_device *fc = fe->dvb->priv;
++      return request_firmware(fw, name, fc->dev);
++}
++
++static struct bcm3510_config air2pc_atsc_first_gen_config = {
++      .demod_address    = 0x0f,
++      .request_firmware = flexcop_fe_request_firmware,
++};
++
++static int airstar_atsc1_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
++      return fc->fe != NULL;
++}
++#else
++#define airstar_atsc1_attach NULL
++#endif
++
++/* AirStar ATSC 2nd generation */
++#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
++static struct nxt200x_config samsung_tbmv_config = {
++      .demod_address = 0x0a,
++};
++
++static int airstar_atsc2_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
++      if (!fc->fe)
++              return 0;
++
++      return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
++                          DVB_PLL_SAMSUNG_TBMV);
++}
++#else
++#define airstar_atsc2_attach NULL
++#endif
++
++/* AirStar ATSC 3rd generation */
++#if FE_SUPPORTED(LGDT330X)
++static struct lgdt330x_config air2pc_atsc_hd5000_config = {
++      .demod_address       = 0x59,
++      .demod_chip          = LGDT3303,
++      .serial_mpeg         = 0x04,
++      .clock_polarity_flip = 1,
++};
++
++static int airstar_atsc3_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
++      if (!fc->fe)
++              return 0;
++
++      return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
++                          TUNER_LG_TDVS_H06XF);
++}
++#else
++#define airstar_atsc3_attach NULL
++#endif
++
++/* CableStar2 DVB-C */
++#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
++static u8 alps_tdee4_stv0297_inittab[] = {
++      0x80, 0x01,
++      0x80, 0x00,
++      0x81, 0x01,
++      0x81, 0x00,
++      0x00, 0x48,
++      0x01, 0x58,
++      0x03, 0x00,
++      0x04, 0x00,
++      0x07, 0x00,
++      0x08, 0x00,
++      0x30, 0xff,
++      0x31, 0x9d,
++      0x32, 0xff,
++      0x33, 0x00,
++      0x34, 0x29,
++      0x35, 0x55,
++      0x36, 0x80,
++      0x37, 0x6e,
++      0x38, 0x9c,
++      0x40, 0x1a,
++      0x41, 0xfe,
++      0x42, 0x33,
++      0x43, 0x00,
++      0x44, 0xff,
++      0x45, 0x00,
++      0x46, 0x00,
++      0x49, 0x04,
++      0x4a, 0x51,
++      0x4b, 0xf8,
++      0x52, 0x30,
++      0x53, 0x06,
++      0x59, 0x06,
++      0x5a, 0x5e,
++      0x5b, 0x04,
++      0x61, 0x49,
++      0x62, 0x0a,
++      0x70, 0xff,
++      0x71, 0x04,
++      0x72, 0x00,
++      0x73, 0x00,
++      0x74, 0x0c,
++      0x80, 0x20,
++      0x81, 0x00,
++      0x82, 0x30,
++      0x83, 0x00,
++      0x84, 0x04,
++      0x85, 0x22,
++      0x86, 0x08,
++      0x87, 0x1b,
++      0x88, 0x00,
++      0x89, 0x00,
++      0x90, 0x00,
++      0x91, 0x04,
++      0xa0, 0x86,
++      0xa1, 0x00,
++      0xa2, 0x00,
++      0xb0, 0x91,
++      0xb1, 0x0b,
++      0xc0, 0x5b,
++      0xc1, 0x10,
++      0xc2, 0x12,
++      0xd0, 0x02,
++      0xd1, 0x00,
++      0xd2, 0x00,
++      0xd3, 0x00,
++      0xd4, 0x02,
++      0xd5, 0x00,
++      0xde, 0x00,
++      0xdf, 0x01,
++      0xff, 0xff,
++};
++
++static struct stv0297_config alps_tdee4_stv0297_config = {
++      .demod_address = 0x1c,
++      .inittab = alps_tdee4_stv0297_inittab,
++};
++
++static int cablestar2_attach(struct flexcop_device *fc,
++      struct i2c_adapter *i2c)
++{
++      fc->fc_i2c_adap[0].no_base_addr = 1;
++      fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
++      if (!fc->fe)
++              goto fail;
++
++      /* This tuner doesn't use the stv0297's I2C gate, but instead the
++       * tuner is connected to a different flexcop I2C adapter.  */
++      if (fc->fe->ops.i2c_gate_ctrl)
++              fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
++      fc->fe->ops.i2c_gate_ctrl = NULL;
++
++      if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
++                      &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
++              goto fail;
++
++      return 1;
++
++fail:
++      /* Reset for next frontend to try */
++      fc->fc_i2c_adap[0].no_base_addr = 0;
++      return 0;
++}
++#else
++#define cablestar2_attach NULL
++#endif
++
++static struct {
++      flexcop_device_type_t type;
++      int (*attach)(struct flexcop_device *, struct i2c_adapter *);
++} flexcop_frontends[] = {
++      { FC_SKY_REV27, skystar2_rev27_attach },
++      { FC_SKY_REV28, skystar2_rev28_attach },
++      { FC_SKY_REV26, skystar2_rev26_attach },
++      { FC_AIR_DVBT, airstar_dvbt_attach },
++      { FC_AIR_ATSC2, airstar_atsc2_attach },
++      { FC_AIR_ATSC3, airstar_atsc3_attach },
++      { FC_AIR_ATSC1, airstar_atsc1_attach },
++      { FC_CABLE, cablestar2_attach },
++      { FC_SKY_REV23, skystar2_rev23_attach },
++};
++
++/* try to figure out the frontend */
++int flexcop_frontend_init(struct flexcop_device *fc)
++{
++      int i;
++      for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
++              if (!flexcop_frontends[i].attach)
++                      continue;
++              /* type needs to be set before, because of some workarounds
++               * done based on the probed card type */
++              fc->dev_type = flexcop_frontends[i].type;
++              if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
++                      goto fe_found;
++              /* Clean up partially attached frontend */
++              if (fc->fe) {
++                      dvb_frontend_detach(fc->fe);
++                      fc->fe = NULL;
++              }
++      }
++      fc->dev_type = FC_UNK;
++      err("no frontend driver found for this B2C2/FlexCop adapter");
++      return -ENODEV;
++
++fe_found:
++      info("found '%s' .", fc->fe->ops.info.name);
++      if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
++              err("frontend registration failed!");
++              dvb_frontend_detach(fc->fe);
++              fc->fe = NULL;
++              return -EINVAL;
++      }
++      fc->init_state |= FC_STATE_FE_INIT;
++      return 0;
++}
++
++void flexcop_frontend_exit(struct flexcop_device *fc)
++{
++      if (fc->init_state & FC_STATE_FE_INIT) {
++              dvb_unregister_frontend(fc->fe);
++              dvb_frontend_detach(fc->fe);
++      }
++      fc->init_state &= ~FC_STATE_FE_INIT;
++}
+diff --git a/drivers/media/common/b2c2/flexcop-hw-filter.c b/drivers/media/common/b2c2/flexcop-hw-filter.c
+new file mode 100644
+index 0000000..77e4547
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-hw-filter.c
+@@ -0,0 +1,232 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-hw-filter.c - pid and mac address filtering and control functions
++ * see flexcop.c for copyright information
++ */
++#include "flexcop.h"
++
++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)
++{
++      flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
++}
++
++static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
++{
++      flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff);
++}
++
++void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
++{
++      flexcop_ibi_value v418, v41c;
++      v41c = fc->read_ibi_reg(fc, mac_address_41c);
++
++      v418.mac_address_418.MAC1 = mac[0];
++      v418.mac_address_418.MAC2 = mac[1];
++      v418.mac_address_418.MAC3 = mac[2];
++      v418.mac_address_418.MAC6 = mac[3];
++      v41c.mac_address_41c.MAC7 = mac[4];
++      v41c.mac_address_41c.MAC8 = mac[5];
++
++      fc->write_ibi_reg(fc, mac_address_418, v418);
++      fc->write_ibi_reg(fc, mac_address_41c, v41c);
++}
++
++void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
++{
++      flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff);
++}
++
++static void flexcop_pid_group_filter(struct flexcop_device *fc,
++              u16 pid, u16 mask)
++{
++      /* index_reg_310.extra_index_reg need to 0 or 7 to work */
++      flexcop_ibi_value v30c;
++      v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
++      v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
++      fc->write_ibi_reg(fc, pid_filter_30c, v30c);
++}
++
++static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
++{
++      flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff);
++}
++
++/* this fancy define reduces the code size of the quite similar PID controlling of
++ * the first 6 PIDs
++ */
++
++#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
++      flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
++v208 = fc->read_ibi_reg(fc, ctrl_208); \
++vpid.vregname.field = onoff ? pid : 0x1fff; \
++vpid.vregname.trans_field = transval; \
++v208.ctrl_208.enablefield = onoff; \
++fc->write_ibi_reg(fc, vregname, vpid); \
++fc->write_ibi_reg(fc, ctrl_208, v208);
++
++static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc,
++              u16 pid, int onoff)
++{
++      pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig,
++                      Stream1_trans, 0);
++}
++
++static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc,
++              u16 pid, int onoff)
++{
++      pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig,
++                      Stream2_trans, 0);
++}
++
++static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc,
++              u16 pid, int onoff)
++{
++      pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0);
++}
++
++static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc,
++              u16 pid, int onoff)
++{
++      pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0);
++}
++
++static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc,
++              u16 pid, int onoff)
++{
++      pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0);
++}
++
++static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc,
++              u16 pid, int onoff)
++{
++      pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0);
++}
++
++static void flexcop_pid_control(struct flexcop_device *fc,
++              int index, u16 pid, int onoff)
++{
++      if (pid == 0x2000)
++              return;
++
++      deb_ts("setting pid: %5d %04x at index %d '%s'\n",
++                      pid, pid, index, onoff ? "on" : "off");
++
++      /* We could use bit magic here to reduce source code size.
++       * I decided against it, but to use the real register names */
++      switch (index) {
++      case 0:
++              flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff);
++              break;
++      case 1:
++              flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff);
++              break;
++      case 2:
++              flexcop_pid_PCR_PID_ctrl(fc, pid, onoff);
++              break;
++      case 3:
++              flexcop_pid_PMT_PID_ctrl(fc, pid, onoff);
++              break;
++      case 4:
++              flexcop_pid_EMM_PID_ctrl(fc, pid, onoff);
++              break;
++      case 5:
++              flexcop_pid_ECM_PID_ctrl(fc, pid, onoff);
++              break;
++      default:
++              if (fc->has_32_hw_pid_filter && index < 38) {
++                      flexcop_ibi_value vpid, vid;
++
++                      /* set the index */
++                      vid = fc->read_ibi_reg(fc, index_reg_310);
++                      vid.index_reg_310.index_reg = index - 6;
++                      fc->write_ibi_reg(fc, index_reg_310, vid);
++
++                      vpid = fc->read_ibi_reg(fc, pid_n_reg_314);
++                      vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
++                      vpid.pid_n_reg_314.PID_enable_bit = onoff;
++                      fc->write_ibi_reg(fc, pid_n_reg_314, vpid);
++              }
++              break;
++      }
++}
++
++static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff)
++{
++      if (fc->fullts_streaming_state != onoff) {
++              deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
++              flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
++              flexcop_pid_group_filter_ctrl(fc, onoff);
++              fc->fullts_streaming_state = onoff;
++      }
++      return 0;
++}
++
++int flexcop_pid_feed_control(struct flexcop_device *fc,
++              struct dvb_demux_feed *dvbdmxfeed, int onoff)
++{
++      int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
++
++      fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
++      if (dvbdmxfeed->index >= max_pid_filter)
++              fc->extra_feedcount += onoff ? 1 : -1;
++
++      /* toggle complete-TS-streaming when:
++       * - pid_filtering is not enabled and it is the first or last feed requested
++       * - pid_filtering is enabled,
++       *   - but the number of requested feeds is exceeded
++       *   - or the requested pid is 0x2000 */
++
++      if (!fc->pid_filtering && fc->feedcount == onoff)
++              flexcop_toggle_fullts_streaming(fc, onoff);
++
++      if (fc->pid_filtering) {
++              flexcop_pid_control \
++                      (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
++
++              if (fc->extra_feedcount > 0)
++                      flexcop_toggle_fullts_streaming(fc, 1);
++              else if (dvbdmxfeed->pid == 0x2000)
++                      flexcop_toggle_fullts_streaming(fc, onoff);
++              else
++                      flexcop_toggle_fullts_streaming(fc, 0);
++      }
++
++      /* 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) /* 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;
++}
++EXPORT_SYMBOL(flexcop_pid_feed_control);
++
++void flexcop_hw_filter_init(struct flexcop_device *fc)
++{
++      int i;
++      flexcop_ibi_value v;
++      for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
++              flexcop_pid_control(fc, i, 0x1fff, 0);
++
++      flexcop_pid_group_filter(fc, 0, 0x1fe0);
++      flexcop_pid_group_filter_ctrl(fc, 0);
++
++      v = fc->read_ibi_reg(fc, pid_filter_308);
++      v.pid_filter_308.EMM_filter_4 = 1;
++      v.pid_filter_308.EMM_filter_6 = 0;
++      fc->write_ibi_reg(fc, pid_filter_308, v);
++
++      flexcop_null_filter_ctrl(fc, 1);
++}
+diff --git a/drivers/media/common/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c
+new file mode 100644
+index 0000000..965d5eb
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-i2c.c
+@@ -0,0 +1,288 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
++ * see flexcop.c for copyright information
++ */
++#include "flexcop.h"
++
++#define FC_MAX_I2C_RETRIES 100000
++
++static int flexcop_i2c_operation(struct flexcop_device *fc,
++              flexcop_ibi_value *r100)
++{
++      int i;
++      flexcop_ibi_value r;
++
++      r100->tw_sm_c_100.working_start = 1;
++      deb_i2c("r100 before: %08x\n",r100->raw);
++
++      fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
++      fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
++
++      for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
++              r = fc->read_ibi_reg(fc, tw_sm_c_100);
++
++              if (!r.tw_sm_c_100.no_base_addr_ack_error) {
++                      if (r.tw_sm_c_100.st_done) {
++                              *r100 = r;
++                              deb_i2c("i2c success\n");
++                              return 0;
++                      }
++              } else {
++                      deb_i2c("suffering from an i2c ack_error\n");
++                      return -EREMOTEIO;
++              }
++      }
++      deb_i2c("tried %d times i2c operation, "
++                      "never finished or too many ack errors.\n", i);
++      return -EREMOTEIO;
++}
++
++static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
++              flexcop_ibi_value r100, u8 *buf)
++{
++      flexcop_ibi_value r104;
++      int len = r100.tw_sm_c_100.total_bytes,
++              /* remember total_bytes is buflen-1 */
++              ret;
++
++      /* work-around to have CableStar2 and SkyStar2 rev 2.7 work
++       * correctly:
++       *
++       * the ITD1000 is behind an i2c-gate which closes automatically
++       * after an i2c-transaction the STV0297 needs 2 consecutive reads
++       * one with no_base_addr = 0 and one with 1
++       *
++       * those two work-arounds are conflictin: we check for the card
++       * type, it is set when probing the ITD1000 */
++      if (i2c->fc->dev_type == FC_SKY_REV27)
++              r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
++
++      ret = flexcop_i2c_operation(i2c->fc, &r100);
++      if (ret != 0) {
++              deb_i2c("Retrying operation\n");
++              r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
++              ret = flexcop_i2c_operation(i2c->fc, &r100);
++      }
++      if (ret != 0) {
++              deb_i2c("read failed. %d\n", ret);
++              return ret;
++      }
++
++      buf[0] = r100.tw_sm_c_100.data1_reg;
++
++      if (len > 0) {
++              r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104);
++              deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
++
++              /* there is at least one more byte, otherwise we wouldn't be here */
++              buf[1] = r104.tw_sm_c_104.data2_reg;
++              if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
++              if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
++      }
++      return 0;
++}
++
++static int flexcop_i2c_write4(struct flexcop_device *fc,
++              flexcop_ibi_value r100, u8 *buf)
++{
++      flexcop_ibi_value r104;
++      int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
++      r104.raw = 0;
++
++      /* there is at least one byte, otherwise we wouldn't be here */
++      r100.tw_sm_c_100.data1_reg = buf[0];
++      r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
++      r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
++      r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
++
++      deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
++
++      /* write the additional i2c data before doing the actual i2c operation */
++      fc->write_ibi_reg(fc, tw_sm_c_104, r104);
++      return flexcop_i2c_operation(fc, &r100);
++}
++
++int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
++              flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
++{
++      int ret;
++
++#ifdef DUMP_I2C_MESSAGES
++      int i;
++#endif
++
++      u16 bytes_to_transfer;
++      flexcop_ibi_value r100;
++
++      deb_i2c("op = %d\n",op);
++      r100.raw = 0;
++      r100.tw_sm_c_100.chipaddr = chipaddr;
++      r100.tw_sm_c_100.twoWS_rw = op;
++      r100.tw_sm_c_100.twoWS_port_reg = i2c->port;
++
++#ifdef DUMP_I2C_MESSAGES
++      printk(KERN_DEBUG "%d ", i2c->port);
++      if (op == FC_READ)
++              printk("rd(");
++      else
++              printk("wr(");
++      printk("%02x): %02x ", chipaddr, addr);
++#endif
++
++      /* in that case addr is the only value ->
++       * we write it twice as baseaddr and val0
++       * BBTI is doing it like that for ISL6421 at least */
++      if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
++              buf = &addr;
++              len = 1;
++      }
++
++      while (len != 0) {
++              bytes_to_transfer = len > 4 ? 4 : len;
++
++              r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
++              r100.tw_sm_c_100.baseaddr = addr;
++
++              if (op == FC_READ)
++                      ret = flexcop_i2c_read4(i2c, r100, buf);
++              else
++                      ret = flexcop_i2c_write4(i2c->fc, r100, buf);
++
++#ifdef DUMP_I2C_MESSAGES
++              for (i = 0; i < bytes_to_transfer; i++)
++                      printk("%02x ", buf[i]);
++#endif
++
++              if (ret < 0)
++                      return ret;
++
++              buf  += bytes_to_transfer;
++              addr += bytes_to_transfer;
++              len  -= bytes_to_transfer;
++      }
++
++#ifdef DUMP_I2C_MESSAGES
++      printk("\n");
++#endif
++
++      return 0;
++}
++/* exported for PCI i2c */
++EXPORT_SYMBOL(flexcop_i2c_request);
++
++/* master xfer callback for demodulator */
++static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
++              struct i2c_msg msgs[], int num)
++{
++      struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
++      int i, ret = 0;
++
++      /* Some drivers use 1 byte or 0 byte reads as probes, which this
++       * driver doesn't support.  These probes will always fail, so this
++       * hack makes them always succeed.  If one knew how, it would of
++       * course be better to actually do the read.  */
++      if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
++              return 1;
++
++      if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
++              return -ERESTARTSYS;
++
++      for (i = 0; i < num; i++) {
++              /* reading */
++              if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
++                      ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
++                                      msgs[i].buf[0], msgs[i+1].buf,
++                                      msgs[i+1].len);
++                      i++; /* skip the following message */
++              } else /* writing */
++                      ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
++                                      msgs[i].buf[0], &msgs[i].buf[1],
++                                      msgs[i].len - 1);
++              if (ret < 0) {
++                      deb_i2c("i2c master_xfer failed");
++                      break;
++              }
++      }
++
++      mutex_unlock(&i2c->fc->i2c_mutex);
++
++      if (ret == 0)
++              ret = num;
++      return ret;
++}
++
++static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
++{
++      return I2C_FUNC_I2C;
++}
++
++static struct i2c_algorithm flexcop_algo = {
++      .master_xfer    = flexcop_master_xfer,
++      .functionality  = flexcop_i2c_func,
++};
++
++int flexcop_i2c_init(struct flexcop_device *fc)
++{
++      int ret;
++      mutex_init(&fc->i2c_mutex);
++
++      fc->fc_i2c_adap[0].fc = fc;
++      fc->fc_i2c_adap[1].fc = fc;
++      fc->fc_i2c_adap[2].fc = fc;
++      fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
++      fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
++      fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
++
++      strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
++                      sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
++      strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
++                      sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
++      strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
++                      sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
++
++      i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
++      i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
++      i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
++
++      fc->fc_i2c_adap[0].i2c_adap.algo =
++              fc->fc_i2c_adap[1].i2c_adap.algo =
++              fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
++      fc->fc_i2c_adap[0].i2c_adap.algo_data =
++              fc->fc_i2c_adap[1].i2c_adap.algo_data =
++              fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
++      fc->fc_i2c_adap[0].i2c_adap.dev.parent =
++              fc->fc_i2c_adap[1].i2c_adap.dev.parent =
++              fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
++
++      ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
++      if (ret < 0)
++              return ret;
++
++      ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
++      if (ret < 0)
++              goto adap_1_failed;
++
++      ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
++      if (ret < 0)
++              goto adap_2_failed;
++
++      fc->init_state |= FC_STATE_I2C_INIT;
++      return 0;
++
++adap_2_failed:
++      i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
++adap_1_failed:
++      i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
++      return ret;
++}
++
++void flexcop_i2c_exit(struct flexcop_device *fc)
++{
++      if (fc->init_state & FC_STATE_I2C_INIT) {
++              i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
++              i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
++              i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
++      }
++      fc->init_state &= ~FC_STATE_I2C_INIT;
++}
+diff --git a/drivers/media/common/b2c2/flexcop-misc.c b/drivers/media/common/b2c2/flexcop-misc.c
+new file mode 100644
+index 0000000..f06f3a9
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-misc.c
+@@ -0,0 +1,86 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-misc.c - miscellaneous functions
++ * see flexcop.c for copyright information
++ */
++#include "flexcop.h"
++
++void flexcop_determine_revision(struct flexcop_device *fc)
++{
++      flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
++
++      switch (v.misc_204.Rev_N_sig_revision_hi) {
++      case 0x2:
++              deb_info("found a FlexCopII.\n");
++              fc->rev = FLEXCOP_II;
++              break;
++      case 0x3:
++              deb_info("found a FlexCopIIb.\n");
++              fc->rev = FLEXCOP_IIB;
++              break;
++      case 0x0:
++              deb_info("found a FlexCopIII.\n");
++              fc->rev = FLEXCOP_III;
++              break;
++      default:
++              err("unknown FlexCop Revision: %x. Please report this to "
++                              "linux-dvb@linuxtv.org.",
++                              v.misc_204.Rev_N_sig_revision_hi);
++              break;
++      }
++
++      if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
++              deb_info("this FlexCop has "
++                              "the additional 32 hardware pid filter.\n");
++      else
++              deb_info("this FlexCop has "
++                              "the 6 basic main hardware pid filter.\n");
++      /* bus parts have to decide if hw pid filtering is used or not. */
++}
++
++static const char *flexcop_revision_names[] = {
++      "Unknown chip",
++      "FlexCopII",
++      "FlexCopIIb",
++      "FlexCopIII",
++};
++
++static const char *flexcop_device_names[] = {
++      [FC_UNK]        = "Unknown device",
++      [FC_CABLE]      = "Cable2PC/CableStar 2 DVB-C",
++      [FC_AIR_DVBT]   = "Air2PC/AirStar 2 DVB-T",
++      [FC_AIR_ATSC1]  = "Air2PC/AirStar 2 ATSC 1st generation",
++      [FC_AIR_ATSC2]  = "Air2PC/AirStar 2 ATSC 2nd generation",
++      [FC_AIR_ATSC3]  = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
++      [FC_SKY_REV23]  = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
++      [FC_SKY_REV26]  = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
++      [FC_SKY_REV27]  = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
++      [FC_SKY_REV28]  = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
++};
++
++static const char *flexcop_bus_names[] = {
++      "USB",
++      "PCI",
++};
++
++void flexcop_device_name(struct flexcop_device *fc,
++              const char *prefix, const char *suffix)
++{
++      info("%s '%s' at the '%s' bus controlled by a '%s' %s",
++                      prefix, 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/common/b2c2/flexcop-reg.h b/drivers/media/common/b2c2/flexcop-reg.h
+new file mode 100644
+index 0000000..dc4528d
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-reg.h
+@@ -0,0 +1,166 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
++ * see flexcop.c for copyright information
++ */
++#ifndef __FLEXCOP_REG_H__
++#define __FLEXCOP_REG_H__
++
++typedef enum {
++      FLEXCOP_UNK = 0,
++      FLEXCOP_II,
++      FLEXCOP_IIB,
++      FLEXCOP_III,
++} flexcop_revision_t;
++
++typedef enum {
++      FC_UNK = 0,
++      FC_CABLE,
++      FC_AIR_DVBT,
++      FC_AIR_ATSC1,
++      FC_AIR_ATSC2,
++      FC_AIR_ATSC3,
++      FC_SKY_REV23,
++      FC_SKY_REV26,
++      FC_SKY_REV27,
++      FC_SKY_REV28,
++} flexcop_device_type_t;
++
++typedef enum {
++      FC_USB = 0,
++      FC_PCI,
++} flexcop_bus_t;
++
++/* FlexCop IBI Registers */
++#if defined(__LITTLE_ENDIAN)
++#include "flexcop_ibi_value_le.h"
++#else
++#if defined(__BIG_ENDIAN)
++#include "flexcop_ibi_value_be.h"
++#else
++#error no endian defined
++#endif
++#endif
++
++#define fc_data_Tag_ID_DVB  0x3e
++#define fc_data_Tag_ID_ATSC 0x3f
++#define fc_data_Tag_ID_IDSB 0x8b
++
++#define fc_key_code_default 0x1
++#define fc_key_code_even    0x2
++#define fc_key_code_odd     0x3
++
++extern flexcop_ibi_value ibi_zero;
++
++typedef enum {
++      FC_I2C_PORT_DEMOD  = 1,
++      FC_I2C_PORT_EEPROM = 2,
++      FC_I2C_PORT_TUNER  = 3,
++} flexcop_i2c_port_t;
++
++typedef enum {
++      FC_WRITE = 0,
++      FC_READ  = 1,
++} flexcop_access_op_t;
++
++typedef enum {
++      FC_SRAM_DEST_NET   = 1,
++      FC_SRAM_DEST_CAI   = 2,
++      FC_SRAM_DEST_CAO   = 4,
++      FC_SRAM_DEST_MEDIA = 8
++} flexcop_sram_dest_t;
++
++typedef enum {
++      FC_SRAM_DEST_TARGET_WAN_USB = 0,
++      FC_SRAM_DEST_TARGET_DMA1    = 1,
++      FC_SRAM_DEST_TARGET_DMA2    = 2,
++      FC_SRAM_DEST_TARGET_FC3_CA  = 3
++} flexcop_sram_dest_target_t;
++
++typedef enum {
++      FC_SRAM_2_32KB  = 0, /*  64KB */
++      FC_SRAM_1_32KB  = 1, /*  32KB - default fow FCII */
++      FC_SRAM_1_128KB = 2, /* 128KB */
++      FC_SRAM_1_48KB  = 3, /*  48KB - default for FCIII */
++} flexcop_sram_type_t;
++
++typedef enum {
++      FC_WAN_SPEED_4MBITS  = 0,
++      FC_WAN_SPEED_8MBITS  = 1,
++      FC_WAN_SPEED_12MBITS = 2,
++      FC_WAN_SPEED_16MBITS = 3,
++} flexcop_wan_speed_t;
++
++typedef enum {
++      FC_DMA_1 = 1,
++      FC_DMA_2 = 2,
++} flexcop_dma_index_t;
++
++typedef enum {
++      FC_DMA_SUBADDR_0 = 1,
++      FC_DMA_SUBADDR_1 = 2,
++} flexcop_dma_addr_index_t;
++
++/* names of the particular registers */
++typedef enum {
++      dma1_000            = 0x000,
++      dma1_004            = 0x004,
++      dma1_008            = 0x008,
++      dma1_00c            = 0x00c,
++      dma2_010            = 0x010,
++      dma2_014            = 0x014,
++      dma2_018            = 0x018,
++      dma2_01c            = 0x01c,
++
++      tw_sm_c_100         = 0x100,
++      tw_sm_c_104         = 0x104,
++      tw_sm_c_108         = 0x108,
++      tw_sm_c_10c         = 0x10c,
++      tw_sm_c_110         = 0x110,
++
++      lnb_switch_freq_200 = 0x200,
++      misc_204            = 0x204,
++      ctrl_208            = 0x208,
++      irq_20c             = 0x20c,
++      sw_reset_210        = 0x210,
++      misc_214            = 0x214,
++      mbox_v8_to_host_218 = 0x218,
++      mbox_host_to_v8_21c = 0x21c,
++
++      pid_filter_300      = 0x300,
++      pid_filter_304      = 0x304,
++      pid_filter_308      = 0x308,
++      pid_filter_30c      = 0x30c,
++      index_reg_310       = 0x310,
++      pid_n_reg_314       = 0x314,
++      mac_low_reg_318     = 0x318,
++      mac_high_reg_31c    = 0x31c,
++
++      data_tag_400        = 0x400,
++      card_id_408         = 0x408,
++      card_id_40c         = 0x40c,
++      mac_address_418     = 0x418,
++      mac_address_41c     = 0x41c,
++
++      ci_600              = 0x600,
++      pi_604              = 0x604,
++      pi_608              = 0x608,
++      dvb_reg_60c         = 0x60c,
++
++      sram_ctrl_reg_700   = 0x700,
++      net_buf_reg_704     = 0x704,
++      cai_buf_reg_708     = 0x708,
++      cao_buf_reg_70c     = 0x70c,
++      media_buf_reg_710   = 0x710,
++      sram_dest_reg_714   = 0x714,
++      net_buf_reg_718     = 0x718,
++      wan_ctrl_reg_71c    = 0x71c,
++} flexcop_ibi_register;
++
++#define flexcop_set_ibi_value(reg,attr,val) { \
++      flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
++      v.reg.attr = val; \
++      fc->write_ibi_reg(fc,reg,v); \
++}
++
++#endif
+diff --git a/drivers/media/common/b2c2/flexcop-sram.c b/drivers/media/common/b2c2/flexcop-sram.c
+new file mode 100644
+index 0000000..f2199e4
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop-sram.c
+@@ -0,0 +1,363 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop-sram.c - functions for controlling the SRAM
++ * see flexcop.c for copyright information
++ */
++#include "flexcop.h"
++
++static void flexcop_sram_set_chip(struct flexcop_device *fc,
++              flexcop_sram_type_t type)
++{
++      flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type);
++}
++
++int flexcop_sram_init(struct flexcop_device *fc)
++{
++      switch (fc->rev) {
++      case FLEXCOP_II:
++      case FLEXCOP_IIB:
++              flexcop_sram_set_chip(fc, FC_SRAM_1_32KB);
++              break;
++      case FLEXCOP_III:
++              flexcop_sram_set_chip(fc, FC_SRAM_1_48KB);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
++               flexcop_sram_dest_target_t target)
++{
++      flexcop_ibi_value v;
++      v = fc->read_ibi_reg(fc, sram_dest_reg_714);
++
++      if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
++              err("SRAM destination target to available on FlexCopII(b)\n");
++              return -EINVAL;
++      }
++      deb_sram("sram dest: %x target: %x\n", dest, target);
++
++      if (dest & FC_SRAM_DEST_NET)
++              v.sram_dest_reg_714.NET_Dest = target;
++      if (dest & FC_SRAM_DEST_CAI)
++              v.sram_dest_reg_714.CAI_Dest = target;
++      if (dest & FC_SRAM_DEST_CAO)
++              v.sram_dest_reg_714.CAO_Dest = target;
++      if (dest & FC_SRAM_DEST_MEDIA)
++              v.sram_dest_reg_714.MEDIA_Dest = target;
++
++      fc->write_ibi_reg(fc,sram_dest_reg_714,v);
++      udelay(1000); /* TODO delay really necessary */
++
++      return 0;
++}
++EXPORT_SYMBOL(flexcop_sram_set_dest);
++
++void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
++{
++      flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
++}
++EXPORT_SYMBOL(flexcop_wan_set_speed);
++
++void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
++{
++      flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
++      v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
++      v.sram_dest_reg_714.ctrl_sramdma = sramdma;
++      v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
++      fc->write_ibi_reg(fc,sram_dest_reg_714,v);
++}
++EXPORT_SYMBOL(flexcop_sram_ctrl);
++
++#if 0
++static void flexcop_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", __func__);
++
++              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", __func__);
++
++              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", __func__);
++
++              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", __func__, adapter->dw_sram_type);
++      } else {
++              adapter->dw_sram_type = 0x10000;
++              ddprintk("%s: dw_sram_type = %x\n", __func__, 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", __func__, 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", __func__, 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", __func__, 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 flexcop_sram_detect(struct flexcop_device *fc)
++{
++      flexcop_ibi_value r208, r71c_0, vr71c_1;
++      r208 = fc->read_ibi_reg(fc, ctrl_208);
++      fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
++
++      r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
++      write_reg_dw(adapter, 0x71c, 1);
++      tmp3 = read_reg_dw(adapter, 0x71c);
++      dprintk("%s: tmp3 = %x\n", __func__, 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", __func__);
++              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", __func__);
++              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", __func__);
++              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", __func__);
++              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", __func__);
++      return 0;
++}
++
++static void sll_detect_sram_size(struct adapter *adapter)
++{
++      sram_detect_for_flex2(adapter);
++}
++
++#endif
+diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c
+new file mode 100644
+index 0000000..412c5da
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop.c
+@@ -0,0 +1,325 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop.c - main module part
++ * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
++ * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
++ *
++ * Acknowledgements:
++ *   John Jurrius from BBTI, Inc. for extensive support
++ *                    with code examples and data books
++ *   Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
++ *
++ * Contributions to the skystar2-driver have been done by
++ *   Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
++ *   Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
++ *   Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
++ *   Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
++ *               filtering)
++ *
++ * 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 "flexcop.h"
++
++#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
++#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
++
++#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
++#define DEBSTATUS ""
++#else
++#define DEBSTATUS " (debugging is not enabled)"
++#endif
++
++int b2c2_flexcop_debug;
++EXPORT_SYMBOL_GPL(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,32=reg (|-able))."
++              DEBSTATUS);
++#undef DEBSTATUS
++
++DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
++
++/* global zero for ibi values */
++flexcop_ibi_value ibi_zero;
++
++static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
++{
++      struct flexcop_device *fc = dvbdmxfeed->demux->priv;
++      return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
++}
++
++static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
++{
++      struct flexcop_device *fc = dvbdmxfeed->demux->priv;
++      return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
++}
++
++static int flexcop_dvb_init(struct flexcop_device *fc)
++{
++      int ret = dvb_register_adapter(&fc->dvb_adapter,
++                      "FlexCop Digital TV device", fc->owner,
++                      fc->dev, adapter_nr);
++      if (ret < 0) {
++              err("error registering DVB adapter");
++              return ret;
++      }
++      fc->dvb_adapter.priv = fc;
++
++      fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
++                      | DMX_MEMORY_BASED_FILTERING);
++      fc->demux.priv = fc;
++      fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
++      fc->demux.start_feed = flexcop_dvb_start_feed;
++      fc->demux.stop_feed = flexcop_dvb_stop_feed;
++      fc->demux.write_to_decoder = NULL;
++
++      ret = dvb_dmx_init(&fc->demux);
++      if (ret < 0) {
++              err("dvb_dmx failed: error %d", ret);
++              goto err_dmx;
++      }
++
++      fc->hw_frontend.source = DMX_FRONTEND_0;
++
++      fc->dmxdev.filternum = fc->demux.feednum;
++      fc->dmxdev.demux = &fc->demux.dmx;
++      fc->dmxdev.capabilities = 0;
++      ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
++      if (ret < 0) {
++              err("dvb_dmxdev_init failed: error %d", ret);
++              goto err_dmx_dev;
++      }
++
++      ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
++      if (ret < 0) {
++              err("adding hw_frontend to dmx failed: error %d", ret);
++              goto err_dmx_add_hw_frontend;
++      }
++
++      fc->mem_frontend.source = DMX_MEMORY_FE;
++      ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
++      if (ret < 0) {
++              err("adding mem_frontend to dmx failed: error %d", ret);
++              goto err_dmx_add_mem_frontend;
++      }
++
++      ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
++      if (ret < 0) {
++              err("connect frontend failed: error %d", ret);
++              goto err_connect_frontend;
++      }
++
++      ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
++      if (ret < 0) {
++              err("dvb_net_init failed: error %d", ret);
++              goto err_net;
++      }
++
++      fc->init_state |= FC_STATE_DVB_INIT;
++      return 0;
++
++err_net:
++      fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
++err_connect_frontend:
++      fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
++err_dmx_add_mem_frontend:
++      fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
++err_dmx_add_hw_frontend:
++      dvb_dmxdev_release(&fc->dmxdev);
++err_dmx_dev:
++      dvb_dmx_release(&fc->demux);
++err_dmx:
++      dvb_unregister_adapter(&fc->dvb_adapter);
++      return ret;
++}
++
++static void flexcop_dvb_exit(struct flexcop_device *fc)
++{
++      if (fc->init_state & FC_STATE_DVB_INIT) {
++              dvb_net_release(&fc->dvbnet);
++
++              fc->demux.dmx.close(&fc->demux.dmx);
++              fc->demux.dmx.remove_frontend(&fc->demux.dmx,
++                      &fc->mem_frontend);
++              fc->demux.dmx.remove_frontend(&fc->demux.dmx,
++                      &fc->hw_frontend);
++              dvb_dmxdev_release(&fc->dmxdev);
++              dvb_dmx_release(&fc->demux);
++              dvb_unregister_adapter(&fc->dvb_adapter);
++              deb_info("deinitialized dvb stuff\n");
++      }
++      fc->init_state &= ~FC_STATE_DVB_INIT;
++}
++
++/* these methods are necessary to achieve the long-term-goal of hiding the
++ * struct flexcop_device from the bus-parts */
++void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
++{
++      dvb_dmx_swfilter(&fc->demux, buf, len);
++}
++EXPORT_SYMBOL(flexcop_pass_dmx_data);
++
++void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
++{
++      dvb_dmx_swfilter_packets(&fc->demux, buf, no);
++}
++EXPORT_SYMBOL(flexcop_pass_dmx_packets);
++
++static void flexcop_reset(struct flexcop_device *fc)
++{
++      flexcop_ibi_value v210, v204;
++
++      /* reset the flexcop itself */
++      fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
++
++      v210.raw = 0;
++      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 */
++
++      v204 = fc->read_ibi_reg(fc,misc_204);
++      v204.misc_204.Per_reset_sig = 0;
++      fc->write_ibi_reg(fc,misc_204,v204);
++      msleep(1);
++      v204.misc_204.Per_reset_sig = 1;
++      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);
++      fc->write_ibi_reg(fc,ctrl_208,v208_save);
++}
++
++struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
++{
++      void *bus;
++      struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
++                              GFP_KERNEL);
++      if (!fc) {
++              err("no memory");
++              return NULL;
++      }
++
++      bus = kzalloc(bus_specific_len, GFP_KERNEL);
++      if (!bus) {
++              err("no memory");
++              kfree(fc);
++              return NULL;
++      }
++
++      fc->bus_specific = bus;
++
++      return fc;
++}
++EXPORT_SYMBOL(flexcop_device_kmalloc);
++
++void flexcop_device_kfree(struct flexcop_device *fc)
++{
++      kfree(fc->bus_specific);
++      kfree(fc);
++}
++EXPORT_SYMBOL(flexcop_device_kfree);
++
++int flexcop_device_initialize(struct flexcop_device *fc)
++{
++      int ret;
++      ibi_zero.raw = 0;
++
++      flexcop_reset(fc);
++      flexcop_determine_revision(fc);
++      flexcop_sram_init(fc);
++      flexcop_hw_filter_init(fc);
++      flexcop_smc_ctrl(fc, 0);
++
++      ret = flexcop_dvb_init(fc);
++      if (ret)
++              goto error;
++
++      /* i2c has to be done before doing EEProm stuff -
++       * because the EEProm is accessed via i2c */
++      ret = flexcop_i2c_init(fc);
++      if (ret)
++              goto error;
++
++      /* do the MAC address reading after initializing the dvb_adapter */
++      if (fc->get_mac_addr(fc, 0) == 0) {
++              u8 *b = fc->dvb_adapter.proposed_mac;
++              info("MAC address = %pM", b);
++              flexcop_set_mac_filter(fc,b);
++              flexcop_mac_filter_ctrl(fc,1);
++      } else
++              warn("reading of MAC address failed.\n");
++
++      ret = flexcop_frontend_init(fc);
++      if (ret)
++              goto error;
++
++      flexcop_device_name(fc,"initialization of","complete");
++      return 0;
++
++error:
++      flexcop_device_exit(fc);
++      return ret;
++}
++EXPORT_SYMBOL(flexcop_device_initialize);
++
++void flexcop_device_exit(struct flexcop_device *fc)
++{
++      flexcop_frontend_exit(fc);
++      flexcop_i2c_exit(fc);
++      flexcop_dvb_exit(fc);
++}
++EXPORT_SYMBOL(flexcop_device_exit);
++
++static int flexcop_module_init(void)
++{
++      info(DRIVER_NAME " loaded successfully");
++      return 0;
++}
++
++static void flexcop_module_cleanup(void)
++{
++      info(DRIVER_NAME " unloaded successfully");
++}
++
++module_init(flexcop_module_init);
++module_exit(flexcop_module_cleanup);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_NAME);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/common/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h
+new file mode 100644
+index 0000000..897b10c
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop.h
+@@ -0,0 +1,29 @@
++/*
++ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
++ * flexcop.h - private header file for all flexcop-chip-source files
++ * see flexcop.c for copyright information
++ */
++#ifndef __FLEXCOP_H__
++#define __FLEXCOP_H___
++
++#define FC_LOG_PREFIX "b2c2-flexcop"
++#include "flexcop-common.h"
++
++extern int b2c2_flexcop_debug;
++
++/* debug */
++#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
++#define dprintk(level,args...) \
++      do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
++#else
++#define dprintk(level,args...)
++#endif
++
++#define deb_info(args...) dprintk(0x01, args)
++#define deb_tuner(args...) dprintk(0x02, args)
++#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/common/b2c2/flexcop_ibi_value_be.h b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
+new file mode 100644
+index 0000000..8f64bdb
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
+@@ -0,0 +1,455 @@
++/* 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/common/b2c2/flexcop_ibi_value_le.h b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
+new file mode 100644
+index 0000000..c75830d
+--- /dev/null
++++ b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
+@@ -0,0 +1,455 @@
++/* 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/common/saa7146/Kconfig b/drivers/media/common/saa7146/Kconfig
+new file mode 100644
+index 0000000..769c6f8
+--- /dev/null
++++ b/drivers/media/common/saa7146/Kconfig
+@@ -0,0 +1,9 @@
++config VIDEO_SAA7146
++      tristate
++      depends on I2C && PCI
++
++config VIDEO_SAA7146_VV
++      tristate
++      depends on VIDEO_V4L2
++      select VIDEOBUF_DMA_SG
++      select VIDEO_SAA7146
+diff --git a/drivers/media/common/saa7146/Makefile b/drivers/media/common/saa7146/Makefile
+new file mode 100644
+index 0000000..3219b00
+--- /dev/null
++++ b/drivers/media/common/saa7146/Makefile
+@@ -0,0 +1,5 @@
++saa7146-objs    := saa7146_i2c.o saa7146_core.o
++saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
++
++obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
++obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
+diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
+new file mode 100644
+index 0000000..bb6ee51
+--- /dev/null
++++ b/drivers/media/common/saa7146/saa7146_core.c
+@@ -0,0 +1,592 @@
++/*
++    saa7146.o - driver for generic saa7146-based hardware
++
++    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <media/saa7146.h>
++#include <linux/module.h>
++
++static int saa7146_num;
++
++unsigned int saa7146_debug;
++
++module_param(saa7146_debug, uint, 0644);
++MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
++
++#if 0
++static void dump_registers(struct saa7146_dev* dev)
++{
++      int i = 0;
++
++      pr_info(" @ %li jiffies:\n", jiffies);
++      for (i = 0; i <= 0x148; i += 4)
++              pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
++}
++#endif
++
++/****************************************************************************
++ * gpio and debi helper functions
++ ****************************************************************************/
++
++void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
++{
++      u32 value = 0;
++
++      BUG_ON(port > 3);
++
++      value = saa7146_read(dev, GPIO_CTRL);
++      value &= ~(0xff << (8*port));
++      value |= (data << (8*port));
++      saa7146_write(dev, GPIO_CTRL, value);
++}
++
++/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
++static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
++                              unsigned long us1, unsigned long us2)
++{
++      unsigned long timeout;
++      int err;
++
++      /* wait for registers to be programmed */
++      timeout = jiffies + usecs_to_jiffies(us1);
++      while (1) {
++              err = time_after(jiffies, timeout);
++              if (saa7146_read(dev, MC2) & 2)
++                      break;
++              if (err) {
++                      pr_err("%s: %s timed out while waiting for registers getting programmed\n",
++                             dev->name, __func__);
++                      return -ETIMEDOUT;
++              }
++              msleep(1);
++      }
++
++      /* wait for transfer to complete */
++      timeout = jiffies + usecs_to_jiffies(us2);
++      while (1) {
++              err = time_after(jiffies, timeout);
++              if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
++                      break;
++              saa7146_read(dev, MC2);
++              if (err) {
++                      DEB_S("%s: %s timed out while waiting for transfer completion\n",
++                            dev->name, __func__);
++                      return -ETIMEDOUT;
++              }
++              msleep(1);
++      }
++
++      return 0;
++}
++
++static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
++                              unsigned long us1, unsigned long us2)
++{
++      unsigned long loops;
++
++      /* wait for registers to be programmed */
++      loops = us1;
++      while (1) {
++              if (saa7146_read(dev, MC2) & 2)
++                      break;
++              if (!loops--) {
++                      pr_err("%s: %s timed out while waiting for registers getting programmed\n",
++                             dev->name, __func__);
++                      return -ETIMEDOUT;
++              }
++              udelay(1);
++      }
++
++      /* wait for transfer to complete */
++      loops = us2 / 5;
++      while (1) {
++              if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
++                      break;
++              saa7146_read(dev, MC2);
++              if (!loops--) {
++                      DEB_S("%s: %s timed out while waiting for transfer completion\n",
++                            dev->name, __func__);
++                      return -ETIMEDOUT;
++              }
++              udelay(5);
++      }
++
++      return 0;
++}
++
++int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
++{
++      if (nobusyloop)
++              return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
++      else
++              return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
++}
++
++/****************************************************************************
++ * general helper functions
++ ****************************************************************************/
++
++/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
++   make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
++   may be triggered on highmem machines */
++static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
++{
++      struct scatterlist *sglist;
++      struct page *pg;
++      int i;
++
++      sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
++      if (NULL == sglist)
++              return NULL;
++      sg_init_table(sglist, nr_pages);
++      for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
++              pg = vmalloc_to_page(virt);
++              if (NULL == pg)
++                      goto err;
++              BUG_ON(PageHighMem(pg));
++              sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
++      }
++      return sglist;
++
++ err:
++      kfree(sglist);
++      return NULL;
++}
++
++/********************************************************************************/
++/* common page table functions */
++
++void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
++{
++      int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
++      void *mem = vmalloc_32(length);
++      int slen = 0;
++
++      if (NULL == mem)
++              goto err_null;
++
++      if (!(pt->slist = vmalloc_to_sg(mem, pages)))
++              goto err_free_mem;
++
++      if (saa7146_pgtable_alloc(pci, pt))
++              goto err_free_slist;
++
++      pt->nents = pages;
++      slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
++      if (0 == slen)
++              goto err_free_pgtable;
++
++      if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
++              goto err_unmap_sg;
++
++      return mem;
++
++err_unmap_sg:
++      pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
++err_free_pgtable:
++      saa7146_pgtable_free(pci, pt);
++err_free_slist:
++      kfree(pt->slist);
++      pt->slist = NULL;
++err_free_mem:
++      vfree(mem);
++err_null:
++      return NULL;
++}
++
++void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
++{
++      pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
++      saa7146_pgtable_free(pci, pt);
++      kfree(pt->slist);
++      pt->slist = NULL;
++      vfree(mem);
++}
++
++void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
++{
++      if (NULL == pt->cpu)
++              return;
++      pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
++      pt->cpu = NULL;
++}
++
++int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
++{
++      __le32       *cpu;
++      dma_addr_t   dma_addr = 0;
++
++      cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
++      if (NULL == cpu) {
++              return -ENOMEM;
++      }
++      pt->size = PAGE_SIZE;
++      pt->cpu  = cpu;
++      pt->dma  = dma_addr;
++
++      return 0;
++}
++
++int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
++      struct scatterlist *list, int sglen  )
++{
++      __le32 *ptr, fill;
++      int nr_pages = 0;
++      int i,p;
++
++      BUG_ON(0 == sglen);
++      BUG_ON(list->offset > PAGE_SIZE);
++
++      /* if we have a user buffer, the first page may not be
++         aligned to a page boundary. */
++      pt->offset = list->offset;
++
++      ptr = pt->cpu;
++      for (i = 0; i < sglen; i++, list++) {
++/*
++              pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
++                       i, sg_dma_address(list), sg_dma_len(list),
++                       list->offset);
++*/
++              for (p = 0; p * 4096 < list->length; p++, ptr++) {
++                      *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
++                      nr_pages++;
++              }
++      }
++
++
++      /* safety; fill the page table up with the last valid page */
++      fill = *(ptr-1);
++      for(i=nr_pages;i<1024;i++) {
++              *ptr++ = fill;
++      }
++
++/*
++      ptr = pt->cpu;
++      pr_debug("offset: %d\n", pt->offset);
++      for(i=0;i<5;i++) {
++              pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
++      }
++*/
++      return 0;
++}
++
++/********************************************************************************/
++/* interrupt handler */
++static irqreturn_t interrupt_hw(int irq, void *dev_id)
++{
++      struct saa7146_dev *dev = dev_id;
++      u32 isr;
++      u32 ack_isr;
++
++      /* read out the interrupt status register */
++      ack_isr = isr = saa7146_read(dev, ISR);
++
++      /* is this our interrupt? */
++      if ( 0 == isr ) {
++              /* nope, some other device */
++              return IRQ_NONE;
++      }
++
++      if (dev->ext) {
++              if (dev->ext->irq_mask & isr) {
++                      if (dev->ext->irq_func)
++                              dev->ext->irq_func(dev, &isr);
++                      isr &= ~dev->ext->irq_mask;
++              }
++      }
++      if (0 != (isr & (MASK_27))) {
++              DEB_INT("irq: RPS0 (0x%08x)\n", isr);
++              if (dev->vv_data && dev->vv_callback)
++                      dev->vv_callback(dev,isr);
++              isr &= ~MASK_27;
++      }
++      if (0 != (isr & (MASK_28))) {
++              if (dev->vv_data && dev->vv_callback)
++                      dev->vv_callback(dev,isr);
++              isr &= ~MASK_28;
++      }
++      if (0 != (isr & (MASK_16|MASK_17))) {
++              SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
++              /* only wake up if we expect something */
++              if (0 != dev->i2c_op) {
++                      dev->i2c_op = 0;
++                      wake_up(&dev->i2c_wq);
++              } else {
++                      u32 psr = saa7146_read(dev, PSR);
++                      u32 ssr = saa7146_read(dev, SSR);
++                      pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
++                              dev->name, isr, psr, ssr);
++              }
++              isr &= ~(MASK_16|MASK_17);
++      }
++      if( 0 != isr ) {
++              ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
++                  isr);
++              ERR("disabling interrupt source(s)!\n");
++              SAA7146_IER_DISABLE(dev,isr);
++      }
++      saa7146_write(dev, ISR, ack_isr);
++      return IRQ_HANDLED;
++}
++
++/*********************************************************************************/
++/* configuration-functions                                                       */
++
++static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
++{
++      struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
++      struct saa7146_extension *ext = pci_ext->ext;
++      struct saa7146_dev *dev;
++      int err = -ENOMEM;
++
++      /* clear out mem for sure */
++      dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
++      if (!dev) {
++              ERR("out of memory\n");
++              goto out;
++      }
++
++      DEB_EE("pci:%p\n", pci);
++
++      err = pci_enable_device(pci);
++      if (err < 0) {
++              ERR("pci_enable_device() failed\n");
++              goto err_free;
++      }
++
++      /* enable bus-mastering */
++      pci_set_master(pci);
++
++      dev->pci = pci;
++
++      /* get chip-revision; this is needed to enable bug-fixes */
++      dev->revision = pci->revision;
++
++      /* remap the memory from virtual to physical address */
++
++      err = pci_request_region(pci, 0, "saa7146");
++      if (err < 0)
++              goto err_disable;
++
++      dev->mem = ioremap(pci_resource_start(pci, 0),
++                         pci_resource_len(pci, 0));
++      if (!dev->mem) {
++              ERR("ioremap() failed\n");
++              err = -ENODEV;
++              goto err_release;
++      }
++
++      /* we don't do a master reset here anymore, it screws up
++         some boards that don't have an i2c-eeprom for configuration
++         values */
++/*
++      saa7146_write(dev, MC1, MASK_31);
++*/
++
++      /* disable all irqs */
++      saa7146_write(dev, IER, 0);
++
++      /* shut down all dma transfers and rps tasks */
++      saa7146_write(dev, MC1, 0x30ff0000);
++
++      /* clear out any rps-signals pending */
++      saa7146_write(dev, MC2, 0xf8000000);
++
++      /* request an interrupt for the saa7146 */
++      err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
++                        dev->name, dev);
++      if (err < 0) {
++              ERR("request_irq() failed\n");
++              goto err_unmap;
++      }
++
++      err = -ENOMEM;
++
++      /* get memory for various stuff */
++      dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
++                                                  &dev->d_rps0.dma_handle);
++      if (!dev->d_rps0.cpu_addr)
++              goto err_free_irq;
++      memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
++
++      dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
++                                                  &dev->d_rps1.dma_handle);
++      if (!dev->d_rps1.cpu_addr)
++              goto err_free_rps0;
++      memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
++
++      dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
++                                                 &dev->d_i2c.dma_handle);
++      if (!dev->d_i2c.cpu_addr)
++              goto err_free_rps1;
++      memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
++
++      /* the rest + print status message */
++
++      /* create a nice device name */
++      sprintf(dev->name, "saa7146 (%d)", saa7146_num);
++
++      pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
++              dev->mem, dev->revision, pci->irq,
++              pci->subsystem_vendor, pci->subsystem_device);
++      dev->ext = ext;
++
++      mutex_init(&dev->v4l2_lock);
++      spin_lock_init(&dev->int_slock);
++      spin_lock_init(&dev->slock);
++
++      mutex_init(&dev->i2c_lock);
++
++      dev->module = THIS_MODULE;
++      init_waitqueue_head(&dev->i2c_wq);
++
++      /* set some sane pci arbitrition values */
++      saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
++
++      /* TODO: use the status code of the callback */
++
++      err = -ENODEV;
++
++      if (ext->probe && ext->probe(dev)) {
++              DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
++              goto err_free_i2c;
++      }
++
++      if (ext->attach(dev, pci_ext)) {
++              DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
++              goto err_free_i2c;
++      }
++      /* V4L extensions will set the pci drvdata to the v4l2_device in the
++         attach() above. So for those cards that do not use V4L we have to
++         set it explicitly. */
++      pci_set_drvdata(pci, &dev->v4l2_dev);
++
++      saa7146_num++;
++
++      err = 0;
++out:
++      return err;
++
++err_free_i2c:
++      pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
++                          dev->d_i2c.dma_handle);
++err_free_rps1:
++      pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
++                          dev->d_rps1.dma_handle);
++err_free_rps0:
++      pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
++                          dev->d_rps0.dma_handle);
++err_free_irq:
++      free_irq(pci->irq, (void *)dev);
++err_unmap:
++      iounmap(dev->mem);
++err_release:
++      pci_release_region(pci, 0);
++err_disable:
++      pci_disable_device(pci);
++err_free:
++      kfree(dev);
++      goto out;
++}
++
++static void saa7146_remove_one(struct pci_dev *pdev)
++{
++      struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
++      struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
++      struct {
++              void *addr;
++              dma_addr_t dma;
++      } dev_map[] = {
++              { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
++              { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
++              { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
++              { NULL, 0 }
++      }, *p;
++
++      DEB_EE("dev:%p\n", dev);
++
++      dev->ext->detach(dev);
++      /* Zero the PCI drvdata after use. */
++      pci_set_drvdata(pdev, NULL);
++
++      /* shut down all video dma transfers */
++      saa7146_write(dev, MC1, 0x00ff0000);
++
++      /* disable all irqs, release irq-routine */
++      saa7146_write(dev, IER, 0);
++
++      free_irq(pdev->irq, dev);
++
++      for (p = dev_map; p->addr; p++)
++              pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
++
++      iounmap(dev->mem);
++      pci_release_region(pdev, 0);
++      pci_disable_device(pdev);
++      kfree(dev);
++
++      saa7146_num--;
++}
++
++/*********************************************************************************/
++/* extension handling functions                                                  */
++
++int saa7146_register_extension(struct saa7146_extension* ext)
++{
++      DEB_EE("ext:%p\n", ext);
++
++      ext->driver.name = ext->name;
++      ext->driver.id_table = ext->pci_tbl;
++      ext->driver.probe = saa7146_init_one;
++      ext->driver.remove = saa7146_remove_one;
++
++      pr_info("register extension '%s'\n", ext->name);
++      return pci_register_driver(&ext->driver);
++}
++
++int saa7146_unregister_extension(struct saa7146_extension* ext)
++{
++      DEB_EE("ext:%p\n", ext);
++      pr_info("unregister extension '%s'\n", ext->name);
++      pci_unregister_driver(&ext->driver);
++      return 0;
++}
++
++EXPORT_SYMBOL_GPL(saa7146_register_extension);
++EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
++
++/* misc functions used by extension modules */
++EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
++EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
++EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
++EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
++EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
++EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
++
++EXPORT_SYMBOL_GPL(saa7146_setgpio);
++
++EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
++
++EXPORT_SYMBOL_GPL(saa7146_debug);
++
++MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
++MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
+new file mode 100644
+index 0000000..eda01bc
+--- /dev/null
++++ b/drivers/media/common/saa7146/saa7146_fops.c
+@@ -0,0 +1,663 @@
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <media/saa7146_vv.h>
++#include <linux/module.h>
++
++/****************************************************************************/
++/* resource management functions, shamelessly stolen from saa7134 driver */
++
++int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      if (fh->resources & bit) {
++              DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
++                    bit, vv->resources);
++              /* have it already allocated */
++              return 1;
++      }
++
++      /* is it free? */
++      if (vv->resources & bit) {
++              DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
++                    vv->resources, bit);
++              /* no, someone else uses it */
++              return 0;
++      }
++      /* it's free, grab it */
++      fh->resources |= bit;
++      vv->resources |= bit;
++      DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
++      return 1;
++}
++
++void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      BUG_ON((fh->resources & bits) != bits);
++
++      fh->resources &= ~bits;
++      vv->resources &= ~bits;
++      DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
++}
++
++
++/********************************************************************************/
++/* common dma functions */
++
++void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
++                                              struct saa7146_buf *buf)
++{
++      struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
++      DEB_EE("dev:%p, buf:%p\n", dev, buf);
++
++      BUG_ON(in_interrupt());
++
++      videobuf_waiton(q, &buf->vb, 0, 0);
++      videobuf_dma_unmap(q->dev, dma);
++      videobuf_dma_free(dma);
++      buf->vb.state = VIDEOBUF_NEEDS_INIT;
++}
++
++
++/********************************************************************************/
++/* common buffer functions */
++
++int saa7146_buffer_queue(struct saa7146_dev *dev,
++                       struct saa7146_dmaqueue *q,
++                       struct saa7146_buf *buf)
++{
++      assert_spin_locked(&dev->slock);
++      DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
++
++      BUG_ON(!q);
++
++      if (NULL == q->curr) {
++              q->curr = buf;
++              DEB_D("immediately activating buffer %p\n", buf);
++              buf->activate(dev,buf,NULL);
++      } else {
++              list_add_tail(&buf->vb.queue,&q->queue);
++              buf->vb.state = VIDEOBUF_QUEUED;
++              DEB_D("adding buffer %p to queue. (active buffer present)\n",
++                    buf);
++      }
++      return 0;
++}
++
++void saa7146_buffer_finish(struct saa7146_dev *dev,
++                         struct saa7146_dmaqueue *q,
++                         int state)
++{
++      assert_spin_locked(&dev->slock);
++      DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
++      DEB_EE("q->curr:%p\n", q->curr);
++
++      BUG_ON(!q->curr);
++
++      /* finish current buffer */
++      if (NULL == q->curr) {
++              DEB_D("aiii. no current buffer\n");
++              return;
++      }
++
++      q->curr->vb.state = state;
++      v4l2_get_timestamp(&q->curr->vb.ts);
++      wake_up(&q->curr->vb.done);
++
++      q->curr = NULL;
++}
++
++void saa7146_buffer_next(struct saa7146_dev *dev,
++                       struct saa7146_dmaqueue *q, int vbi)
++{
++      struct saa7146_buf *buf,*next = NULL;
++
++      BUG_ON(!q);
++
++      DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
++
++      assert_spin_locked(&dev->slock);
++      if (!list_empty(&q->queue)) {
++              /* activate next one from queue */
++              buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
++              list_del(&buf->vb.queue);
++              if (!list_empty(&q->queue))
++                      next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
++              q->curr = buf;
++              DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
++                      buf, q->queue.prev, q->queue.next);
++              buf->activate(dev,buf,next);
++      } else {
++              DEB_INT("no next buffer. stopping.\n");
++              if( 0 != vbi ) {
++                      /* turn off video-dma3 */
++                      saa7146_write(dev,MC1, MASK_20);
++              } else {
++                      /* nothing to do -- just prevent next video-dma1 transfer
++                         by lowering the protection address */
++
++                      // fixme: fix this for vflip != 0
++
++                      saa7146_write(dev, PROT_ADDR1, 0);
++                      saa7146_write(dev, MC2, (MASK_02|MASK_18));
++
++                      /* write the address of the rps-program */
++                      saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
++                      /* turn on rps */
++                      saa7146_write(dev, MC1, (MASK_12 | MASK_28));
++
++/*
++                      printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
++                      printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
++                      printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
++                      printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
++                      printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));
++                      printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
++*/
++              }
++              del_timer(&q->timeout);
++      }
++}
++
++void saa7146_buffer_timeout(unsigned long data)
++{
++      struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data;
++      struct saa7146_dev *dev = q->dev;
++      unsigned long flags;
++
++      DEB_EE("dev:%p, dmaq:%p\n", dev, q);
++
++      spin_lock_irqsave(&dev->slock,flags);
++      if (q->curr) {
++              DEB_D("timeout on %p\n", q->curr);
++              saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
++      }
++
++      /* we don't restart the transfer here like other drivers do. when
++         a streaming capture is disabled, the timeout function will be
++         called for the current buffer. if we activate the next buffer now,
++         we mess up our capture logic. if a timeout occurs on another buffer,
++         then something is seriously broken before, so no need to buffer the
++         next capture IMHO... */
++/*
++      saa7146_buffer_next(dev,q);
++*/
++      spin_unlock_irqrestore(&dev->slock,flags);
++}
++
++/********************************************************************************/
++/* file operations */
++
++static int fops_open(struct file *file)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct saa7146_dev *dev = video_drvdata(file);
++      struct saa7146_fh *fh = NULL;
++      int result = 0;
++
++      DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
++
++      if (mutex_lock_interruptible(vdev->lock))
++              return -ERESTARTSYS;
++
++      DEB_D("using: %p\n", dev);
++
++      /* check if an extension is registered */
++      if( NULL == dev->ext ) {
++              DEB_S("no extension registered for this device\n");
++              result = -ENODEV;
++              goto out;
++      }
++
++      /* allocate per open data */
++      fh = kzalloc(sizeof(*fh),GFP_KERNEL);
++      if (NULL == fh) {
++              DEB_S("cannot allocate memory for per open data\n");
++              result = -ENOMEM;
++              goto out;
++      }
++
++      v4l2_fh_init(&fh->fh, vdev);
++
++      file->private_data = &fh->fh;
++      fh->dev = dev;
++
++      if (vdev->vfl_type == VFL_TYPE_VBI) {
++              DEB_S("initializing vbi...\n");
++              if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
++                      result = saa7146_vbi_uops.open(dev,file);
++              if (dev->ext_vv_data->vbi_fops.open)
++                      dev->ext_vv_data->vbi_fops.open(file);
++      } else {
++              DEB_S("initializing video...\n");
++              result = saa7146_video_uops.open(dev,file);
++      }
++
++      if (0 != result) {
++              goto out;
++      }
++
++      if( 0 == try_module_get(dev->ext->module)) {
++              result = -EINVAL;
++              goto out;
++      }
++
++      result = 0;
++      v4l2_fh_add(&fh->fh);
++out:
++      if (fh && result != 0) {
++              kfree(fh);
++              file->private_data = NULL;
++      }
++      mutex_unlock(vdev->lock);
++      return result;
++}
++
++static int fops_release(struct file *file)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct saa7146_fh  *fh  = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++
++      DEB_EE("file:%p\n", file);
++
++      mutex_lock(vdev->lock);
++
++      if (vdev->vfl_type == VFL_TYPE_VBI) {
++              if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
++                      saa7146_vbi_uops.release(dev,file);
++              if (dev->ext_vv_data->vbi_fops.release)
++                      dev->ext_vv_data->vbi_fops.release(file);
++      } else {
++              saa7146_video_uops.release(dev,file);
++      }
++
++      v4l2_fh_del(&fh->fh);
++      v4l2_fh_exit(&fh->fh);
++      module_put(dev->ext->module);
++      file->private_data = NULL;
++      kfree(fh);
++
++      mutex_unlock(vdev->lock);
++
++      return 0;
++}
++
++static int fops_mmap(struct file *file, struct vm_area_struct * vma)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct saa7146_fh *fh = file->private_data;
++      struct videobuf_queue *q;
++      int res;
++
++      switch (vdev->vfl_type) {
++      case VFL_TYPE_GRABBER: {
++              DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
++                     file, vma);
++              q = &fh->video_q;
++              break;
++              }
++      case VFL_TYPE_VBI: {
++              DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
++                     file, vma);
++              if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
++                      return -ENODEV;
++              q = &fh->vbi_q;
++              break;
++              }
++      default:
++              BUG();
++              return 0;
++      }
++
++      if (mutex_lock_interruptible(vdev->lock))
++              return -ERESTARTSYS;
++      res = videobuf_mmap_mapper(q, vma);
++      mutex_unlock(vdev->lock);
++      return res;
++}
++
++static unsigned int __fops_poll(struct file *file, struct poll_table_struct *wait)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct saa7146_fh *fh = file->private_data;
++      struct videobuf_buffer *buf = NULL;
++      struct videobuf_queue *q;
++      unsigned int res = v4l2_ctrl_poll(file, wait);
++
++      DEB_EE("file:%p, poll:%p\n", file, wait);
++
++      if (vdev->vfl_type == VFL_TYPE_VBI) {
++              if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
++                      return res | POLLOUT | POLLWRNORM;
++              if( 0 == fh->vbi_q.streaming )
++                      return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
++              q = &fh->vbi_q;
++      } else {
++              DEB_D("using video queue\n");
++              q = &fh->video_q;
++      }
++
++      if (!list_empty(&q->stream))
++              buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
++
++      if (!buf) {
++              DEB_D("buf == NULL!\n");
++              return res | POLLERR;
++      }
++
++      poll_wait(file, &buf->done, wait);
++      if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
++              DEB_D("poll succeeded!\n");
++              return res | POLLIN | POLLRDNORM;
++      }
++
++      DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
++      return res;
++}
++
++static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
++{
++      struct video_device *vdev = video_devdata(file);
++      unsigned int res;
++
++      mutex_lock(vdev->lock);
++      res = __fops_poll(file, wait);
++      mutex_unlock(vdev->lock);
++      return res;
++}
++
++static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct saa7146_fh *fh = file->private_data;
++      int ret;
++
++      switch (vdev->vfl_type) {
++      case VFL_TYPE_GRABBER:
++/*
++              DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
++                     file, data, (unsigned long)count);
++*/
++              return saa7146_video_uops.read(file,data,count,ppos);
++      case VFL_TYPE_VBI:
++/*
++              DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
++                     file, data, (unsigned long)count);
++*/
++              if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) {
++                      if (mutex_lock_interruptible(vdev->lock))
++                              return -ERESTARTSYS;
++                      ret = saa7146_vbi_uops.read(file, data, count, ppos);
++                      mutex_unlock(vdev->lock);
++                      return ret;
++              }
++              return -EINVAL;
++      default:
++              BUG();
++              return 0;
++      }
++}
++
++static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct saa7146_fh *fh = file->private_data;
++      int ret;
++
++      switch (vdev->vfl_type) {
++      case VFL_TYPE_GRABBER:
++              return -EINVAL;
++      case VFL_TYPE_VBI:
++              if (fh->dev->ext_vv_data->vbi_fops.write) {
++                      if (mutex_lock_interruptible(vdev->lock))
++                              return -ERESTARTSYS;
++                      ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
++                      mutex_unlock(vdev->lock);
++                      return ret;
++              }
++              return -EINVAL;
++      default:
++              BUG();
++              return -EINVAL;
++      }
++}
++
++static const struct v4l2_file_operations video_fops =
++{
++      .owner          = THIS_MODULE,
++      .open           = fops_open,
++      .release        = fops_release,
++      .read           = fops_read,
++      .write          = fops_write,
++      .poll           = fops_poll,
++      .mmap           = fops_mmap,
++      .unlocked_ioctl = video_ioctl2,
++};
++
++static void vv_callback(struct saa7146_dev *dev, unsigned long status)
++{
++      u32 isr = status;
++
++      DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
++
++      if (0 != (isr & (MASK_27))) {
++              DEB_INT("irq: RPS0 (0x%08x)\n", isr);
++              saa7146_video_uops.irq_done(dev,isr);
++      }
++
++      if (0 != (isr & (MASK_28))) {
++              u32 mc2 = saa7146_read(dev, MC2);
++              if( 0 != (mc2 & MASK_15)) {
++                      DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
++                      wake_up(&dev->vv_data->vbi_wq);
++                      saa7146_write(dev,MC2, MASK_31);
++                      return;
++              }
++              DEB_INT("irq: RPS1 (0x%08x)\n", isr);
++              saa7146_vbi_uops.irq_done(dev,isr);
++      }
++}
++
++static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
++      .s_ctrl = saa7146_s_ctrl,
++};
++
++int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
++{
++      struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
++      struct v4l2_pix_format *fmt;
++      struct v4l2_vbi_format *vbi;
++      struct saa7146_vv *vv;
++      int err;
++
++      err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
++      if (err)
++              return err;
++
++      v4l2_ctrl_handler_init(hdl, 6);
++      v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
++              V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
++      v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
++              V4L2_CID_CONTRAST, 0, 127, 1, 64);
++      v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
++              V4L2_CID_SATURATION, 0, 127, 1, 64);
++      v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
++              V4L2_CID_VFLIP, 0, 1, 1, 0);
++      v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
++              V4L2_CID_HFLIP, 0, 1, 1, 0);
++      if (hdl->error) {
++              err = hdl->error;
++              v4l2_ctrl_handler_free(hdl);
++              return err;
++      }
++      dev->v4l2_dev.ctrl_handler = hdl;
++
++      vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
++      if (vv == NULL) {
++              ERR("out of memory. aborting.\n");
++              v4l2_ctrl_handler_free(hdl);
++              return -ENOMEM;
++      }
++      ext_vv->vid_ops = saa7146_video_ioctl_ops;
++      ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
++      ext_vv->core_ops = &saa7146_video_ioctl_ops;
++
++      DEB_EE("dev:%p\n", dev);
++
++      /* set default values for video parts of the saa7146 */
++      saa7146_write(dev, BCS_CTRL, 0x80400040);
++
++      /* enable video-port pins */
++      saa7146_write(dev, MC1, (MASK_10 | MASK_26));
++
++      /* save per-device extension data (one extension can
++         handle different devices that might need different
++         configuration data) */
++      dev->ext_vv_data = ext_vv;
++
++      vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
++      if( NULL == vv->d_clipping.cpu_addr ) {
++              ERR("out of memory. aborting.\n");
++              kfree(vv);
++              v4l2_ctrl_handler_free(hdl);
++              return -1;
++      }
++      memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
++
++      saa7146_video_uops.init(dev,vv);
++      if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
++              saa7146_vbi_uops.init(dev,vv);
++
++      fmt = &vv->ov_fb.fmt;
++      fmt->width = vv->standard->h_max_out;
++      fmt->height = vv->standard->v_max_out;
++      fmt->pixelformat = V4L2_PIX_FMT_RGB565;
++      fmt->bytesperline = 2 * fmt->width;
++      fmt->sizeimage = fmt->bytesperline * fmt->height;
++      fmt->colorspace = V4L2_COLORSPACE_SRGB;
++
++      fmt = &vv->video_fmt;
++      fmt->width = 384;
++      fmt->height = 288;
++      fmt->pixelformat = V4L2_PIX_FMT_BGR24;
++      fmt->field = V4L2_FIELD_ANY;
++      fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
++      fmt->bytesperline = 3 * fmt->width;
++      fmt->sizeimage = fmt->bytesperline * fmt->height;
++
++      vbi = &vv->vbi_fmt;
++      vbi->sampling_rate      = 27000000;
++      vbi->offset             = 248; /* todo */
++      vbi->samples_per_line   = 720 * 2;
++      vbi->sample_format      = V4L2_PIX_FMT_GREY;
++
++      /* fixme: this only works for PAL */
++      vbi->start[0] = 5;
++      vbi->count[0] = 16;
++      vbi->start[1] = 312;
++      vbi->count[1] = 16;
++
++      init_timer(&vv->vbi_read_timeout);
++
++      vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
++      vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
++      dev->vv_data = vv;
++      dev->vv_callback = &vv_callback;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(saa7146_vv_init);
++
++int saa7146_vv_release(struct saa7146_dev* dev)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++
++      DEB_EE("dev:%p\n", dev);
++
++      v4l2_device_unregister(&dev->v4l2_dev);
++      pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
++      v4l2_ctrl_handler_free(&dev->ctrl_handler);
++      kfree(vv);
++      dev->vv_data = NULL;
++      dev->vv_callback = NULL;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(saa7146_vv_release);
++
++int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
++                          char *name, int type)
++{
++      struct video_device *vfd;
++      int err;
++      int i;
++
++      DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
++
++      // released by vfd->release
++      vfd = video_device_alloc();
++      if (vfd == NULL)
++              return -ENOMEM;
++
++      vfd->fops = &video_fops;
++      if (type == VFL_TYPE_GRABBER)
++              vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
++      else
++              vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
++      vfd->release = video_device_release;
++      vfd->lock = &dev->v4l2_lock;
++      vfd->v4l2_dev = &dev->v4l2_dev;
++      vfd->tvnorms = 0;
++      set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
++      for (i = 0; i < dev->ext_vv_data->num_stds; i++)
++              vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
++      strlcpy(vfd->name, name, sizeof(vfd->name));
++      video_set_drvdata(vfd, dev);
++
++      err = video_register_device(vfd, type, -1);
++      if (err < 0) {
++              ERR("cannot register v4l2 device. skipping.\n");
++              video_device_release(vfd);
++              return err;
++      }
++
++      pr_info("%s: registered device %s [v4l2]\n",
++              dev->name, video_device_node_name(vfd));
++
++      *vid = vfd;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(saa7146_register_device);
++
++int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
++{
++      DEB_EE("dev:%p\n", dev);
++
++      video_unregister_device(*vid);
++      *vid = NULL;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(saa7146_unregister_device);
++
++static int __init saa7146_vv_init_module(void)
++{
++      return 0;
++}
++
++
++static void __exit saa7146_vv_cleanup_module(void)
++{
++}
++
++module_init(saa7146_vv_init_module);
++module_exit(saa7146_vv_cleanup_module);
++
++MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
++MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
+new file mode 100644
+index 0000000..be746d1
+--- /dev/null
++++ b/drivers/media/common/saa7146/saa7146_hlp.c
+@@ -0,0 +1,1048 @@
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <media/saa7146_vv.h>
++
++static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
++{
++      /* clear out the necessary bits */
++      *clip_format &= 0x0000ffff;
++      /* set these bits new */
++      *clip_format |=  (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
++}
++
++static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl)
++{
++      *hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28);
++      *hps_ctrl |= (source << 30) | (sync << 28);
++}
++
++static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl)
++{
++      int hyo = 0, hxo = 0;
++
++      hyo = vv->standard->v_offset;
++      hxo = vv->standard->h_offset;
++
++      *hps_h_scale    &= ~(MASK_B0 | 0xf00);
++      *hps_h_scale    |= (hxo <<  0);
++
++      *hps_ctrl       &= ~(MASK_W0 | MASK_B2);
++      *hps_ctrl       |= (hyo << 12);
++}
++
++/* helper functions for the calculation of the horizontal- and vertical
++   scaling registers, clip-format-register etc ...
++   these functions take pointers to the (most-likely read-out
++   original-values) and manipulate them according to the requested
++   changes.
++*/
++
++/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */
++static struct {
++      u16 hps_coeff;
++      u16 weight_sum;
++} hps_h_coeff_tab [] = {
++      {0x00,   2}, {0x02,   4}, {0x00,   4}, {0x06,   8}, {0x02,   8},
++      {0x08,   8}, {0x00,   8}, {0x1E,  16}, {0x0E,   8}, {0x26,   8},
++      {0x06,   8}, {0x42,   8}, {0x02,   8}, {0x80,   8}, {0x00,   8},
++      {0xFE,  16}, {0xFE,   8}, {0x7E,   8}, {0x7E,   8}, {0x3E,   8},
++      {0x3E,   8}, {0x1E,   8}, {0x1E,   8}, {0x0E,   8}, {0x0E,   8},
++      {0x06,   8}, {0x06,   8}, {0x02,   8}, {0x02,   8}, {0x00,   8},
++      {0x00,   8}, {0xFE,  16}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
++      {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
++      {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
++      {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0x7E,   8},
++      {0x7E,   8}, {0x3E,   8}, {0x3E,   8}, {0x1E,   8}, {0x1E,   8},
++      {0x0E,   8}, {0x0E,   8}, {0x06,   8}, {0x06,   8}, {0x02,   8},
++      {0x02,   8}, {0x00,   8}, {0x00,   8}, {0xFE,  16}
++};
++
++/* table of attenuation values for horizontal scaling */
++static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
++
++/* calculate horizontal scale registers */
++static int calculate_h_scale_registers(struct saa7146_dev *dev,
++      int in_x, int out_x, int flip_lr,
++      u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale)
++{
++      /* horizontal prescaler */
++      u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;
++      /* horizontal scaler */
++      u32 xim = 0, xp = 0, xsci =0;
++      /* vertical scale & gain */
++      u32 pfuv = 0;
++
++      /* helper variables */
++      u32 h_atten = 0, i = 0;
++
++      if ( 0 == out_x ) {
++              return -EINVAL;
++      }
++
++      /* mask out vanity-bit */
++      *hps_ctrl &= ~MASK_29;
++
++      /* calculate prescale-(xspc)-value:     [n   .. 1/2) : 1
++                                              [1/2 .. 1/3) : 2
++                                              [1/3 .. 1/4) : 3
++                                              ...             */
++      if (in_x > out_x) {
++              xpsc = in_x / out_x;
++      }
++      else {
++              /* zooming */
++              xpsc = 1;
++      }
++
++      /* if flip_lr-bit is set, number of pixels after
++         horizontal prescaling must be < 384 */
++      if ( 0 != flip_lr ) {
++
++              /* set vanity bit */
++              *hps_ctrl |= MASK_29;
++
++              while (in_x / xpsc >= 384 )
++                      xpsc++;
++      }
++      /* if zooming is wanted, number of pixels after
++         horizontal prescaling must be < 768 */
++      else {
++              while ( in_x / xpsc >= 768 )
++                      xpsc++;
++      }
++
++      /* maximum prescale is 64 (p.69) */
++      if ( xpsc > 64 )
++              xpsc = 64;
++
++      /* keep xacm clear*/
++      xacm = 0;
++
++      /* set horizontal filter parameters (CXY = CXUV) */
++      cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff;
++      cxuv = cxy;
++
++      /* calculate and set horizontal fine scale (xsci) */
++
++      /* bypass the horizontal scaler ? */
++      if ( (in_x == out_x) && ( 1 == xpsc ) )
++              xsci = 0x400;
++      else
++              xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc;
++
++      /* set start phase for horizontal fine scale (xp) to 0 */
++      xp = 0;
++
++      /* set xim, if we bypass the horizontal scaler */
++      if ( 0x400 == xsci )
++              xim = 1;
++      else
++              xim = 0;
++
++      /* if the prescaler is bypassed, enable horizontal
++         accumulation mode (xacm) and clear dcgx */
++      if( 1 == xpsc ) {
++              xacm = 1;
++              dcgx = 0;
++      } else {
++              xacm = 0;
++              /* get best match in the table of attenuations
++                 for horizontal scaling */
++              h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum;
++
++              for (i = 0; h_attenuation[i] != 0; i++) {
++                      if (h_attenuation[i] >= h_atten)
++                              break;
++              }
++
++              dcgx = i;
++      }
++
++      /* the horizontal scaling increment controls the UV filter
++         to reduce the bandwidth to improve the display quality,
++         so set it ... */
++      if ( xsci == 0x400)
++              pfuv = 0x00;
++      else if ( xsci < 0x600)
++              pfuv = 0x01;
++      else if ( xsci < 0x680)
++              pfuv = 0x11;
++      else if ( xsci < 0x700)
++              pfuv = 0x22;
++      else
++              pfuv = 0x33;
++
++
++      *hps_v_gain  &= MASK_W0|MASK_B2;
++      *hps_v_gain  |= (pfuv << 24);
++
++      *hps_h_scale    &= ~(MASK_W1 | 0xf000);
++      *hps_h_scale    |= (xim << 31) | (xp << 24) | (xsci << 12);
++
++      *hps_h_prescale |= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0);
++
++      return 0;
++}
++
++static struct {
++      u16 hps_coeff;
++      u16 weight_sum;
++} hps_v_coeff_tab [] = {
++ {0x0100,   2},  {0x0102,   4},  {0x0300,   4},  {0x0106,   8},  {0x0502,   8},
++ {0x0708,   8},  {0x0F00,   8},  {0x011E,  16},  {0x110E,  16},  {0x1926,  16},
++ {0x3906,  16},  {0x3D42,  16},  {0x7D02,  16},  {0x7F80,  16},  {0xFF00,  16},
++ {0x01FE,  32},  {0x01FE,  32},  {0x817E,  32},  {0x817E,  32},  {0xC13E,  32},
++ {0xC13E,  32},  {0xE11E,  32},  {0xE11E,  32},  {0xF10E,  32},  {0xF10E,  32},
++ {0xF906,  32},  {0xF906,  32},  {0xFD02,  32},  {0xFD02,  32},  {0xFF00,  32},
++ {0xFF00,  32},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
++ {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
++ {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
++ {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x817E,  64},
++ {0x817E,  64},  {0xC13E,  64},  {0xC13E,  64},  {0xE11E,  64},  {0xE11E,  64},
++ {0xF10E,  64},  {0xF10E,  64},  {0xF906,  64},  {0xF906,  64},  {0xFD02,  64},
++ {0xFD02,  64},  {0xFF00,  64},  {0xFF00,  64},  {0x01FE, 128}
++};
++
++/* table of attenuation values for vertical scaling */
++static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
++
++/* calculate vertical scale registers */
++static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field,
++      int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain)
++{
++      int lpi = 0;
++
++      /* vertical scaling */
++      u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0;
++      /* vertical scale & gain */
++      u32 dcgy = 0, cya_cyb = 0;
++
++      /* helper variables */
++      u32 v_atten = 0, i = 0;
++
++      /* error, if vertical zooming */
++      if ( in_y < out_y ) {
++              return -EINVAL;
++      }
++
++      /* linear phase interpolation may be used
++         if scaling is between 1 and 1/2 (both fields used)
++         or scaling is between 1/2 and 1/4 (if only one field is used) */
++
++      if (V4L2_FIELD_HAS_BOTH(field)) {
++              if( 2*out_y >= in_y) {
++                      lpi = 1;
++              }
++      } else if (field == V4L2_FIELD_TOP
++              || field == V4L2_FIELD_ALTERNATE
++              || field == V4L2_FIELD_BOTTOM) {
++              if( 4*out_y >= in_y ) {
++                      lpi = 1;
++              }
++              out_y *= 2;
++      }
++      if( 0 != lpi ) {
++
++              yacm = 0;
++              yacl = 0;
++              cya_cyb = 0x00ff;
++
++              /* calculate scaling increment */
++              if ( in_y > out_y )
++                      ysci = ((1024 * in_y) / (out_y + 1)) - 1024;
++              else
++                      ysci = 0;
++
++              dcgy = 0;
++
++              /* calculate ype and ypo */
++              ype = ysci / 16;
++              ypo = ype + (ysci / 64);
++
++      } else {
++              yacm = 1;
++
++              /* calculate scaling increment */
++              ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10;
++
++              /* calculate ype and ypo */
++              ypo = ype = ((ysci + 15) / 16);
++
++              /* the sequence length interval (yacl) has to be set according
++                 to the prescale value, e.g.  [n   .. 1/2) : 0
++                                              [1/2 .. 1/3) : 1
++                                              [1/3 .. 1/4) : 2
++                                              ... */
++              if ( ysci < 512) {
++                      yacl = 0;
++              } else {
++                      yacl = ( ysci / (1024 - ysci) );
++              }
++
++              /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
++              cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff;
++
++              /* get best match in the table of attenuations for vertical scaling */
++              v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum;
++
++              for (i = 0; v_attenuation[i] != 0; i++) {
++                      if (v_attenuation[i] >= v_atten)
++                              break;
++              }
++
++              dcgy = i;
++      }
++
++      /* ypo and ype swapped in spec ? */
++      *hps_v_scale    |= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1);
++
++      *hps_v_gain     &= ~(MASK_W0|MASK_B2);
++      *hps_v_gain     |= (dcgy << 16) | (cya_cyb << 0);
++
++      return 0;
++}
++
++/* simple bubble-sort algorithm with duplicate elimination */
++static int sort_and_eliminate(u32* values, int* count)
++{
++      int low = 0, high = 0, top = 0, temp = 0;
++      int cur = 0, next = 0;
++
++      /* sanity checks */
++      if( (0 > *count) || (NULL == values) ) {
++              return -EINVAL;
++      }
++
++      /* bubble sort the first @count items of the array @values */
++      for( top = *count; top > 0; top--) {
++              for( low = 0, high = 1; high < top; low++, high++) {
++                      if( values[low] > values[high] ) {
++                              temp = values[low];
++                              values[low] = values[high];
++                              values[high] = temp;
++                      }
++              }
++      }
++
++      /* remove duplicate items */
++      for( cur = 0, next = 1; next < *count; next++) {
++              if( values[cur] != values[next])
++                      values[++cur] = values[next];
++      }
++
++      *count = cur + 1;
++
++      return 0;
++}
++
++static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh,
++      struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      __le32 *clipping = vv->d_clipping.cpu_addr;
++
++      int width = vv->ov.win.w.width;
++      int height =  vv->ov.win.w.height;
++      int clipcount = vv->ov.nclips;
++
++      u32 line_list[32];
++      u32 pixel_list[32];
++      int numdwords = 0;
++
++      int i = 0, j = 0;
++      int cnt_line = 0, cnt_pixel = 0;
++
++      int x[32], y[32], w[32], h[32];
++
++      /* clear out memory */
++      memset(&line_list[0],  0x00, sizeof(u32)*32);
++      memset(&pixel_list[0], 0x00, sizeof(u32)*32);
++      memset(clipping,  0x00, SAA7146_CLIPPING_MEM);
++
++      /* fill the line and pixel-lists */
++      for(i = 0; i < clipcount; i++) {
++              int l = 0, r = 0, t = 0, b = 0;
++
++              x[i] = vv->ov.clips[i].c.left;
++              y[i] = vv->ov.clips[i].c.top;
++              w[i] = vv->ov.clips[i].c.width;
++              h[i] = vv->ov.clips[i].c.height;
++
++              if( w[i] < 0) {
++                      x[i] += w[i]; w[i] = -w[i];
++              }
++              if( h[i] < 0) {
++                      y[i] += h[i]; h[i] = -h[i];
++              }
++              if( x[i] < 0) {
++                      w[i] += x[i]; x[i] = 0;
++              }
++              if( y[i] < 0) {
++                      h[i] += y[i]; y[i] = 0;
++              }
++              if( 0 != vv->vflip ) {
++                      y[i] = height - y[i] - h[i];
++              }
++
++              l = x[i];
++              r = x[i]+w[i];
++              t = y[i];
++              b = y[i]+h[i];
++
++              /* insert left/right coordinates */
++              pixel_list[ 2*i   ] = min_t(int, l, width);
++              pixel_list[(2*i)+1] = min_t(int, r, width);
++              /* insert top/bottom coordinates */
++              line_list[ 2*i   ] = min_t(int, t, height);
++              line_list[(2*i)+1] = min_t(int, b, height);
++      }
++
++      /* sort and eliminate lists */
++      cnt_line = cnt_pixel = 2*clipcount;
++      sort_and_eliminate( &pixel_list[0], &cnt_pixel );
++      sort_and_eliminate( &line_list[0], &cnt_line );
++
++      /* calculate the number of used u32s */
++      numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2;
++      numdwords = max_t(int, 4, numdwords);
++      numdwords = min_t(int, 64, numdwords);
++
++      /* fill up cliptable */
++      for(i = 0; i < cnt_pixel; i++) {
++              clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16);
++      }
++      for(i = 0; i < cnt_line; i++) {
++              clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16);
++      }
++
++      /* fill up cliptable with the display infos */
++      for(j = 0; j < clipcount; j++) {
++
++              for(i = 0; i < cnt_pixel; i++) {
++
++                      if( x[j] < 0)
++                              x[j] = 0;
++
++                      if( pixel_list[i] < (x[j] + w[j])) {
++
++                              if ( pixel_list[i] >= x[j] ) {
++                                      clipping[2*i] |= cpu_to_le32(1 << j);
++                              }
++                      }
++              }
++              for(i = 0; i < cnt_line; i++) {
++
++                      if( y[j] < 0)
++                              y[j] = 0;
++
++                      if( line_list[i] < (y[j] + h[j]) ) {
++
++                              if( line_list[i] >= y[j] ) {
++                                      clipping[(2*i)+1] |= cpu_to_le32(1 << j);
++                              }
++                      }
++              }
++      }
++
++      /* adjust arbitration control register */
++      *arbtr_ctrl &= 0xffff00ff;
++      *arbtr_ctrl |= 0x00001c00;
++
++      vdma2->base_even        = vv->d_clipping.dma_handle;
++      vdma2->base_odd         = vv->d_clipping.dma_handle;
++      vdma2->prot_addr        = vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords));
++      vdma2->base_page        = 0x04;
++      vdma2->pitch            = 0x00;
++      vdma2->num_line_byte    = (0 << 16 | (sizeof(u32))*(numdwords-1) );
++
++      /* set clipping-mode. this depends on the field(s) used */
++      *clip_format &= 0xfffffff7;
++      if (V4L2_FIELD_HAS_BOTH(field)) {
++              *clip_format |= 0x00000008;
++      } else {
++              *clip_format |= 0x00000000;
++      }
++}
++
++/* disable clipping */
++static void saa7146_disable_clipping(struct saa7146_dev *dev)
++{
++      u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
++
++      /* mask out relevant bits (=lower word)*/
++      clip_format &= MASK_W1;
++
++      /* upload clipping-registers*/
++      saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
++      saa7146_write(dev, MC2, (MASK_05 | MASK_21));
++
++      /* disable video dma2 */
++      saa7146_write(dev, MC1, MASK_21);
++}
++
++static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      enum v4l2_field field = vv->ov.win.field;
++      struct  saa7146_video_dma vdma2;
++      u32 clip_format;
++      u32 arbtr_ctrl;
++
++      /* check clipcount, disable clipping if clipcount == 0*/
++      if (vv->ov.nclips == 0) {
++              saa7146_disable_clipping(dev);
++              return;
++      }
++
++      clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
++      arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
++
++      calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field);
++
++      /* set clipping format */
++      clip_format &= 0xffff0008;
++      clip_format |= (SAA7146_CLIPPING_RECT << 4);
++
++      /* prepare video dma2 */
++      saa7146_write(dev, BASE_EVEN2,          vdma2.base_even);
++      saa7146_write(dev, BASE_ODD2,           vdma2.base_odd);
++      saa7146_write(dev, PROT_ADDR2,          vdma2.prot_addr);
++      saa7146_write(dev, BASE_PAGE2,          vdma2.base_page);
++      saa7146_write(dev, PITCH2,              vdma2.pitch);
++      saa7146_write(dev, NUM_LINE_BYTE2,      vdma2.num_line_byte);
++
++      /* prepare the rest */
++      saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
++      saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
++
++      /* upload clip_control-register, clipping-registers, enable video dma2 */
++      saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19));
++      saa7146_write(dev, MC1, (MASK_05 | MASK_21));
++}
++
++static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++
++      int source = vv->current_hps_source;
++      int sync = vv->current_hps_sync;
++
++      u32 hps_v_scale = 0, hps_v_gain  = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;
++
++      /* set vertical scale */
++      hps_v_scale = 0; /* all bits get set by the function-call */
++      hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/
++      calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);
++
++      /* set horizontal scale */
++      hps_ctrl        = 0;
++      hps_h_prescale  = 0; /* all bits get set in the function */
++      hps_h_scale     = 0;
++      calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
++
++      /* set hyo and hxo */
++      calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);
++      calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl);
++
++      /* write out new register contents */
++      saa7146_write(dev, HPS_V_SCALE, hps_v_scale);
++      saa7146_write(dev, HPS_V_GAIN,  hps_v_gain);
++      saa7146_write(dev, HPS_CTRL,    hps_ctrl);
++      saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale);
++      saa7146_write(dev, HPS_H_SCALE, hps_h_scale);
++
++      /* upload shadow-ram registers */
++      saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
++}
++
++/* calculate the new memory offsets for a desired position */
++static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
++
++      int b_depth = vv->ov_fmt->depth;
++      int b_bpl = vv->ov_fb.fmt.bytesperline;
++      /* The unsigned long cast is to remove a 64-bit compile warning since
++         it looks like a 64-bit address is cast to a 32-bit value, even
++         though the base pointer is really a 32-bit physical address that
++         goes into a 32-bit DMA register.
++         FIXME: might not work on some 64-bit platforms, but see the FIXME
++         in struct v4l2_framebuffer (videodev2.h) for that.
++       */
++      u32 base = (u32)(unsigned long)vv->ov_fb.base;
++
++      struct  saa7146_video_dma vdma1;
++
++      /* calculate memory offsets for picture, look if we shall top-down-flip */
++      vdma1.pitch     = 2*b_bpl;
++      if ( 0 == vv->vflip ) {
++              vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
++              vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
++              vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
++      }
++      else {
++              vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
++              vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
++              vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
++      }
++
++      if (V4L2_FIELD_HAS_BOTH(field)) {
++      } else if (field == V4L2_FIELD_ALTERNATE) {
++              /* fixme */
++              vdma1.base_odd = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++      } else if (field == V4L2_FIELD_TOP) {
++              vdma1.base_odd = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++      } else if (field == V4L2_FIELD_BOTTOM) {
++              vdma1.base_odd = vdma1.base_even;
++              vdma1.base_even = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++      }
++
++      if ( 0 != vv->vflip ) {
++              vdma1.pitch *= -1;
++      }
++
++      vdma1.base_page = sfmt->swap;
++      vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
++
++      saa7146_write_out_dma(dev, 1, &vdma1);
++}
++
++static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette)
++{
++      u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
++
++      /* call helper function */
++      calculate_output_format_register(dev,palette,&clip_format);
++
++      /* update the hps registers */
++      saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format);
++      saa7146_write(dev, MC2, (MASK_05 | MASK_21));
++}
++
++/* select input-source */
++void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      u32 hps_ctrl = 0;
++
++      /* read old state */
++      hps_ctrl = saa7146_read(dev, HPS_CTRL);
++
++      hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 );
++      hps_ctrl |= (source << 30) | (sync << 28);
++
++      /* write back & upload register */
++      saa7146_write(dev, HPS_CTRL, hps_ctrl);
++      saa7146_write(dev, MC2, (MASK_05 | MASK_21));
++
++      vv->current_hps_source = source;
++      vv->current_hps_sync = sync;
++}
++EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
++
++int saa7146_enable_overlay(struct saa7146_fh *fh)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
++      saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
++      saa7146_set_output_format(dev, vv->ov_fmt->trans);
++      saa7146_set_clipping_rect(fh);
++
++      /* enable video dma1 */
++      saa7146_write(dev, MC1, (MASK_06 | MASK_22));
++      return 0;
++}
++
++void saa7146_disable_overlay(struct saa7146_fh *fh)
++{
++      struct saa7146_dev *dev = fh->dev;
++
++      /* disable clipping + video dma1 */
++      saa7146_disable_clipping(dev);
++      saa7146_write(dev, MC1, MASK_22);
++}
++
++void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma)
++{
++      int where = 0;
++
++      if( which < 1 || which > 3) {
++              return;
++      }
++
++      /* calculate starting address */
++      where  = (which-1)*0x18;
++
++      saa7146_write(dev, where,       vdma->base_odd);
++      saa7146_write(dev, where+0x04,  vdma->base_even);
++      saa7146_write(dev, where+0x08,  vdma->prot_addr);
++      saa7146_write(dev, where+0x0c,  vdma->pitch);
++      saa7146_write(dev, where+0x10,  vdma->base_page);
++      saa7146_write(dev, where+0x14,  vdma->num_line_byte);
++
++      /* upload */
++      saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1)));
++/*
++      printk("vdma%d.base_even:     0x%08x\n", which,vdma->base_even);
++      printk("vdma%d.base_odd:      0x%08x\n", which,vdma->base_odd);
++      printk("vdma%d.prot_addr:     0x%08x\n", which,vdma->prot_addr);
++      printk("vdma%d.base_page:     0x%08x\n", which,vdma->base_page);
++      printk("vdma%d.pitch:         0x%08x\n", which,vdma->pitch);
++      printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte);
++*/
++}
++
++static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_video_dma vdma1;
++
++      struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
++
++      int width = buf->fmt->width;
++      int height = buf->fmt->height;
++      int bytesperline = buf->fmt->bytesperline;
++      enum v4l2_field field = buf->fmt->field;
++
++      int depth = sfmt->depth;
++
++      DEB_CAP("[size=%dx%d,fields=%s]\n",
++              width, height, v4l2_field_names[field]);
++
++      if( bytesperline != 0) {
++              vdma1.pitch = bytesperline*2;
++      } else {
++              vdma1.pitch = (width*depth*2)/8;
++      }
++      vdma1.num_line_byte     = ((vv->standard->v_field<<16) + vv->standard->h_pixels);
++      vdma1.base_page         = buf->pt[0].dma | ME1 | sfmt->swap;
++
++      if( 0 != vv->vflip ) {
++              vdma1.prot_addr = buf->pt[0].offset;
++              vdma1.base_even = buf->pt[0].offset+(vdma1.pitch/2)*height;
++              vdma1.base_odd  = vdma1.base_even - (vdma1.pitch/2);
++      } else {
++              vdma1.base_even = buf->pt[0].offset;
++              vdma1.base_odd  = vdma1.base_even + (vdma1.pitch/2);
++              vdma1.prot_addr = buf->pt[0].offset+(vdma1.pitch/2)*height;
++      }
++
++      if (V4L2_FIELD_HAS_BOTH(field)) {
++      } else if (field == V4L2_FIELD_ALTERNATE) {
++              /* fixme */
++              if ( vv->last_field == V4L2_FIELD_TOP ) {
++                      vdma1.base_odd  = vdma1.prot_addr;
++                      vdma1.pitch /= 2;
++              } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
++                      vdma1.base_odd  = vdma1.base_even;
++                      vdma1.base_even = vdma1.prot_addr;
++                      vdma1.pitch /= 2;
++              }
++      } else if (field == V4L2_FIELD_TOP) {
++              vdma1.base_odd  = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++      } else if (field == V4L2_FIELD_BOTTOM) {
++              vdma1.base_odd  = vdma1.base_even;
++              vdma1.base_even = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++      }
++
++      if( 0 != vv->vflip ) {
++              vdma1.pitch *= -1;
++      }
++
++      saa7146_write_out_dma(dev, 1, &vdma1);
++      return 0;
++}
++
++static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
++{
++      int height = buf->fmt->height;
++      int width = buf->fmt->width;
++
++      vdma2->pitch    = width;
++      vdma3->pitch    = width;
++
++      /* fixme: look at bytesperline! */
++
++      if( 0 != vv->vflip ) {
++              vdma2->prot_addr        = buf->pt[1].offset;
++              vdma2->base_even        = ((vdma2->pitch/2)*height)+buf->pt[1].offset;
++              vdma2->base_odd         = vdma2->base_even - (vdma2->pitch/2);
++
++              vdma3->prot_addr        = buf->pt[2].offset;
++              vdma3->base_even        = ((vdma3->pitch/2)*height)+buf->pt[2].offset;
++              vdma3->base_odd         = vdma3->base_even - (vdma3->pitch/2);
++      } else {
++              vdma3->base_even        = buf->pt[2].offset;
++              vdma3->base_odd         = vdma3->base_even + (vdma3->pitch/2);
++              vdma3->prot_addr        = (vdma3->pitch/2)*height+buf->pt[2].offset;
++
++              vdma2->base_even        = buf->pt[1].offset;
++              vdma2->base_odd         = vdma2->base_even + (vdma2->pitch/2);
++              vdma2->prot_addr        = (vdma2->pitch/2)*height+buf->pt[1].offset;
++      }
++
++      return 0;
++}
++
++static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
++{
++      int height = buf->fmt->height;
++      int width = buf->fmt->width;
++
++      vdma2->pitch    = width/2;
++      vdma3->pitch    = width/2;
++
++      if( 0 != vv->vflip ) {
++              vdma2->prot_addr        = buf->pt[2].offset;
++              vdma2->base_even        = ((vdma2->pitch/2)*height)+buf->pt[2].offset;
++              vdma2->base_odd         = vdma2->base_even - (vdma2->pitch/2);
++
++              vdma3->prot_addr        = buf->pt[1].offset;
++              vdma3->base_even        = ((vdma3->pitch/2)*height)+buf->pt[1].offset;
++              vdma3->base_odd         = vdma3->base_even - (vdma3->pitch/2);
++
++      } else {
++              vdma3->base_even        = buf->pt[2].offset;
++              vdma3->base_odd         = vdma3->base_even + (vdma3->pitch);
++              vdma3->prot_addr        = (vdma3->pitch/2)*height+buf->pt[2].offset;
++
++              vdma2->base_even        = buf->pt[1].offset;
++              vdma2->base_odd         = vdma2->base_even + (vdma2->pitch);
++              vdma2->prot_addr        = (vdma2->pitch/2)*height+buf->pt[1].offset;
++      }
++      return 0;
++}
++
++static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_video_dma vdma1;
++      struct saa7146_video_dma vdma2;
++      struct saa7146_video_dma vdma3;
++
++      struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
++
++      int width = buf->fmt->width;
++      int height = buf->fmt->height;
++      enum v4l2_field field = buf->fmt->field;
++
++      BUG_ON(0 == buf->pt[0].dma);
++      BUG_ON(0 == buf->pt[1].dma);
++      BUG_ON(0 == buf->pt[2].dma);
++
++      DEB_CAP("[size=%dx%d,fields=%s]\n",
++              width, height, v4l2_field_names[field]);
++
++      /* fixme: look at bytesperline! */
++
++      /* fixme: what happens for user space buffers here?. The offsets are
++         most likely wrong, this version here only works for page-aligned
++         buffers, modifications to the pagetable-functions are necessary...*/
++
++      vdma1.pitch             = width*2;
++      vdma1.num_line_byte     = ((vv->standard->v_field<<16) + vv->standard->h_pixels);
++      vdma1.base_page         = buf->pt[0].dma | ME1;
++
++      if( 0 != vv->vflip ) {
++              vdma1.prot_addr = buf->pt[0].offset;
++              vdma1.base_even = ((vdma1.pitch/2)*height)+buf->pt[0].offset;
++              vdma1.base_odd  = vdma1.base_even - (vdma1.pitch/2);
++      } else {
++              vdma1.base_even = buf->pt[0].offset;
++              vdma1.base_odd  = vdma1.base_even + (vdma1.pitch/2);
++              vdma1.prot_addr = (vdma1.pitch/2)*height+buf->pt[0].offset;
++      }
++
++      vdma2.num_line_byte     = 0; /* unused */
++      vdma2.base_page         = buf->pt[1].dma | ME1;
++
++      vdma3.num_line_byte     = 0; /* unused */
++      vdma3.base_page         = buf->pt[2].dma | ME1;
++
++      switch( sfmt->depth ) {
++              case 12: {
++                      calc_planar_420(vv,buf,&vdma2,&vdma3);
++                      break;
++              }
++              case 16: {
++                      calc_planar_422(vv,buf,&vdma2,&vdma3);
++                      break;
++              }
++              default: {
++                      return -1;
++              }
++      }
++
++      if (V4L2_FIELD_HAS_BOTH(field)) {
++      } else if (field == V4L2_FIELD_ALTERNATE) {
++              /* fixme */
++              vdma1.base_odd  = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++              vdma2.base_odd  = vdma2.prot_addr;
++              vdma2.pitch /= 2;
++              vdma3.base_odd  = vdma3.prot_addr;
++              vdma3.pitch /= 2;
++      } else if (field == V4L2_FIELD_TOP) {
++              vdma1.base_odd  = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++              vdma2.base_odd  = vdma2.prot_addr;
++              vdma2.pitch /= 2;
++              vdma3.base_odd  = vdma3.prot_addr;
++              vdma3.pitch /= 2;
++      } else if (field == V4L2_FIELD_BOTTOM) {
++              vdma1.base_odd  = vdma1.base_even;
++              vdma1.base_even = vdma1.prot_addr;
++              vdma1.pitch /= 2;
++              vdma2.base_odd  = vdma2.base_even;
++              vdma2.base_even = vdma2.prot_addr;
++              vdma2.pitch /= 2;
++              vdma3.base_odd  = vdma3.base_even;
++              vdma3.base_even = vdma3.prot_addr;
++              vdma3.pitch /= 2;
++      }
++
++      if( 0 != vv->vflip ) {
++              vdma1.pitch *= -1;
++              vdma2.pitch *= -1;
++              vdma3.pitch *= -1;
++      }
++
++      saa7146_write_out_dma(dev, 1, &vdma1);
++      if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) {
++              saa7146_write_out_dma(dev, 3, &vdma2);
++              saa7146_write_out_dma(dev, 2, &vdma3);
++      } else {
++              saa7146_write_out_dma(dev, 2, &vdma2);
++              saa7146_write_out_dma(dev, 3, &vdma3);
++      }
++      return 0;
++}
++
++static void program_capture_engine(struct saa7146_dev *dev, int planar)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      int count = 0;
++
++      unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
++      unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
++
++      /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
++      WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);
++      WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
++
++      /* set rps register 0 */
++      WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4));
++      WRITE_RPS0(MASK_27 | MASK_11);
++
++      /* turn on video-dma1 */
++      WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
++      WRITE_RPS0(MASK_06 | MASK_22);                  /* => mask */
++      WRITE_RPS0(MASK_06 | MASK_22);                  /* => values */
++      if( 0 != planar ) {
++              /* turn on video-dma2 */
++              WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
++              WRITE_RPS0(MASK_05 | MASK_21);                  /* => mask */
++              WRITE_RPS0(MASK_05 | MASK_21);                  /* => values */
++
++              /* turn on video-dma3 */
++              WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
++              WRITE_RPS0(MASK_04 | MASK_20);                  /* => mask */
++              WRITE_RPS0(MASK_04 | MASK_20);                  /* => values */
++      }
++
++      /* wait for o_fid_a/b / e_fid_a/b toggle */
++      if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
++              WRITE_RPS0(CMD_PAUSE | o_wait);
++              WRITE_RPS0(CMD_PAUSE | e_wait);
++      } else if ( vv->last_field == V4L2_FIELD_TOP ) {
++              WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
++              WRITE_RPS0(CMD_PAUSE | o_wait);
++      } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
++              WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
++              WRITE_RPS0(CMD_PAUSE | e_wait);
++      }
++
++      /* turn off video-dma1 */
++      WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
++      WRITE_RPS0(MASK_22 | MASK_06);                  /* => mask */
++      WRITE_RPS0(MASK_22);                            /* => values */
++      if( 0 != planar ) {
++              /* turn off video-dma2 */
++              WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
++              WRITE_RPS0(MASK_05 | MASK_21);                  /* => mask */
++              WRITE_RPS0(MASK_21);                            /* => values */
++
++              /* turn off video-dma3 */
++              WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
++              WRITE_RPS0(MASK_04 | MASK_20);                  /* => mask */
++              WRITE_RPS0(MASK_20);                            /* => values */
++      }
++
++      /* generate interrupt */
++      WRITE_RPS0(CMD_INTERRUPT);
++
++      /* stop */
++      WRITE_RPS0(CMD_STOP);
++}
++
++void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
++{
++      struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
++      struct saa7146_vv *vv = dev->vv_data;
++      u32 vdma1_prot_addr;
++
++      DEB_CAP("buf:%p, next:%p\n", buf, next);
++
++      vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
++      if( 0 == vdma1_prot_addr ) {
++              /* clear out beginning of streaming bit (rps register 0)*/
++              DEB_CAP("forcing sync to new frame\n");
++              saa7146_write(dev, MC2, MASK_27 );
++      }
++
++      saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);
++      saa7146_set_output_format(dev, sfmt->trans);
++      saa7146_disable_clipping(dev);
++
++      if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
++      } else if ( vv->last_field == V4L2_FIELD_TOP ) {
++              vv->last_field = V4L2_FIELD_BOTTOM;
++      } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
++              vv->last_field = V4L2_FIELD_TOP;
++      }
++
++      if( 0 != IS_PLANAR(sfmt->trans)) {
++              calculate_video_dma_grab_planar(dev, buf);
++              program_capture_engine(dev,1);
++      } else {
++              calculate_video_dma_grab_packed(dev, buf);
++              program_capture_engine(dev,0);
++      }
++
++/*
++      printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
++      printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
++      printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
++      printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
++      printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));
++      printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
++      printk("vdma%d => vptr      : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1));
++*/
++
++      /* write the address of the rps-program */
++      saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
++
++      /* turn on rps */
++      saa7146_write(dev, MC1, (MASK_12 | MASK_28));
++}
+diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c
+new file mode 100644
+index 0000000..2202719
+--- /dev/null
++++ b/drivers/media/common/saa7146/saa7146_i2c.c
+@@ -0,0 +1,423 @@
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <media/saa7146_vv.h>
++
++static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
++{
++      /* DEB_I2C("'%s'\n", adapter->name); */
++
++      return    I2C_FUNC_I2C
++              | I2C_FUNC_SMBUS_QUICK
++              | I2C_FUNC_SMBUS_READ_BYTE      | I2C_FUNC_SMBUS_WRITE_BYTE
++              | I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
++}
++
++/* this function returns the status-register of our i2c-device */
++static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
++{
++      u32 iicsta = saa7146_read(dev, I2C_STATUS);
++      /* DEB_I2C("status: 0x%08x\n", iicsta); */
++      return iicsta;
++}
++
++/* this function runs through the i2c-messages and prepares the data to be
++   sent through the saa7146. have a look at the specifications p. 122 ff
++   to understand this. it returns the number of u32s to send, or -1
++   in case of an error. */
++static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
++{
++      int h1, h2;
++      int i, j, addr;
++      int mem = 0, op_count = 0;
++
++      /* first determine size of needed memory */
++      for(i = 0; i < num; i++) {
++              mem += m[i].len + 1;
++      }
++
++      /* worst case: we need one u32 for three bytes to be send
++         plus one extra byte to address the device */
++      mem = 1 + ((mem-1) / 3);
++
++      /* we assume that op points to a memory of at least
++       * SAA7146_I2C_MEM bytes size. if we exceed this limit...
++       */
++      if ((4 * mem) > SAA7146_I2C_MEM) {
++              /* DEB_I2C("cannot prepare i2c-message\n"); */
++              return -ENOMEM;
++      }
++
++      /* be careful: clear out the i2c-mem first */
++      memset(op,0,sizeof(__le32)*mem);
++
++      /* loop through all messages */
++      for(i = 0; i < num; i++) {
++
++              /* insert the address of the i2c-slave.
++                 note: we get 7 bit i2c-addresses,
++                 so we have to perform a translation */
++              addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
++              h1 = op_count/3; h2 = op_count%3;
++              op[h1] |= cpu_to_le32(      (u8)addr << ((3-h2)*8));
++              op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
++              op_count++;
++
++              /* loop through all bytes of message i */
++              for(j = 0; j < m[i].len; j++) {
++                      /* insert the data bytes */
++                      h1 = op_count/3; h2 = op_count%3;
++                      op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
++                      op[h1] |= cpu_to_le32(       SAA7146_I2C_CONT << ((3-h2)*2));
++                      op_count++;
++              }
++
++      }
++
++      /* have a look at the last byte inserted:
++        if it was: ...CONT change it to ...STOP */
++      h1 = (op_count-1)/3; h2 = (op_count-1)%3;
++      if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
++              op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
++              op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
++      }
++
++      /* return the number of u32s to send */
++      return mem;
++}
++
++/* this functions loops through all i2c-messages. normally, it should determine
++   which bytes were read through the adapter and write them back to the corresponding
++   i2c-message. but instead, we simply write back all bytes.
++   fixme: this could be improved. */
++static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
++{
++      int i, j;
++      int op_count = 0;
++
++      /* loop through all messages */
++      for(i = 0; i < num; i++) {
++
++              op_count++;
++
++              /* loop through all bytes of message i */
++              for(j = 0; j < m[i].len; j++) {
++                      /* write back all bytes that could have been read */
++                      m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
++                      op_count++;
++              }
++      }
++
++      return 0;
++}
++
++/* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */
++static int saa7146_i2c_reset(struct saa7146_dev *dev)
++{
++      /* get current status */
++      u32 status = saa7146_i2c_status(dev);
++
++      /* clear registers for sure */
++      saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
++      saa7146_write(dev, I2C_TRANSFER, 0);
++
++      /* check if any operation is still in progress */
++      if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
++
++              /* yes, kill ongoing operation */
++              DEB_I2C("busy_state detected\n");
++
++              /* set "ABORT-OPERATION"-bit (bit 7)*/
++              saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
++              saa7146_write(dev, MC2, (MASK_00 | MASK_16));
++              msleep(SAA7146_I2C_DELAY);
++
++              /* clear all error-bits pending; this is needed because p.123, note 1 */
++              saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
++              saa7146_write(dev, MC2, (MASK_00 | MASK_16));
++              msleep(SAA7146_I2C_DELAY);
++      }
++
++      /* check if any error is (still) present. (this can be necessary because p.123, note 1) */
++      status = saa7146_i2c_status(dev);
++
++      if ( dev->i2c_bitrate != status ) {
++
++              DEB_I2C("error_state detected. status:0x%08x\n", status);
++
++              /* Repeat the abort operation. This seems to be necessary
++                 after serious protocol errors caused by e.g. the SAA7740 */
++              saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
++              saa7146_write(dev, MC2, (MASK_00 | MASK_16));
++              msleep(SAA7146_I2C_DELAY);
++
++              /* clear all error-bits pending */
++              saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
++              saa7146_write(dev, MC2, (MASK_00 | MASK_16));
++              msleep(SAA7146_I2C_DELAY);
++
++              /* the data sheet says it might be necessary to clear the status
++                 twice after an abort */
++              saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
++              saa7146_write(dev, MC2, (MASK_00 | MASK_16));
++              msleep(SAA7146_I2C_DELAY);
++      }
++
++      /* if any error is still present, a fatal error has occurred ... */
++      status = saa7146_i2c_status(dev);
++      if ( dev->i2c_bitrate != status ) {
++              DEB_I2C("fatal error. status:0x%08x\n", status);
++              return -1;
++      }
++
++      return 0;
++}
++
++/* this functions writes out the data-byte 'dword' to the i2c-device.
++   it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
++   failed badly (e.g. address error) */
++static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
++{
++      u32 status = 0, mc2 = 0;
++      int trial = 0;
++      unsigned long timeout;
++
++      /* write out i2c-command */
++      DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n",
++              *dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op);
++
++      if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
++
++              saa7146_write(dev, I2C_STATUS,   dev->i2c_bitrate);
++              saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
++
++              dev->i2c_op = 1;
++              SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
++              SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
++              saa7146_write(dev, MC2, (MASK_00 | MASK_16));
++
++              timeout = HZ/100 + 1; /* 10ms */
++              timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout);
++              if (timeout == -ERESTARTSYS || dev->i2c_op) {
++                      SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
++                      SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
++                      if (timeout == -ERESTARTSYS)
++                              /* a signal arrived */
++                              return -ERESTARTSYS;
++
++                      pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
++                              dev->name, __func__);
++                      return -EIO;
++              }
++              status = saa7146_read(dev, I2C_STATUS);
++      } else {
++              saa7146_write(dev, I2C_STATUS,   dev->i2c_bitrate);
++              saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
++              saa7146_write(dev, MC2, (MASK_00 | MASK_16));
++
++              /* do not poll for i2c-status before upload is complete */
++              timeout = jiffies + HZ/100 + 1; /* 10ms */
++              while(1) {
++                      mc2 = (saa7146_read(dev, MC2) & 0x1);
++                      if( 0 != mc2 ) {
++                              break;
++                      }
++                      if (time_after(jiffies,timeout)) {
++                              pr_warn("%s %s: timed out waiting for MC2\n",
++                                      dev->name, __func__);
++                              return -EIO;
++                      }
++              }
++              /* wait until we get a transfer done or error */
++              timeout = jiffies + HZ/100 + 1; /* 10ms */
++              /* first read usually delivers bogus results... */
++              saa7146_i2c_status(dev);
++              while(1) {
++                      status = saa7146_i2c_status(dev);
++                      if ((status & 0x3) != 1)
++                              break;
++                      if (time_after(jiffies,timeout)) {
++                              /* this is normal when probing the bus
++                               * (no answer from nonexisistant device...)
++                               */
++                              pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
++                                      dev->name, __func__);
++                              return -EIO;
++                      }
++                      if (++trial < 50 && short_delay)
++                              udelay(10);
++                      else
++                              msleep(1);
++              }
++      }
++
++      /* give a detailed status report */
++      if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
++                           SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
++                           SAA7146_I2C_AL    | SAA7146_I2C_ERR   |
++                           SAA7146_I2C_BUSY)) ) {
++
++              if ( 0 == (status & SAA7146_I2C_ERR) ||
++                   0 == (status & SAA7146_I2C_BUSY) ) {
++                      /* it may take some time until ERR goes high - ignore */
++                      DEB_I2C("unexpected i2c status %04x\n", status);
++              }
++              if( 0 != (status & SAA7146_I2C_SPERR) ) {
++                      DEB_I2C("error due to invalid start/stop condition\n");
++              }
++              if( 0 != (status & SAA7146_I2C_DTERR) ) {
++                      DEB_I2C("error in data transmission\n");
++              }
++              if( 0 != (status & SAA7146_I2C_DRERR) ) {
++                      DEB_I2C("error when receiving data\n");
++              }
++              if( 0 != (status & SAA7146_I2C_AL) ) {
++                      DEB_I2C("error because arbitration lost\n");
++              }
++
++              /* we handle address-errors here */
++              if( 0 != (status & SAA7146_I2C_APERR) ) {
++                      DEB_I2C("error in address phase\n");
++                      return -EREMOTEIO;
++              }
++
++              return -EIO;
++      }
++
++      /* read back data, just in case we were reading ... */
++      *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
++
++      DEB_I2C("after: 0x%08x\n", *dword);
++      return 0;
++}
++
++static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
++{
++      int i = 0, count = 0;
++      __le32 *buffer = dev->d_i2c.cpu_addr;
++      int err = 0;
++      int short_delay = 0;
++
++      if (mutex_lock_interruptible(&dev->i2c_lock))
++              return -ERESTARTSYS;
++
++      for(i=0;i<num;i++) {
++              DEB_I2C("msg:%d/%d\n", i+1, num);
++      }
++
++      /* prepare the message(s), get number of u32s to transfer */
++      count = saa7146_i2c_msg_prepare(msgs, num, buffer);
++      if ( 0 > count ) {
++              err = -1;
++              goto out;
++      }
++
++      if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) )
++              short_delay = 1;
++
++      do {
++              /* reset the i2c-device if necessary */
++              err = saa7146_i2c_reset(dev);
++              if ( 0 > err ) {
++                      DEB_I2C("could not reset i2c-device\n");
++                      goto out;
++              }
++
++              /* write out the u32s one after another */
++              for(i = 0; i < count; i++) {
++                      err = saa7146_i2c_writeout(dev, &buffer[i], short_delay);
++                      if ( 0 != err) {
++                              /* this one is unsatisfying: some i2c slaves on some
++                                 dvb cards don't acknowledge correctly, so the saa7146
++                                 thinks that an address error occurred. in that case, the
++                                 transaction should be retrying, even if an address error
++                                 occurred. analog saa7146 based cards extensively rely on
++                                 i2c address probing, however, and address errors indicate that a
++                                 device is really *not* there. retrying in that case
++                                 increases the time the device needs to probe greatly, so
++                                 it should be avoided. So we bail out in irq mode after an
++                                 address error and trust the saa7146 address error detection. */
++                              if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
++                                      goto out;
++                              DEB_I2C("error while sending message(s). starting again\n");
++                              break;
++                      }
++              }
++              if( 0 == err ) {
++                      err = num;
++                      break;
++              }
++
++              /* delay a bit before retrying */
++              msleep(10);
++
++      } while (err != num && retries--);
++
++      /* quit if any error occurred */
++      if (err != num)
++              goto out;
++
++      /* if any things had to be read, get the results */
++      if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
++              DEB_I2C("could not cleanup i2c-message\n");
++              err = -1;
++              goto out;
++      }
++
++      /* return the number of delivered messages */
++      DEB_I2C("transmission successful. (msg:%d)\n", err);
++out:
++      /* another bug in revision 0: the i2c-registers get uploaded randomly by other
++         uploads, so we better clear them out before continuing */
++      if( 0 == dev->revision ) {
++              __le32 zero = 0;
++              saa7146_i2c_reset(dev);
++              if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
++                      pr_info("revision 0 error. this should never happen\n");
++              }
++      }
++
++      mutex_unlock(&dev->i2c_lock);
++      return err;
++}
++
++/* utility functions */
++static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
++{
++      struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
++      struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
++
++      /* use helper function to transfer data */
++      return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
++}
++
++
++/*****************************************************************************/
++/* i2c-adapter helper functions                                              */
++
++/* exported algorithm data */
++static struct i2c_algorithm saa7146_algo = {
++      .master_xfer    = saa7146_i2c_xfer,
++      .functionality  = saa7146_i2c_func,
++};
++
++int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
++{
++      DEB_EE("bitrate: 0x%08x\n", bitrate);
++
++      /* enable i2c-port pins */
++      saa7146_write(dev, MC1, (MASK_08 | MASK_24));
++
++      dev->i2c_bitrate = bitrate;
++      saa7146_i2c_reset(dev);
++
++      if (i2c_adapter) {
++              i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev);
++              i2c_adapter->dev.parent    = &dev->pci->dev;
++              i2c_adapter->algo          = &saa7146_algo;
++              i2c_adapter->algo_data     = NULL;
++              i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
++              i2c_adapter->retries = SAA7146_I2C_RETRIES;
++      }
++
++      return 0;
++}
+diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
+new file mode 100644
+index 0000000..1e71e37
+--- /dev/null
++++ b/drivers/media/common/saa7146/saa7146_vbi.c
+@@ -0,0 +1,498 @@
++#include <media/saa7146_vv.h>
++
++static int vbi_pixel_to_capture = 720 * 2;
++
++static int vbi_workaround(struct saa7146_dev *dev)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++
++      u32          *cpu;
++      dma_addr_t   dma_addr;
++
++      int count = 0;
++      int i;
++
++      DECLARE_WAITQUEUE(wait, current);
++
++      DEB_VBI("dev:%p\n", dev);
++
++      /* once again, a bug in the saa7146: the brs acquisition
++         is buggy and especially the BXO-counter does not work
++         as specified. there is this workaround, but please
++         don't let me explain it. ;-) */
++
++      cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr);
++      if (NULL == cpu)
++              return -ENOMEM;
++
++      /* setup some basic programming, just for the workaround */
++      saa7146_write(dev, BASE_EVEN3,  dma_addr);
++      saa7146_write(dev, BASE_ODD3,   dma_addr+vbi_pixel_to_capture);
++      saa7146_write(dev, PROT_ADDR3,  dma_addr+4096);
++      saa7146_write(dev, PITCH3,      vbi_pixel_to_capture);
++      saa7146_write(dev, BASE_PAGE3,  0x0);
++      saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));
++      saa7146_write(dev, MC2, MASK_04|MASK_20);
++
++      /* load brs-control register */
++      WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
++      /* BXO = 1h, BRS to outbound */
++      WRITE_RPS1(0xc000008c);
++      /* wait for vbi_a or vbi_b*/
++      if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
++              DEB_D("...using port b\n");
++              WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
++              WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
++/*
++              WRITE_RPS1(CMD_PAUSE | MASK_09);
++*/
++      } else {
++              DEB_D("...using port a\n");
++              WRITE_RPS1(CMD_PAUSE | MASK_10);
++      }
++      /* upload brs */
++      WRITE_RPS1(CMD_UPLOAD | MASK_08);
++      /* load brs-control register */
++      WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
++      /* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
++      WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
++      /* wait for brs_done */
++      WRITE_RPS1(CMD_PAUSE | MASK_08);
++      /* upload brs */
++      WRITE_RPS1(CMD_UPLOAD | MASK_08);
++      /* load video-dma3 NumLines3 and NumBytes3 */
++      WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
++      /* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
++      WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
++      /* load brs-control register */
++      WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
++      /* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
++      WRITE_RPS1((540 << 7) | (5 << 19));  // 5 == vbi_start
++      /* wait for brs_done */
++      WRITE_RPS1(CMD_PAUSE | MASK_08);
++      /* upload brs and video-dma3*/
++      WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
++      /* load mc2 register: enable dma3 */
++      WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
++      WRITE_RPS1(MASK_20 | MASK_04);
++      /* generate interrupt */
++      WRITE_RPS1(CMD_INTERRUPT);
++      /* stop rps1 */
++      WRITE_RPS1(CMD_STOP);
++
++      /* we have to do the workaround twice to be sure that
++         everything is ok */
++      for(i = 0; i < 2; i++) {
++
++              /* indicate to the irq handler that we do the workaround */
++              saa7146_write(dev, MC2, MASK_31|MASK_15);
++
++              saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));
++              saa7146_write(dev, MC2, MASK_04|MASK_20);
++
++              /* enable rps1 irqs */
++              SAA7146_IER_ENABLE(dev,MASK_28);
++
++              /* prepare to wait to be woken up by the irq-handler */
++              add_wait_queue(&vv->vbi_wq, &wait);
++              current->state = TASK_INTERRUPTIBLE;
++
++              /* start rps1 to enable workaround */
++              saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
++              saa7146_write(dev, MC1, (MASK_13 | MASK_29));
++
++              schedule();
++
++              DEB_VBI("brs bug workaround %d/1\n", i);
++
++              remove_wait_queue(&vv->vbi_wq, &wait);
++              current->state = TASK_RUNNING;
++
++              /* disable rps1 irqs */
++              SAA7146_IER_DISABLE(dev,MASK_28);
++
++              /* stop video-dma3 */
++              saa7146_write(dev, MC1, MASK_20);
++
++              if(signal_pending(current)) {
++
++                      DEB_VBI("aborted (rps:0x%08x)\n",
++                              saa7146_read(dev, RPS_ADDR1));
++
++                      /* stop rps1 for sure */
++                      saa7146_write(dev, MC1, MASK_29);
++
++                      pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
++                      return -EINTR;
++              }
++      }
++
++      pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
++      return 0;
++}
++
++static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++
++      struct saa7146_video_dma vdma3;
++
++      int count = 0;
++      unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
++      unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
++
++/*
++      vdma3.base_even = 0xc8000000+2560*70;
++      vdma3.base_odd  = 0xc8000000;
++      vdma3.prot_addr = 0xc8000000+2560*164;
++      vdma3.pitch     = 2560;
++      vdma3.base_page = 0;
++      vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!
++*/
++      vdma3.base_even = buf->pt[2].offset;
++      vdma3.base_odd  = buf->pt[2].offset + 16 * vbi_pixel_to_capture;
++      vdma3.prot_addr = buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture;
++      vdma3.pitch     = vbi_pixel_to_capture;
++      vdma3.base_page = buf->pt[2].dma | ME1;
++      vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;
++
++      saa7146_write_out_dma(dev, 3, &vdma3);
++
++      /* write beginning of rps-program */
++      count = 0;
++
++      /* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */
++
++      /* we don't wait here for the first field anymore. this is different from the video
++         capture and might cause that the first buffer is only half filled (with only
++         one field). but since this is some sort of streaming data, this is not that negative.
++         but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
++
++/*
++      WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
++      WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);
++*/
++      /* set bit 1 */
++      WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));
++      WRITE_RPS1(MASK_28 | MASK_12);
++
++      /* turn on video-dma3 */
++      WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));
++      WRITE_RPS1(MASK_04 | MASK_20);                  /* => mask */
++      WRITE_RPS1(MASK_04 | MASK_20);                  /* => values */
++
++      /* wait for o_fid_a/b / e_fid_a/b toggle */
++      WRITE_RPS1(CMD_PAUSE | o_wait);
++      WRITE_RPS1(CMD_PAUSE | e_wait);
++
++      /* generate interrupt */
++      WRITE_RPS1(CMD_INTERRUPT);
++
++      /* stop */
++      WRITE_RPS1(CMD_STOP);
++
++      /* enable rps1 irqs */
++      SAA7146_IER_ENABLE(dev, MASK_28);
++
++      /* write the address of the rps-program */
++      saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
++
++      /* turn on rps */
++      saa7146_write(dev, MC1, (MASK_13 | MASK_29));
++}
++
++static int buffer_activate(struct saa7146_dev *dev,
++                         struct saa7146_buf *buf,
++                         struct saa7146_buf *next)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      buf->vb.state = VIDEOBUF_ACTIVE;
++
++      DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
++      saa7146_set_vbi_capture(dev,buf,next);
++
++      mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
++      return 0;
++}
++
++static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field)
++{
++      struct file *file = q->priv_data;
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_buf *buf = (struct saa7146_buf *)vb;
++
++      int err = 0;
++      int lines, llength, size;
++
++      lines   = 16 * 2 ; /* 2 fields */
++      llength = vbi_pixel_to_capture;
++      size = lines * llength;
++
++      DEB_VBI("vb:%p\n", vb);
++
++      if (0 != buf->vb.baddr  &&  buf->vb.bsize < size) {
++              DEB_VBI("size mismatch\n");
++              return -EINVAL;
++      }
++
++      if (buf->vb.size != size)
++              saa7146_dma_free(dev,q,buf);
++
++      if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
++              struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
++
++              buf->vb.width  = llength;
++              buf->vb.height = lines;
++              buf->vb.size   = size;
++              buf->vb.field  = field; // FIXME: check this
++
++              saa7146_pgtable_free(dev->pci, &buf->pt[2]);
++              saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
++
++              err = videobuf_iolock(q,&buf->vb, NULL);
++              if (err)
++                      goto oops;
++              err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
++                                               dma->sglist, dma->sglen);
++              if (0 != err)
++                      return err;
++      }
++      buf->vb.state = VIDEOBUF_PREPARED;
++      buf->activate = buffer_activate;
++
++      return 0;
++
++ oops:
++      DEB_VBI("error out\n");
++      saa7146_dma_free(dev,q,buf);
++
++      return err;
++}
++
++static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
++{
++      int llength,lines;
++
++      lines   = 16 * 2 ; /* 2 fields */
++      llength = vbi_pixel_to_capture;
++
++      *size = lines * llength;
++      *count = 2;
++
++      DEB_VBI("count:%d, size:%d\n", *count, *size);
++
++      return 0;
++}
++
++static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
++{
++      struct file *file = q->priv_data;
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_buf *buf = (struct saa7146_buf *)vb;
++
++      DEB_VBI("vb:%p\n", vb);
++      saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf);
++}
++
++static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
++{
++      struct file *file = q->priv_data;
++      struct saa7146_fh *fh   = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_buf *buf = (struct saa7146_buf *)vb;
++
++      DEB_VBI("vb:%p\n", vb);
++      saa7146_dma_free(dev,q,buf);
++}
++
++static struct videobuf_queue_ops vbi_qops = {
++      .buf_setup    = buffer_setup,
++      .buf_prepare  = buffer_prepare,
++      .buf_queue    = buffer_queue,
++      .buf_release  = buffer_release,
++};
++
++/* ------------------------------------------------------------------ */
++
++static void vbi_stop(struct saa7146_fh *fh, struct file *file)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      unsigned long flags;
++      DEB_VBI("dev:%p, fh:%p\n", dev, fh);
++
++      spin_lock_irqsave(&dev->slock,flags);
++
++      /* disable rps1  */
++      saa7146_write(dev, MC1, MASK_29);
++
++      /* disable rps1 irqs */
++      SAA7146_IER_DISABLE(dev, MASK_28);
++
++      /* shut down dma 3 transfers */
++      saa7146_write(dev, MC1, MASK_20);
++
++      if (vv->vbi_dmaq.curr)
++              saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
++
++      videobuf_queue_cancel(&fh->vbi_q);
++
++      vv->vbi_streaming = NULL;
++
++      del_timer(&vv->vbi_dmaq.timeout);
++      del_timer(&vv->vbi_read_timeout);
++
++      spin_unlock_irqrestore(&dev->slock, flags);
++}
++
++static void vbi_read_timeout(unsigned long data)
++{
++      struct file *file = (struct file*)data;
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++
++      DEB_VBI("dev:%p, fh:%p\n", dev, fh);
++
++      vbi_stop(fh, file);
++}
++
++static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
++{
++      DEB_VBI("dev:%p\n", dev);
++
++      INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
++
++      init_timer(&vv->vbi_dmaq.timeout);
++      vv->vbi_dmaq.timeout.function = saa7146_buffer_timeout;
++      vv->vbi_dmaq.timeout.data     = (unsigned long)(&vv->vbi_dmaq);
++      vv->vbi_dmaq.dev              = dev;
++
++      init_waitqueue_head(&vv->vbi_wq);
++}
++
++static int vbi_open(struct saa7146_dev *dev, struct file *file)
++{
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_vv *vv = fh->dev->vv_data;
++
++      u32 arbtr_ctrl  = saa7146_read(dev, PCI_BT_V1);
++      int ret = 0;
++
++      DEB_VBI("dev:%p, fh:%p\n", dev, fh);
++
++      ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
++      if (0 == ret) {
++              DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
++              return -EBUSY;
++      }
++
++      /* adjust arbitrition control for video dma 3 */
++      arbtr_ctrl &= ~0x1f0000;
++      arbtr_ctrl |=  0x1d0000;
++      saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
++      saa7146_write(dev, MC2, (MASK_04|MASK_20));
++
++      videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
++                          &dev->pci->dev, &dev->slock,
++                          V4L2_BUF_TYPE_VBI_CAPTURE,
++                          V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
++                          sizeof(struct saa7146_buf),
++                          file, &dev->v4l2_lock);
++
++      vv->vbi_read_timeout.function = vbi_read_timeout;
++      vv->vbi_read_timeout.data = (unsigned long)file;
++
++      /* initialize the brs */
++      if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
++              saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));
++      } else {
++              saa7146_write(dev, BRS_CTRL, 0x00000001);
++
++              if (0 != (ret = vbi_workaround(dev))) {
++                      DEB_VBI("vbi workaround failed!\n");
++                      /* return ret;*/
++              }
++      }
++
++      /* upload brs register */
++      saa7146_write(dev, MC2, (MASK_08|MASK_24));
++      return 0;
++}
++
++static void vbi_close(struct saa7146_dev *dev, struct file *file)
++{
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_vv *vv = dev->vv_data;
++      DEB_VBI("dev:%p, fh:%p\n", dev, fh);
++
++      if( fh == vv->vbi_streaming ) {
++              vbi_stop(fh, file);
++      }
++      saa7146_res_free(fh, RESOURCE_DMA3_BRS);
++}
++
++static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      spin_lock(&dev->slock);
++
++      if (vv->vbi_dmaq.curr) {
++              DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
++              /* this must be += 2, one count for each field */
++              vv->vbi_fieldcount+=2;
++              vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount;
++              saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
++      } else {
++              DEB_VBI("dev:%p\n", dev);
++      }
++      saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
++
++      spin_unlock(&dev->slock);
++}
++
++static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
++{
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      ssize_t ret = 0;
++
++      DEB_VBI("dev:%p, fh:%p\n", dev, fh);
++
++      if( NULL == vv->vbi_streaming ) {
++              // fixme: check if dma3 is available
++              // fixme: activate vbi engine here if necessary. (really?)
++              vv->vbi_streaming = fh;
++      }
++
++      if( fh != vv->vbi_streaming ) {
++              DEB_VBI("open %p is already using vbi capture\n",
++                      vv->vbi_streaming);
++              return -EBUSY;
++      }
++
++      mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
++      ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
++                                 file->f_flags & O_NONBLOCK);
++/*
++      printk("BASE_ODD3:      0x%08x\n", saa7146_read(dev, BASE_ODD3));
++      printk("BASE_EVEN3:     0x%08x\n", saa7146_read(dev, BASE_EVEN3));
++      printk("PROT_ADDR3:     0x%08x\n", saa7146_read(dev, PROT_ADDR3));
++      printk("PITCH3:         0x%08x\n", saa7146_read(dev, PITCH3));
++      printk("BASE_PAGE3:     0x%08x\n", saa7146_read(dev, BASE_PAGE3));
++      printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3));
++      printk("BRS_CTRL:       0x%08x\n", saa7146_read(dev, BRS_CTRL));
++*/
++      return ret;
++}
++
++struct saa7146_use_ops saa7146_vbi_uops = {
++      .init           = vbi_init,
++      .open           = vbi_open,
++      .release        = vbi_close,
++      .irq_done       = vbi_irq_done,
++      .read           = vbi_read,
++};
+diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
+new file mode 100644
+index 0000000..4143d61
+--- /dev/null
++++ b/drivers/media/common/saa7146/saa7146_video.c
+@@ -0,0 +1,1332 @@
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <media/saa7146_vv.h>
++#include <media/v4l2-chip-ident.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-ctrls.h>
++#include <linux/module.h>
++
++static int max_memory = 32;
++
++module_param(max_memory, int, 0644);
++MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");
++
++#define IS_CAPTURE_ACTIVE(fh) \
++      (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))
++
++#define IS_OVERLAY_ACTIVE(fh) \
++      (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))
++
++/* format descriptions for capture and preview */
++static struct saa7146_format formats[] = {
++      {
++              .name           = "RGB-8 (3-3-2)",
++              .pixelformat    = V4L2_PIX_FMT_RGB332,
++              .trans          = RGB08_COMPOSED,
++              .depth          = 8,
++              .flags          = 0,
++      }, {
++              .name           = "RGB-16 (5/B-6/G-5/R)",
++              .pixelformat    = V4L2_PIX_FMT_RGB565,
++              .trans          = RGB16_COMPOSED,
++              .depth          = 16,
++              .flags          = 0,
++      }, {
++              .name           = "RGB-24 (B-G-R)",
++              .pixelformat    = V4L2_PIX_FMT_BGR24,
++              .trans          = RGB24_COMPOSED,
++              .depth          = 24,
++              .flags          = 0,
++      }, {
++              .name           = "RGB-32 (B-G-R)",
++              .pixelformat    = V4L2_PIX_FMT_BGR32,
++              .trans          = RGB32_COMPOSED,
++              .depth          = 32,
++              .flags          = 0,
++      }, {
++              .name           = "RGB-32 (R-G-B)",
++              .pixelformat    = V4L2_PIX_FMT_RGB32,
++              .trans          = RGB32_COMPOSED,
++              .depth          = 32,
++              .flags          = 0,
++              .swap           = 0x2,
++      }, {
++              .name           = "Greyscale-8",
++              .pixelformat    = V4L2_PIX_FMT_GREY,
++              .trans          = Y8,
++              .depth          = 8,
++              .flags          = 0,
++      }, {
++              .name           = "YUV 4:2:2 planar (Y-Cb-Cr)",
++              .pixelformat    = V4L2_PIX_FMT_YUV422P,
++              .trans          = YUV422_DECOMPOSED,
++              .depth          = 16,
++              .flags          = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
++      }, {
++              .name           = "YVU 4:2:0 planar (Y-Cb-Cr)",
++              .pixelformat    = V4L2_PIX_FMT_YVU420,
++              .trans          = YUV420_DECOMPOSED,
++              .depth          = 12,
++              .flags          = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
++      }, {
++              .name           = "YUV 4:2:0 planar (Y-Cb-Cr)",
++              .pixelformat    = V4L2_PIX_FMT_YUV420,
++              .trans          = YUV420_DECOMPOSED,
++              .depth          = 12,
++              .flags          = FORMAT_IS_PLANAR,
++      }, {
++              .name           = "YUV 4:2:2 (U-Y-V-Y)",
++              .pixelformat    = V4L2_PIX_FMT_UYVY,
++              .trans          = YUV422_COMPOSED,
++              .depth          = 16,
++              .flags          = 0,
++      }
++};
++
++/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.
++   due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped
++   (like V4L2_PIX_FMT_YUYV) ... 8-( */
++
++static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
++
++struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
++{
++      int i, j = NUM_FORMATS;
++
++      for (i = 0; i < j; i++) {
++              if (formats[i].pixelformat == fourcc) {
++                      return formats+i;
++              }
++      }
++
++      DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
++      return NULL;
++}
++
++static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
++
++int saa7146_start_preview(struct saa7146_fh *fh)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct v4l2_format fmt;
++      int ret = 0, err = 0;
++
++      DEB_EE("dev:%p, fh:%p\n", dev, fh);
++
++      /* check if we have overlay information */
++      if (vv->ov.fh == NULL) {
++              DEB_D("no overlay data available. try S_FMT first.\n");
++              return -EAGAIN;
++      }
++
++      /* check if streaming capture is running */
++      if (IS_CAPTURE_ACTIVE(fh) != 0) {
++              DEB_D("streaming capture is active\n");
++              return -EBUSY;
++      }
++
++      /* check if overlay is running */
++      if (IS_OVERLAY_ACTIVE(fh) != 0) {
++              if (vv->video_fh == fh) {
++                      DEB_D("overlay is already active\n");
++                      return 0;
++              }
++              DEB_D("overlay is already active in another open\n");
++              return -EBUSY;
++      }
++
++      if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
++              DEB_D("cannot get necessary overlay resources\n");
++              return -EBUSY;
++      }
++
++      fmt.fmt.win = vv->ov.win;
++      err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
++      if (0 != err) {
++              saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
++              return -EBUSY;
++      }
++      vv->ov.win = fmt.fmt.win;
++
++      DEB_D("%dx%d+%d+%d %s field=%s\n",
++            vv->ov.win.w.width, vv->ov.win.w.height,
++            vv->ov.win.w.left, vv->ov.win.w.top,
++            vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]);
++
++      if (0 != (ret = saa7146_enable_overlay(fh))) {
++              DEB_D("enabling overlay failed: %d\n", ret);
++              saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
++              return ret;
++      }
++
++      vv->video_status = STATUS_OVERLAY;
++      vv->video_fh = fh;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(saa7146_start_preview);
++
++int saa7146_stop_preview(struct saa7146_fh *fh)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      DEB_EE("dev:%p, fh:%p\n", dev, fh);
++
++      /* check if streaming capture is running */
++      if (IS_CAPTURE_ACTIVE(fh) != 0) {
++              DEB_D("streaming capture is active\n");
++              return -EBUSY;
++      }
++
++      /* check if overlay is running at all */
++      if ((vv->video_status & STATUS_OVERLAY) == 0) {
++              DEB_D("no active overlay\n");
++              return 0;
++      }
++
++      if (vv->video_fh != fh) {
++              DEB_D("overlay is active, but in another open\n");
++              return -EBUSY;
++      }
++
++      vv->video_status = 0;
++      vv->video_fh = NULL;
++
++      saa7146_disable_overlay(fh);
++
++      saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(saa7146_stop_preview);
++
++/********************************************************************************/
++/* common pagetable functions */
++
++static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
++{
++      struct pci_dev *pci = dev->pci;
++      struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
++      struct scatterlist *list = dma->sglist;
++      int length = dma->sglen;
++      struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
++
++      DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
++
++      if( 0 != IS_PLANAR(sfmt->trans)) {
++              struct saa7146_pgtable *pt1 = &buf->pt[0];
++              struct saa7146_pgtable *pt2 = &buf->pt[1];
++              struct saa7146_pgtable *pt3 = &buf->pt[2];
++              __le32  *ptr1, *ptr2, *ptr3;
++              __le32 fill;
++
++              int size = buf->fmt->width*buf->fmt->height;
++              int i,p,m1,m2,m3,o1,o2;
++
++              switch( sfmt->depth ) {
++                      case 12: {
++                              /* create some offsets inside the page table */
++                              m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
++                              m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
++                              m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
++                              o1 = size%PAGE_SIZE;
++                              o2 = (size+(size/4))%PAGE_SIZE;
++                              DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
++                                      size, m1, m2, m3, o1, o2);
++                              break;
++                      }
++                      case 16: {
++                              /* create some offsets inside the page table */
++                              m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
++                              m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
++                              m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
++                              o1 = size%PAGE_SIZE;
++                              o2 = (size+(size/2))%PAGE_SIZE;
++                              DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
++                                      size, m1, m2, m3, o1, o2);
++                              break;
++                      }
++                      default: {
++                              return -1;
++                      }
++              }
++
++              ptr1 = pt1->cpu;
++              ptr2 = pt2->cpu;
++              ptr3 = pt3->cpu;
++
++              /* walk all pages, copy all page addresses to ptr1 */
++              for (i = 0; i < length; i++, list++) {
++                      for (p = 0; p * 4096 < list->length; p++, ptr1++) {
++                              *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
++                      }
++              }
++/*
++              ptr1 = pt1->cpu;
++              for(j=0;j<40;j++) {
++                      printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
++              }
++*/
++
++              /* if we have a user buffer, the first page may not be
++                 aligned to a page boundary. */
++              pt1->offset = dma->sglist->offset;
++              pt2->offset = pt1->offset+o1;
++              pt3->offset = pt1->offset+o2;
++
++              /* create video-dma2 page table */
++              ptr1 = pt1->cpu;
++              for(i = m1; i <= m2 ; i++, ptr2++) {
++                      *ptr2 = ptr1[i];
++              }
++              fill = *(ptr2-1);
++              for(;i<1024;i++,ptr2++) {
++                      *ptr2 = fill;
++              }
++              /* create video-dma3 page table */
++              ptr1 = pt1->cpu;
++              for(i = m2; i <= m3; i++,ptr3++) {
++                      *ptr3 = ptr1[i];
++              }
++              fill = *(ptr3-1);
++              for(;i<1024;i++,ptr3++) {
++                      *ptr3 = fill;
++              }
++              /* finally: finish up video-dma1 page table */
++              ptr1 = pt1->cpu+m1;
++              fill = pt1->cpu[m1];
++              for(i=m1;i<1024;i++,ptr1++) {
++                      *ptr1 = fill;
++              }
++/*
++              ptr1 = pt1->cpu;
++              ptr2 = pt2->cpu;
++              ptr3 = pt3->cpu;
++              for(j=0;j<40;j++) {
++                      printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
++              }
++              for(j=0;j<40;j++) {
++                      printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);
++              }
++              for(j=0;j<40;j++) {
++                      printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
++              }
++*/
++      } else {
++              struct saa7146_pgtable *pt = &buf->pt[0];
++              return saa7146_pgtable_build_single(pci, pt, list, length);
++      }
++
++      return 0;
++}
++
++
++/********************************************************************************/
++/* file operations */
++
++static int video_begin(struct saa7146_fh *fh)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_format *fmt = NULL;
++      unsigned int resource;
++      int ret = 0, err = 0;
++
++      DEB_EE("dev:%p, fh:%p\n", dev, fh);
++
++      if ((vv->video_status & STATUS_CAPTURE) != 0) {
++              if (vv->video_fh == fh) {
++                      DEB_S("already capturing\n");
++                      return 0;
++              }
++              DEB_S("already capturing in another open\n");
++              return -EBUSY;
++      }
++
++      if ((vv->video_status & STATUS_OVERLAY) != 0) {
++              DEB_S("warning: suspending overlay video for streaming capture\n");
++              vv->ov_suspend = vv->video_fh;
++              err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
++              if (0 != err) {
++                      DEB_D("suspending video failed. aborting\n");
++                      return err;
++              }
++      }
++
++      fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
++      /* we need to have a valid format set here */
++      BUG_ON(NULL == fmt);
++
++      if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
++              resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
++      } else {
++              resource = RESOURCE_DMA1_HPS;
++      }
++
++      ret = saa7146_res_get(fh, resource);
++      if (0 == ret) {
++              DEB_S("cannot get capture resource %d\n", resource);
++              if (vv->ov_suspend != NULL) {
++                      saa7146_start_preview(vv->ov_suspend);
++                      vv->ov_suspend = NULL;
++              }
++              return -EBUSY;
++      }
++
++      /* clear out beginning of streaming bit (rps register 0)*/
++      saa7146_write(dev, MC2, MASK_27 );
++
++      /* enable rps0 irqs */
++      SAA7146_IER_ENABLE(dev, MASK_27);
++
++      vv->video_fh = fh;
++      vv->video_status = STATUS_CAPTURE;
++
++      return 0;
++}
++
++static int video_end(struct saa7146_fh *fh, struct file *file)
++{
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_format *fmt = NULL;
++      unsigned long flags;
++      unsigned int resource;
++      u32 dmas = 0;
++      DEB_EE("dev:%p, fh:%p\n", dev, fh);
++
++      if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
++              DEB_S("not capturing\n");
++              return 0;
++      }
++
++      if (vv->video_fh != fh) {
++              DEB_S("capturing, but in another open\n");
++              return -EBUSY;
++      }
++
++      fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
++      /* we need to have a valid format set here */
++      BUG_ON(NULL == fmt);
++
++      if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
++              resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
++              dmas = MASK_22 | MASK_21 | MASK_20;
++      } else {
++              resource = RESOURCE_DMA1_HPS;
++              dmas = MASK_22;
++      }
++      spin_lock_irqsave(&dev->slock,flags);
++
++      /* disable rps0  */
++      saa7146_write(dev, MC1, MASK_28);
++
++      /* disable rps0 irqs */
++      SAA7146_IER_DISABLE(dev, MASK_27);
++
++      /* shut down all used video dma transfers */
++      saa7146_write(dev, MC1, dmas);
++
++      spin_unlock_irqrestore(&dev->slock, flags);
++
++      vv->video_fh = NULL;
++      vv->video_status = 0;
++
++      saa7146_res_free(fh, resource);
++
++      if (vv->ov_suspend != NULL) {
++              saa7146_start_preview(vv->ov_suspend);
++              vv->ov_suspend = NULL;
++      }
++
++      return 0;
++}
++
++static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++
++      strcpy((char *)cap->driver, "saa7146 v4l2");
++      strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
++      sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
++      cap->device_caps =
++              V4L2_CAP_VIDEO_CAPTURE |
++              V4L2_CAP_VIDEO_OVERLAY |
++              V4L2_CAP_READWRITE |
++              V4L2_CAP_STREAMING;
++      cap->device_caps |= dev->ext_vv_data->capabilities;
++      cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
++      if (vdev->vfl_type == VFL_TYPE_GRABBER)
++              cap->device_caps &=
++                      ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
++      else
++              cap->device_caps &=
++                      ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
++      return 0;
++}
++
++static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      *fb = vv->ov_fb;
++      fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
++      fb->flags = V4L2_FBUF_FLAG_PRIMARY;
++      return 0;
++}
++
++static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_format *fmt;
++
++      DEB_EE("VIDIOC_S_FBUF\n");
++
++      if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
++              return -EPERM;
++
++      /* check args */
++      fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
++      if (NULL == fmt)
++              return -EINVAL;
++
++      /* planar formats are not allowed for overlay video, clipping and video dma would clash */
++      if (fmt->flags & FORMAT_IS_PLANAR)
++              DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
++                    (char *)&fmt->pixelformat);
++
++      /* check if overlay is running */
++      if (IS_OVERLAY_ACTIVE(fh) != 0) {
++              if (vv->video_fh != fh) {
++                      DEB_D("refusing to change framebuffer informations while overlay is active in another open\n");
++                      return -EBUSY;
++              }
++      }
++
++      /* ok, accept it */
++      vv->ov_fb = *fb;
++      vv->ov_fmt = fmt;
++
++      if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
++              vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
++              DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
++      }
++      return 0;
++}
++
++static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
++{
++      if (f->index >= NUM_FORMATS)
++              return -EINVAL;
++      strlcpy((char *)f->description, formats[f->index].name,
++                      sizeof(f->description));
++      f->pixelformat = formats[f->index].pixelformat;
++      return 0;
++}
++
++int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++      struct saa7146_dev *dev = container_of(ctrl->handler,
++                              struct saa7146_dev, ctrl_handler);
++      struct saa7146_vv *vv = dev->vv_data;
++      u32 val;
++
++      switch (ctrl->id) {
++      case V4L2_CID_BRIGHTNESS:
++              val = saa7146_read(dev, BCS_CTRL);
++              val &= 0x00ffffff;
++              val |= (ctrl->val << 24);
++              saa7146_write(dev, BCS_CTRL, val);
++              saa7146_write(dev, MC2, MASK_22 | MASK_06);
++              break;
++
++      case V4L2_CID_CONTRAST:
++              val = saa7146_read(dev, BCS_CTRL);
++              val &= 0xff00ffff;
++              val |= (ctrl->val << 16);
++              saa7146_write(dev, BCS_CTRL, val);
++              saa7146_write(dev, MC2, MASK_22 | MASK_06);
++              break;
++
++      case V4L2_CID_SATURATION:
++              val = saa7146_read(dev, BCS_CTRL);
++              val &= 0xffffff00;
++              val |= (ctrl->val << 0);
++              saa7146_write(dev, BCS_CTRL, val);
++              saa7146_write(dev, MC2, MASK_22 | MASK_06);
++              break;
++
++      case V4L2_CID_HFLIP:
++              /* fixme: we can support changing VFLIP and HFLIP here... */
++              if ((vv->video_status & STATUS_CAPTURE))
++                      return -EBUSY;
++              vv->hflip = ctrl->val;
++              break;
++
++      case V4L2_CID_VFLIP:
++              if ((vv->video_status & STATUS_CAPTURE))
++                      return -EBUSY;
++              vv->vflip = ctrl->val;
++              break;
++
++      default:
++              return -EINVAL;
++      }
++
++      if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
++              struct saa7146_fh *fh = vv->video_fh;
++
++              saa7146_stop_preview(fh);
++              saa7146_start_preview(fh);
++      }
++      return 0;
++}
++
++static int vidioc_g_parm(struct file *file, void *fh,
++              struct v4l2_streamparm *parm)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++              return -EINVAL;
++      parm->parm.capture.readbuffers = 1;
++      v4l2_video_std_frame_period(vv->standard->id,
++                                  &parm->parm.capture.timeperframe);
++      return 0;
++}
++
++static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      f->fmt.pix = vv->video_fmt;
++      return 0;
++}
++
++static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      f->fmt.win = vv->ov.win;
++      return 0;
++}
++
++static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      f->fmt.vbi = vv->vbi_fmt;
++      return 0;
++}
++
++static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_format *fmt;
++      enum v4l2_field field;
++      int maxw, maxh;
++      int calc_bpl;
++
++      DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
++
++      fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
++      if (NULL == fmt)
++              return -EINVAL;
++
++      field = f->fmt.pix.field;
++      maxw  = vv->standard->h_max_out;
++      maxh  = vv->standard->v_max_out;
++
++      if (V4L2_FIELD_ANY == field) {
++              field = (f->fmt.pix.height > maxh / 2)
++                      ? V4L2_FIELD_INTERLACED
++                      : V4L2_FIELD_BOTTOM;
++      }
++      switch (field) {
++      case V4L2_FIELD_ALTERNATE:
++              vv->last_field = V4L2_FIELD_TOP;
++              maxh = maxh / 2;
++              break;
++      case V4L2_FIELD_TOP:
++      case V4L2_FIELD_BOTTOM:
++              vv->last_field = V4L2_FIELD_INTERLACED;
++              maxh = maxh / 2;
++              break;
++      case V4L2_FIELD_INTERLACED:
++              vv->last_field = V4L2_FIELD_INTERLACED;
++              break;
++      default:
++              DEB_D("no known field mode '%d'\n", field);
++              return -EINVAL;
++      }
++
++      f->fmt.pix.field = field;
++      f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
++      if (f->fmt.pix.width > maxw)
++              f->fmt.pix.width = maxw;
++      if (f->fmt.pix.height > maxh)
++              f->fmt.pix.height = maxh;
++
++      calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
++
++      if (f->fmt.pix.bytesperline < calc_bpl)
++              f->fmt.pix.bytesperline = calc_bpl;
++
++      if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
++              f->fmt.pix.bytesperline = calc_bpl;
++
++      f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
++      DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",
++            f->fmt.pix.width, f->fmt.pix.height,
++            f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
++
++      return 0;
++}
++
++
++static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct v4l2_window *win = &f->fmt.win;
++      enum v4l2_field field;
++      int maxw, maxh;
++
++      DEB_EE("dev:%p\n", dev);
++
++      if (NULL == vv->ov_fb.base) {
++              DEB_D("no fb base set\n");
++              return -EINVAL;
++      }
++      if (NULL == vv->ov_fmt) {
++              DEB_D("no fb fmt set\n");
++              return -EINVAL;
++      }
++      if (win->w.width < 48 || win->w.height < 32) {
++              DEB_D("min width/height. (%d,%d)\n",
++                    win->w.width, win->w.height);
++              return -EINVAL;
++      }
++      if (win->clipcount > 16) {
++              DEB_D("clipcount too big\n");
++              return -EINVAL;
++      }
++
++      field = win->field;
++      maxw  = vv->standard->h_max_out;
++      maxh  = vv->standard->v_max_out;
++
++      if (V4L2_FIELD_ANY == field) {
++              field = (win->w.height > maxh / 2)
++                      ? V4L2_FIELD_INTERLACED
++                      : V4L2_FIELD_TOP;
++              }
++      switch (field) {
++      case V4L2_FIELD_TOP:
++      case V4L2_FIELD_BOTTOM:
++      case V4L2_FIELD_ALTERNATE:
++              maxh = maxh / 2;
++              break;
++      case V4L2_FIELD_INTERLACED:
++              break;
++      default:
++              DEB_D("no known field mode '%d'\n", field);
++              return -EINVAL;
++      }
++
++      win->field = field;
++      if (win->w.width > maxw)
++              win->w.width = maxw;
++      if (win->w.height > maxh)
++              win->w.height = maxh;
++
++      return 0;
++}
++
++static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
++{
++      struct saa7146_fh *fh = __fh;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      int err;
++
++      DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
++      if (IS_CAPTURE_ACTIVE(fh) != 0) {
++              DEB_EE("streaming capture is active\n");
++              return -EBUSY;
++      }
++      err = vidioc_try_fmt_vid_cap(file, fh, f);
++      if (0 != err)
++              return err;
++      vv->video_fmt = f->fmt.pix;
++      DEB_EE("set to pixelformat '%4.4s'\n",
++             (char *)&vv->video_fmt.pixelformat);
++      return 0;
++}
++
++static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
++{
++      struct saa7146_fh *fh = __fh;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      int err;
++
++      DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
++      err = vidioc_try_fmt_vid_overlay(file, fh, f);
++      if (0 != err)
++              return err;
++      vv->ov.win    = f->fmt.win;
++      vv->ov.nclips = f->fmt.win.clipcount;
++      if (vv->ov.nclips > 16)
++              vv->ov.nclips = 16;
++      if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
++                              sizeof(struct v4l2_clip) * vv->ov.nclips)) {
++              return -EFAULT;
++      }
++
++      /* vv->ov.fh is used to indicate that we have valid overlay informations, too */
++      vv->ov.fh = fh;
++
++      /* check if our current overlay is active */
++      if (IS_OVERLAY_ACTIVE(fh) != 0) {
++              saa7146_stop_preview(fh);
++              saa7146_start_preview(fh);
++      }
++      return 0;
++}
++
++static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++
++      *norm = vv->standard->id;
++      return 0;
++}
++
++      /* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
++         PAL / NTSC / SECAM. if your hardware does not (or does more)
++         -- override this function in your extension */
++/*
++      case VIDIOC_ENUMSTD:
++      {
++              struct v4l2_standard *e = arg;
++              if (e->index < 0 )
++                      return -EINVAL;
++              if( e->index < dev->ext_vv_data->num_stds ) {
++                      DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
++                      v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
++                      return 0;
++              }
++              return -EINVAL;
++      }
++      */
++
++static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
++{
++      struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      int found = 0;
++      int err, i;
++
++      DEB_EE("VIDIOC_S_STD\n");
++
++      if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
++              DEB_D("cannot change video standard while streaming capture is active\n");
++              return -EBUSY;
++      }
++
++      if ((vv->video_status & STATUS_OVERLAY) != 0) {
++              vv->ov_suspend = vv->video_fh;
++              err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
++              if (0 != err) {
++                      DEB_D("suspending video failed. aborting\n");
++                      return err;
++              }
++      }
++
++      for (i = 0; i < dev->ext_vv_data->num_stds; i++)
++              if (*id & dev->ext_vv_data->stds[i].id)
++                      break;
++      if (i != dev->ext_vv_data->num_stds) {
++              vv->standard = &dev->ext_vv_data->stds[i];
++              if (NULL != dev->ext_vv_data->std_callback)
++                      dev->ext_vv_data->std_callback(dev, vv->standard);
++              found = 1;
++      }
++
++      if (vv->ov_suspend != NULL) {
++              saa7146_start_preview(vv->ov_suspend);
++              vv->ov_suspend = NULL;
++      }
++
++      if (!found) {
++              DEB_EE("VIDIOC_S_STD: standard not found\n");
++              return -EINVAL;
++      }
++
++      DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);
++      return 0;
++}
++
++static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
++{
++      int err;
++
++      DEB_D("VIDIOC_OVERLAY on:%d\n", on);
++      if (on)
++              err = saa7146_start_preview(fh);
++      else
++              err = saa7146_stop_preview(fh);
++      return err;
++}
++
++static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
++{
++      struct saa7146_fh *fh = __fh;
++
++      if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++              return videobuf_reqbufs(&fh->video_q, b);
++      if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++              return videobuf_reqbufs(&fh->vbi_q, b);
++      return -EINVAL;
++}
++
++static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++      struct saa7146_fh *fh = __fh;
++
++      if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++              return videobuf_querybuf(&fh->video_q, buf);
++      if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++              return videobuf_querybuf(&fh->vbi_q, buf);
++      return -EINVAL;
++}
++
++static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++      struct saa7146_fh *fh = __fh;
++
++      if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++              return videobuf_qbuf(&fh->video_q, buf);
++      if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++              return videobuf_qbuf(&fh->vbi_q, buf);
++      return -EINVAL;
++}
++
++static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
++{
++      struct saa7146_fh *fh = __fh;
++
++      if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++              return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
++      if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
++              return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
++      return -EINVAL;
++}
++
++static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
++{
++      struct saa7146_fh *fh = __fh;
++      int err;
++
++      DEB_D("VIDIOC_STREAMON, type:%d\n", type);
++
++      err = video_begin(fh);
++      if (err)
++              return err;
++      if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++              return videobuf_streamon(&fh->video_q);
++      if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
++              return videobuf_streamon(&fh->vbi_q);
++      return -EINVAL;
++}
++
++static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
++{
++      struct saa7146_fh *fh = __fh;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      int err;
++
++      DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
++
++      /* ugly: we need to copy some checks from video_end(),
++         because videobuf_streamoff() relies on the capture running.
++         check and fix this */
++      if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
++              DEB_S("not capturing\n");
++              return 0;
++      }
++
++      if (vv->video_fh != fh) {
++              DEB_S("capturing, but in another open\n");
++              return -EBUSY;
++      }
++
++      err = -EINVAL;
++      if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++              err = videobuf_streamoff(&fh->video_q);
++      else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
++              err = videobuf_streamoff(&fh->vbi_q);
++      if (0 != err) {
++              DEB_D("warning: videobuf_streamoff() failed\n");
++              video_end(fh, file);
++      } else {
++              err = video_end(fh, file);
++      }
++      return err;
++}
++
++static int vidioc_g_chip_ident(struct file *file, void *__fh,
++              struct v4l2_dbg_chip_ident *chip)
++{
++      struct saa7146_fh *fh = __fh;
++      struct saa7146_dev *dev = fh->dev;
++
++      chip->ident = V4L2_IDENT_NONE;
++      chip->revision = 0;
++      if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
++              if (v4l2_chip_match_host(&chip->match))
++                      chip->ident = V4L2_IDENT_SAA7146;
++              return 0;
++      }
++      if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
++          chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
++              return -EINVAL;
++      return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
++                      core, g_chip_ident, chip);
++}
++
++const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
++      .vidioc_querycap             = vidioc_querycap,
++      .vidioc_enum_fmt_vid_cap     = vidioc_enum_fmt_vid_cap,
++      .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
++      .vidioc_g_fmt_vid_cap        = vidioc_g_fmt_vid_cap,
++      .vidioc_try_fmt_vid_cap      = vidioc_try_fmt_vid_cap,
++      .vidioc_s_fmt_vid_cap        = vidioc_s_fmt_vid_cap,
++      .vidioc_g_fmt_vid_overlay    = vidioc_g_fmt_vid_overlay,
++      .vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
++      .vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
++      .vidioc_g_chip_ident         = vidioc_g_chip_ident,
++
++      .vidioc_overlay              = vidioc_overlay,
++      .vidioc_g_fbuf               = vidioc_g_fbuf,
++      .vidioc_s_fbuf               = vidioc_s_fbuf,
++      .vidioc_reqbufs              = vidioc_reqbufs,
++      .vidioc_querybuf             = vidioc_querybuf,
++      .vidioc_qbuf                 = vidioc_qbuf,
++      .vidioc_dqbuf                = vidioc_dqbuf,
++      .vidioc_g_std                = vidioc_g_std,
++      .vidioc_s_std                = vidioc_s_std,
++      .vidioc_streamon             = vidioc_streamon,
++      .vidioc_streamoff            = vidioc_streamoff,
++      .vidioc_g_parm               = vidioc_g_parm,
++      .vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
++      .vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
++};
++
++const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
++      .vidioc_querycap             = vidioc_querycap,
++      .vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
++      .vidioc_g_chip_ident         = vidioc_g_chip_ident,
++
++      .vidioc_reqbufs              = vidioc_reqbufs,
++      .vidioc_querybuf             = vidioc_querybuf,
++      .vidioc_qbuf                 = vidioc_qbuf,
++      .vidioc_dqbuf                = vidioc_dqbuf,
++      .vidioc_g_std                = vidioc_g_std,
++      .vidioc_s_std                = vidioc_s_std,
++      .vidioc_streamon             = vidioc_streamon,
++      .vidioc_streamoff            = vidioc_streamoff,
++      .vidioc_g_parm               = vidioc_g_parm,
++      .vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
++      .vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
++};
++
++/*********************************************************************************/
++/* buffer handling functions                                                  */
++
++static int buffer_activate (struct saa7146_dev *dev,
++                   struct saa7146_buf *buf,
++                   struct saa7146_buf *next)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++
++      buf->vb.state = VIDEOBUF_ACTIVE;
++      saa7146_set_capture(dev,buf,next);
++
++      mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
++      return 0;
++}
++
++static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)
++{
++      saa7146_pgtable_free(dev->pci, &buf->pt[0]);
++      saa7146_pgtable_free(dev->pci, &buf->pt[1]);
++      saa7146_pgtable_free(dev->pci, &buf->pt[2]);
++}
++
++static int buffer_prepare(struct videobuf_queue *q,
++                        struct videobuf_buffer *vb, enum v4l2_field field)
++{
++      struct file *file = q->priv_data;
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_buf *buf = (struct saa7146_buf *)vb;
++      int size,err = 0;
++
++      DEB_CAP("vbuf:%p\n", vb);
++
++      /* sanity checks */
++      if (vv->video_fmt.width  < 48 ||
++          vv->video_fmt.height < 32 ||
++          vv->video_fmt.width  > vv->standard->h_max_out ||
++          vv->video_fmt.height > vv->standard->v_max_out) {
++              DEB_D("w (%d) / h (%d) out of bounds\n",
++                    vv->video_fmt.width, vv->video_fmt.height);
++              return -EINVAL;
++      }
++
++      size = vv->video_fmt.sizeimage;
++      if (0 != buf->vb.baddr && buf->vb.bsize < size) {
++              DEB_D("size mismatch\n");
++              return -EINVAL;
++      }
++
++      DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
++              vv->video_fmt.width, vv->video_fmt.height,
++              size, v4l2_field_names[vv->video_fmt.field]);
++      if (buf->vb.width  != vv->video_fmt.width  ||
++          buf->vb.bytesperline != vv->video_fmt.bytesperline ||
++          buf->vb.height != vv->video_fmt.height ||
++          buf->vb.size   != size ||
++          buf->vb.field  != field      ||
++          buf->vb.field  != vv->video_fmt.field  ||
++          buf->fmt       != &vv->video_fmt) {
++              saa7146_dma_free(dev,q,buf);
++      }
++
++      if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
++              struct saa7146_format *sfmt;
++
++              buf->vb.bytesperline  = vv->video_fmt.bytesperline;
++              buf->vb.width  = vv->video_fmt.width;
++              buf->vb.height = vv->video_fmt.height;
++              buf->vb.size   = size;
++              buf->vb.field  = field;
++              buf->fmt       = &vv->video_fmt;
++              buf->vb.field  = vv->video_fmt.field;
++
++              sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
++
++              release_all_pagetables(dev, buf);
++              if( 0 != IS_PLANAR(sfmt->trans)) {
++                      saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
++                      saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
++                      saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
++              } else {
++                      saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
++              }
++
++              err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
++              if (err)
++                      goto oops;
++              err = saa7146_pgtable_build(dev,buf);
++              if (err)
++                      goto oops;
++      }
++      buf->vb.state = VIDEOBUF_PREPARED;
++      buf->activate = buffer_activate;
++
++      return 0;
++
++ oops:
++      DEB_D("error out\n");
++      saa7146_dma_free(dev,q,buf);
++
++      return err;
++}
++
++static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
++{
++      struct file *file = q->priv_data;
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_vv *vv = fh->dev->vv_data;
++
++      if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
++              *count = MAX_SAA7146_CAPTURE_BUFFERS;
++
++      *size = vv->video_fmt.sizeimage;
++
++      /* check if we exceed the "max_memory" parameter */
++      if( (*count * *size) > (max_memory*1048576) ) {
++              *count = (max_memory*1048576) / *size;
++      }
++
++      DEB_CAP("%d buffers, %d bytes each\n", *count, *size);
++
++      return 0;
++}
++
++static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
++{
++      struct file *file = q->priv_data;
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_buf *buf = (struct saa7146_buf *)vb;
++
++      DEB_CAP("vbuf:%p\n", vb);
++      saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf);
++}
++
++static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
++{
++      struct file *file = q->priv_data;
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_buf *buf = (struct saa7146_buf *)vb;
++
++      DEB_CAP("vbuf:%p\n", vb);
++
++      saa7146_dma_free(dev,q,buf);
++
++      release_all_pagetables(dev, buf);
++}
++
++static struct videobuf_queue_ops video_qops = {
++      .buf_setup    = buffer_setup,
++      .buf_prepare  = buffer_prepare,
++      .buf_queue    = buffer_queue,
++      .buf_release  = buffer_release,
++};
++
++/********************************************************************************/
++/* file operations */
++
++static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
++{
++      INIT_LIST_HEAD(&vv->video_dmaq.queue);
++
++      init_timer(&vv->video_dmaq.timeout);
++      vv->video_dmaq.timeout.function = saa7146_buffer_timeout;
++      vv->video_dmaq.timeout.data     = (unsigned long)(&vv->video_dmaq);
++      vv->video_dmaq.dev              = dev;
++
++      /* set some default values */
++      vv->standard = &dev->ext_vv_data->stds[0];
++
++      /* FIXME: what's this? */
++      vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;
++      vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;
++}
++
++
++static int video_open(struct saa7146_dev *dev, struct file *file)
++{
++      struct saa7146_fh *fh = file->private_data;
++
++      videobuf_queue_sg_init(&fh->video_q, &video_qops,
++                          &dev->pci->dev, &dev->slock,
++                          V4L2_BUF_TYPE_VIDEO_CAPTURE,
++                          V4L2_FIELD_INTERLACED,
++                          sizeof(struct saa7146_buf),
++                          file, &dev->v4l2_lock);
++
++      return 0;
++}
++
++
++static void video_close(struct saa7146_dev *dev, struct file *file)
++{
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_vv *vv = dev->vv_data;
++      struct videobuf_queue *q = &fh->video_q;
++
++      if (IS_CAPTURE_ACTIVE(fh) != 0)
++              video_end(fh, file);
++      else if (IS_OVERLAY_ACTIVE(fh) != 0)
++              saa7146_stop_preview(fh);
++
++      videobuf_stop(q);
++      /* hmm, why is this function declared void? */
++}
++
++
++static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
++{
++      struct saa7146_vv *vv = dev->vv_data;
++      struct saa7146_dmaqueue *q = &vv->video_dmaq;
++
++      spin_lock(&dev->slock);
++      DEB_CAP("called\n");
++
++      /* only finish the buffer if we have one... */
++      if( NULL != q->curr ) {
++              saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
++      }
++      saa7146_buffer_next(dev,q,0);
++
++      spin_unlock(&dev->slock);
++}
++
++static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
++{
++      struct saa7146_fh *fh = file->private_data;
++      struct saa7146_dev *dev = fh->dev;
++      struct saa7146_vv *vv = dev->vv_data;
++      ssize_t ret = 0;
++
++      DEB_EE("called\n");
++
++      if ((vv->video_status & STATUS_CAPTURE) != 0) {
++              /* fixme: should we allow read() captures while streaming capture? */
++              if (vv->video_fh == fh) {
++                      DEB_S("already capturing\n");
++                      return -EBUSY;
++              }
++              DEB_S("already capturing in another open\n");
++              return -EBUSY;
++      }
++
++      ret = video_begin(fh);
++      if( 0 != ret) {
++              goto out;
++      }
++
++      ret = videobuf_read_one(&fh->video_q , data, count, ppos,
++                              file->f_flags & O_NONBLOCK);
++      if (ret != 0) {
++              video_end(fh, file);
++      } else {
++              ret = video_end(fh, file);
++      }
++out:
++      /* restart overlay if it was active before */
++      if (vv->ov_suspend != NULL) {
++              saa7146_start_preview(vv->ov_suspend);
++              vv->ov_suspend = NULL;
++      }
++
++      return ret;
++}
++
++struct saa7146_use_ops saa7146_video_uops = {
++      .init = video_init,
++      .open = video_open,
++      .release = video_close,
++      .irq_done = video_irq_done,
++      .read = video_read,
++};
+diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
+deleted file mode 100644
+index d6b1cf6..0000000
+--- a/drivers/media/common/saa7146_core.c
++++ /dev/null
+@@ -1,600 +0,0 @@
+-/*
+-    saa7146.o - driver for generic saa7146-based hardware
+-
+-    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+-
+-    This program is free software; you can redistribute it and/or modify
+-    it under the terms of the GNU General Public License as published by
+-    the Free Software Foundation; either version 2 of the License, or
+-    (at your option) any later version.
+-
+-    This program is distributed in the hope that it will be useful,
+-    but WITHOUT ANY WARRANTY; without even the implied warranty of
+-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-    GNU General Public License for more details.
+-
+-    You should have received a copy of the GNU General Public License
+-    along with this program; if not, write to the Free Software
+-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-*/
+-
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+-
+-#include <media/saa7146.h>
+-#include <linux/module.h>
+-
+-LIST_HEAD(saa7146_devices);
+-DEFINE_MUTEX(saa7146_devices_lock);
+-
+-static int saa7146_num;
+-
+-unsigned int saa7146_debug;
+-
+-module_param(saa7146_debug, uint, 0644);
+-MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
+-
+-#if 0
+-static void dump_registers(struct saa7146_dev* dev)
+-{
+-      int i = 0;
+-
+-      pr_info(" @ %li jiffies:\n", jiffies);
+-      for (i = 0; i <= 0x148; i += 4)
+-              pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
+-}
+-#endif
+-
+-/****************************************************************************
+- * gpio and debi helper functions
+- ****************************************************************************/
+-
+-void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
+-{
+-      u32 value = 0;
+-
+-      BUG_ON(port > 3);
+-
+-      value = saa7146_read(dev, GPIO_CTRL);
+-      value &= ~(0xff << (8*port));
+-      value |= (data << (8*port));
+-      saa7146_write(dev, GPIO_CTRL, value);