diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/common/ir-keymaps.c v4l-dvb/linux/drivers/media/common/ir-keymaps.c
--- v4l-dvb.20071229/linux/drivers/media/common/ir-keymaps.c	2007-12-29 22:34:26.000000000 +0100
+++ v4l-dvb/linux/drivers/media/common/ir-keymaps.c	2007-12-31 15:03:24.000000000 +0100
@@ -1898,3 +1898,40 @@
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
+
+IR_KEYTAB_TYPE ir_codes_videomate_s350[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_TV,
+	[ 0x01 ] = KEY_DVD,
+	[ 0x04 ] = KEY_RECORD,
+	[ 0x05 ] = KEY_VIDEO, /* TV/Video */
+	[ 0x07 ] = KEY_STOP,
+	[ 0x08 ] = KEY_PLAYPAUSE,
+	[ 0x0a ] = KEY_REWIND,
+	[ 0x0f ] = KEY_FASTFORWARD,
+	[ 0x10 ] = KEY_CHANNELUP,
+	[ 0x12 ] = KEY_VOLUMEUP,
+	[ 0x13 ] = KEY_CHANNELDOWN,
+	[ 0x14 ] = KEY_MUTE,
+	[ 0x15 ] = KEY_VOLUMEDOWN,
+	[ 0x16 ] = KEY_1,
+	[ 0x17 ] = KEY_2,
+	[ 0x18 ] = KEY_3,
+	[ 0x19 ] = KEY_4,
+	[ 0x1a ] = KEY_5,
+	[ 0x1b ] = KEY_6,
+	[ 0x1c ] = KEY_7,
+	[ 0x1d ] = KEY_8,
+	[ 0x1e ] = KEY_9,
+	[ 0x1f ] = KEY_0,
+	[ 0x21 ] = KEY_SLEEP,
+	[ 0x24 ] = KEY_ZOOM,
+	[ 0x25 ] = KEY_LAST,	/* Recall */
+	[ 0x26 ] = KEY_SUBTITLE, /* CC */
+	[ 0x27 ] = KEY_LANGUAGE, /* MTS */
+	[ 0x29 ] = KEY_CHANNEL, /* SURF */
+	[ 0x2b ] = KEY_A,
+	[ 0x2c ] = KEY_B,
+	[ 0x2f ] = KEY_SHUFFLE, /* Snapshot */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_videomate_s350);
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/Kconfig v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/Kconfig	2007-12-29 22:34:26.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig	2007-12-31 15:04:12.000000000 +0100
@@ -71,6 +71,13 @@
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_ZL10313
+	tristate "Zarlink ZL10313 DVB-S demodulator"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S demodulator module. Say Y when you want to support this frontend.
+
 comment "DVB-T (terrestrial) frontends"
 	depends on DVB_CORE
 
@@ -360,14 +367,19 @@
 	  This device is only used inside a SiP called togther with a
 	  demodulator for now.
 
-config DVB_TUNER_XC5000
-	tristate "Xceive XC5000 silicon tuner"
-	depends on I2C
+config DVB_ZL1003X
+	tristate "Zarlink ZL10036/ZL10038 silicon tuner"
+	depends on DVB_CORE && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
-	  A driver for the silicon tuner XC5000 from Xceive.
-	  This device is only used inside a SiP called togther with a
-	  demodulator for now.
+	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_ZL10039
+	tristate "Zarlink ZL10039 DVB-S tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the ZL10039 DVB-S tuner from Zarlink
 
 comment "Miscellaneous devices"
 	depends on DVB_CORE
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/Makefile v4l-dvb/linux/drivers/media/dvb/frontends/Makefile
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/Makefile	2007-12-29 22:34:26.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/Makefile	2007-12-31 15:04:12.000000000 +0100
@@ -50,4 +50,6 @@
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
-obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_DVB_ZL10313) += zl10313.o
+obj-$(CONFIG_DVB_ZL1003X) += zl1003x.o
+obj-$(CONFIG_DVB_ZL10039) += zl10039.o
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10039.c v4l-dvb/linux/drivers/media/dvb/frontends/zl10039.c
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10039.c	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl10039.c	2007-12-31 15:04:12.000000000 +0100
@@ -0,0 +1,260 @@
+/*
+ *  Driver for Zarlink ZL10039 DVB-S tuner
+ *
+ *  Copyright 2007 Jan DaniÃ«l Louw <jd.louw@mweb.co.za>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/dvb/frontend.h>
+
+#include "dvb_frontend.h"
+#include "zl10039.h"
+#include "zl10039_priv.h"
+
+
+static int zl10039_read(const struct zl10039_state *state,
+			const enum zl10039_reg_addr reg, u8 *buf,
+			const size_t count)
+{
+	struct i2c_msg msg[2];
+	u8 regbuf[1] = { reg };
+	int i;
+
+	io_printk("%s\n", __FUNCTION__);
+	/* Write register address */
+	msg[0].addr = state->config.tuner_address;
+	msg[0].flags = 0;
+	msg[0].buf = regbuf;
+	msg[0].len = 1;
+	/* Read count bytes */
+	msg[1].addr = state->config.tuner_address;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf;
+	msg[1].len = count;
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		eprintk("%s: i2c read error\n", __FUNCTION__);
+		return -EREMOTEIO;
+	}
+	for (i = 0; i < count; i++) {
+		io_printk("R[%s] = 0x%x\n", zl10039_reg_names[reg + i], buf[i]);
+	}
+	return 0; /* Success */
+}
+
+static int zl10039_write(struct zl10039_state *state,
+			const enum zl10039_reg_addr reg, const u8 *src,
+			const size_t count)
+{
+	u8 buf[count + 1];
+	struct i2c_msg msg;
+	int i;
+
+	io_printk("%s\n", __FUNCTION__);
+	for (i = 0; i < count; i++) {
+		io_printk("W[%s] = 0x%x\n", zl10039_reg_names[reg + i], src[i]);
+	}
+	/* Write register address and data in one go */
+	buf[0] = reg;
+	memcpy(&buf[1], src, count);
+	msg.addr = state->config.tuner_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = count + 1;
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		eprintk("%s: i2c write error\n", __FUNCTION__);
+		return -EREMOTEIO;
+	}
+	return 0; /* Success */
+}
+
+static inline int zl10039_readreg(struct zl10039_state *state,
+				const enum zl10039_reg_addr reg, u8 *val)
+{
+	return zl10039_read(state, reg, val, 1);
+}
+
+static inline int zl10039_writereg(struct zl10039_state *state,
+				const enum zl10039_reg_addr reg,
+				const u8 val)
+{
+	return zl10039_write(state, reg, &val, 1);
+}
+
+static int zl10039_init(struct dvb_frontend *fe)
+{
+	struct zl10039_state *state = fe->tuner_priv;
+	int ret;
+
+	trace_printk("%s\n", __FUNCTION__);
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+	/* Reset logic */
+	ret = zl10039_writereg(state, GENERAL, 0x40);
+	if (ret < 0) {
+		eprintk("Note: i2c write error normal when resetting the "
+			"tuner\n");
+	}
+	/* Wake up */
+	ret = zl10039_writereg(state, GENERAL, 0x01);
+	if (ret < 0) {
+		eprintk("Tuner power up failed\n");
+		return ret;
+	}
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	return 0;
+}
+
+static int zl10039_sleep(struct dvb_frontend *fe)
+{
+	struct zl10039_state *state = fe->tuner_priv;
+	int ret;
+
+	trace_printk("%s\n", __FUNCTION__);
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = zl10039_writereg(state, GENERAL, 0x80);
+	if (ret < 0) {
+		eprintk("Tuner sleep failed\n");
+		return ret;
+	}
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	return 0;
+}
+
+static int zl10039_set_params(struct dvb_frontend *fe,
+			struct dvb_frontend_parameters *params)
+{
+	struct zl10039_state *state = fe->tuner_priv;
+	u8 buf[6];
+	u8 bf;
+	u32 fbw;
+	u32 div;
+	int ret;
+
+	trace_printk("%s\n", __FUNCTION__);
+	params_printk("Set frequency = %d, symbol rate = %d\n",
+			params->frequency, params->u.qpsk.symbol_rate);
+
+	/* Assumed 10.111 MHz crystal oscillator */
+	/* Cancelled num/den 80 to prevent overflow */
+	div = (params->frequency * 1000) / 126387;
+	fbw = (params->u.qpsk.symbol_rate * 27) / 32000;
+	/* Cancelled num/den 10 to prevent overflow */
+	bf = ((fbw * 5088) / 1011100) - 1;
+
+	/*PLL divider*/
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+	/*Reference divider*/
+	/* Select reference ratio of 80 */
+	buf[2] = 0x1D;
+	/*PLL test modes*/
+	buf[3] = 0x40;
+	/*RF Control register*/
+	buf[4] = 0x6E; /* Bypass enable */
+	/*Baseband filter cutoff */
+	buf[5] = bf;
+
+	/* Open i2c gate */
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+	/* BR = 10, Enable filter adjustment */
+	ret = zl10039_writereg(state, BASE1, 0x0A);
+	if (ret < 0) goto error;
+	/* Write new config values */
+	ret = zl10039_write(state, PLL0, buf, sizeof(buf));
+	if (ret < 0) goto error;
+	/* BR = 10, Disable filter adjustment */
+	ret = zl10039_writereg(state, BASE1, 0x6A);
+	if (ret < 0) goto error;
+
+	zl10039_dump_registers(state);
+	/* Close i2c gate */
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	return 0;
+error:
+	eprintk("Error setting tuner\n");
+	return ret;
+}
+
+static struct dvb_tuner_ops zl10039_ops;
+
+struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
+		const struct zl10039_config *config, struct i2c_adapter *i2c)
+{
+	struct zl10039_state *state = NULL;
+
+	trace_printk("%s\n", __FUNCTION__);
+	state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	state->i2c = i2c;
+	state->config.tuner_address = config->tuner_address;
+
+	/* Open i2c gate */
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+	/* check if this is a valid tuner */
+	if (zl10039_readreg(state, GENERAL, &state->id) < 0) {
+		/* Close i2c gate */
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		goto error;
+	}
+	/* Close i2c gate */
+	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+
+	state->id = state->id & 0x0F;
+	switch (state->id) {
+	case ID_ZL10039:
+		strcpy(fe->ops.tuner_ops.info.name,
+			"Zarlink ZL10039 DVB-S tuner");
+		break;
+	default:
+		eprintk("Chip ID does not match a known type\n");
+		goto error;
+	}
+	memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = state;
+	iprintk("Tuner attached @ i2c address 0x%02x\n", config->tuner_address);
+	return fe;
+error:
+	kfree(state);
+	return NULL;
+}
+
+static int zl10039_release(struct dvb_frontend *fe)
+{
+	struct zl10039_state *state = fe->tuner_priv;
+
+	trace_printk("%s\n", __FUNCTION__);
+	kfree(state);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static struct dvb_tuner_ops zl10039_ops = {
+	.release = zl10039_release,
+	.init = zl10039_init,
+	.sleep = zl10039_sleep,
+	.set_params = zl10039_set_params,
+};
+
+EXPORT_SYMBOL(zl10039_attach);
+
+MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver");
+MODULE_AUTHOR("Jan DaniÃ«l Louw <jd.louw@mweb.co.za>");
+MODULE_LICENSE("GPL");
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10039.h v4l-dvb/linux/drivers/media/dvb/frontends/zl10039.h
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10039.h	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl10039.h	2007-12-31 15:04:12.000000000 +0100
@@ -0,0 +1,46 @@
+/*
+    Driver for Zarlink ZL10039 DVB-S tuner
+
+    Copyright (C) 2007 Jan Daniël Louw <jd.louw@mweb.co.za>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef ZL10039_H
+#define ZL10039_H
+
+struct zl10039_config
+{
+	/* tuner's i2c address */
+	u8 tuner_address;
+};
+
+#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
+	    && defined(MODULE))
+struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
+					const struct zl10039_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
+					const struct zl10039_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ZL10039 */
+
+#endif /* ZL10039_H */
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10039_priv.h v4l-dvb/linux/drivers/media/dvb/frontends/zl10039_priv.h
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10039_priv.h	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl10039_priv.h	2007-12-31 15:04:12.000000000 +0100
@@ -0,0 +1,121 @@
+/*
+ *  Driver for Zarlink ZL10039 DVB-S tuner
+ *
+ *  Copyright 2007 Jan DaniÃ«l Louw <jd.louw@mweb.co.za>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef DVB_FRONTENDS_ZL10039_PRIV
+#define DVB_FRONTENDS_ZL10039_PRIV
+
+/* Trace function calls */
+#define DEBUG_CALL_TRACE	0
+/* Trace read/write function calls - information overload */
+#define DEBUG_IO_TRACE		0
+/* Print register values at critical points */
+#define DEBUG_DUMP_REGISTERS	0
+/* Print important params passed to functions */
+#define DEBUG_PRINT_PARAMS	0
+
+#if DEBUG_CALL_TRACE
+	#define trace_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " args)
+#else
+	#define trace_printk(args...)
+#endif
+
+#if DEBUG_IO_TRACE
+	#define io_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " args)
+#else
+	#define io_printk(args...)
+#endif
+
+#if DEBUG_PRINT_PARAMS
+	#define params_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " \
+						args)
+#else
+	#define params_printk(args...)
+#endif
+
+#define eprintk(args...) printk(KERN_ERR "tuner: zl10039: " args)
+#define iprintk(args...) printk(KERN_INFO "tuner: zl10039: " args)
+
+enum zl10039_model_id {
+	ID_ZL10039 = 1
+};
+
+struct zl10039_state {
+	struct i2c_adapter *i2c;
+	struct zl10039_config config;
+	u8 id;
+};
+
+enum zl10039_reg_addr {
+	PLL0 = 0,
+	PLL1,
+	PLL2,
+	PLL3,
+	RFFE,
+	BASE0,
+	BASE1,
+	BASE2,
+	LO0,
+	LO1,
+	LO2,
+	LO3,
+	LO4,
+	LO5,
+	LO6,
+	GENERAL
+};
+
+#if DEBUG_DUMP_REGISTERS || DEBUG_IO_TRACE
+static const char *zl10039_reg_names[] = {
+	"PLL_0", "PLL_1", "PLL_2", "PLL_3",
+	"RF_FRONT_END", "BASE_BAND_0", "BASE_BAND_1", "BASE_BAND_2",
+	"LOCAL_OSC_0", "LOCAL_OSC_1", "LOCAL_OSC_2", "LOCAL_OSC_3",
+	"LOCAL_OSC_4", "LOCAL_OSC_5", "LOCAL_OSC_6", "GENERAL"
+};
+#endif
+
+#if DEBUG_DUMP_REGISTERS
+static int zl10039_read(const struct zl10039_state *state,
+			const enum zl10039_reg_addr reg, u8 *buf,
+			const size_t count);
+
+static void zl10039_dump_registers(const struct zl10039_state *state)
+{
+	u8 buf[16];
+	int ret;
+	u8 reg;
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10039_read(state, PLL0, buf, sizeof(buf));
+	if (ret < 0) return;
+	for (reg = PLL0; reg <= GENERAL; reg += 4) {
+		printk(KERN_DEBUG "%03x: [%02x %13s] [%02x %13s] [%02x %13s] "
+			"[%02x %13s]\n", reg, buf[reg], zl10039_reg_names[reg],
+			buf[reg+1], zl10039_reg_names[reg+1], buf[reg+2],
+			zl10039_reg_names[reg+2], buf[reg+3],
+			zl10039_reg_names[reg+3]);
+	}
+}
+#else
+static inline void zl10039_dump_registers(const struct zl10039_state *state) {}
+#endif /* DEBUG_DUMP_REGISTERS */
+
+#endif /* DVB_FRONTENDS_ZL10039_PRIV */
+
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl1003x.c v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.c
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl1003x.c	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.c	2008-01-13 00:50:48.000000000 +0100
@@ -0,0 +1,310 @@
+/**
+ * Driver for Zarlink zl1003x DVB-S silicon tuner
+ *
+ * Copyright (C) 2006,2007 Tino Reichardt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **
+ * This driver is currently for these two silicon tuners:
+ * - zl10036 (40pin, FTA)
+ * - zl10038 (40pin, FTA with DVB-S2)
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "zl1003x.h"
+
+static int debug = 0;
+#define dprintk(args...) \
+	do { if (debug) printk(KERN_DEBUG "zl1003x: " args); } while (0)
+
+struct zl1003x_priv {
+	int i2c_address;
+	struct i2c_adapter *i2c;
+	u32 frequency;
+	u8 type:3;
+	u8 has_loopthrough:1;
+};
+
+static int zl1003x_read_status(struct dvb_frontend *fe)
+{
+	struct zl1003x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg[2];
+	u8 buf1[1] = { 0 };
+	u8 buf2[1];
+
+	msg[0].addr = priv->i2c_address;
+	msg[0].flags = 0;
+	msg[0].buf = buf1;
+	msg[0].len = 1;
+
+	msg[1].addr = priv->i2c_address;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf2;
+	msg[1].len = 1;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_ERR "%s: i2c error a addr=%02x\n",
+			__FUNCTION__, priv->i2c_address);
+		return -EIO;
+	}
+
+	if (debug)
+		dprintk("R(status): %02x, addr=%02x\n", buf2[0], priv->i2c_address);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return buf2[0];
+}
+
+static int zl1003x_write(struct dvb_frontend *fe, u8 *str, u8 count)
+{
+	struct zl1003x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg[1];
+	u8 reg=0;
+	int ret;
+
+
+	/* address validation */
+	     if ((str[0] & 0x80) == 0x00) reg=2;
+	else if ((str[0] & 0xc0) == 0x80) reg=4;
+	else if ((str[0] & 0xf0) == 0xc0) reg=6;
+	else if ((str[0] & 0xf0) == 0xd0) reg=8;
+	else if ((str[0] & 0xf0) == 0xe0) reg=10;
+	else if ((str[0] & 0xf0) == 0xf0) reg=12;
+	else {
+		printk(KERN_ERR "%s: invalid data:%02x\n", __FUNCTION__, str[0]);
+		return -EINVAL;
+	}
+
+	msg[0].addr = priv->i2c_address;
+	msg[0].flags = 0;
+	msg[0].buf = str;
+	msg[0].len = count;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+
+	if (ret != 1) {
+		printk(KERN_ERR "%s: i2c error, ret=%d\n", __FUNCTION__, ret);
+		return -EIO;
+	}
+
+	if (debug) {
+		dprintk("W(%d):", reg);
+		{
+			int i;
+			for (i=0; i<count; i++) {
+				printk(" %02x", str[i]);
+			}
+			printk("\n");
+		}
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int zl1003x_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	dprintk("%s\n", __FUNCTION__);
+
+	return 0;
+}
+
+static int zl1003x_sleep(struct dvb_frontend *fe)
+{
+	u8 buf[2] = { 0xf0, 0x80 };
+
+	dprintk("%s\n", __FUNCTION__);
+
+	return zl1003x_write(fe, buf, 2);
+}
+
+/**
+ * register map of the ZL10036/ZL10038
+ *
+ * reg[default] content
+ *  2[0x00]:   0 | N14 | N13 | N12 | N11 | N10 |  N9 |  N8
+ *  3[0x00]:  N7 |  N6 |  N5 |  N4 |  N3 |  N2 |  N1 |  N0
+ *  4[0x80]:   1 |   0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN
+ *  5[0x00]:  P0 |  C1 |  C0 |  R4 |  R3 |  R2 |  R1 |  R0
+ *  6[0xc0]:   1 |   1 |   0 |   0 | RSD |   0 |   0 |   0
+ *  7[0x20]:  P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 |   0
+ *  8[0xdb]:   1 |   1 |   0 |   1 |   0 |  CC |   1 |   1
+ *  9[0x30]: VSD |  V2 |  V1 |  V0 |  S3 |  S2 |  S1 |  S0
+ * 10[0xe1]:   1 |   1 |   1 |   0 |   0 | LS2 | LS1 | LS0
+ * 11[0xf5]:  WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE
+ * 12[0xf0]:   1 |   1 |   1 |   1 |   0 |   0 |   0 |   0
+ * 13[0x28]:  PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR |  TL
+ */
+
+static int zl1003x_set_params(struct dvb_frontend *fe, struct
+		dvb_frontend_parameters *params)
+{
+	struct zl1003x_priv *priv = fe->tuner_priv;
+	u8 br, bf, buf[12];
+	u32 div, fbw;
+	int ret;
+
+	dprintk("%s\n", __FUNCTION__);
+	dprintk("Set frequency = %d, symbol rate = %d\n",
+			params->frequency, params->u.qpsk.symbol_rate);
+
+	/* assumed 10.111 MHz crystal oscillator */
+	div = (params->frequency * 1000) / 90276; /* 90,27 KHz r=112 */
+	fbw = (params->u.qpsk.symbol_rate * 27) / 32000; /* in KHz */
+	if (fbw < 28200) {
+	  br = 17;
+	} else {
+	  br = (10111 * 63 * 1000) / (fbw * 1257);
+	}
+	bf = (fbw * br * 1257) / (10111 * 1000) - 1;
+
+	dprintk("fbw=%d, div=%d, bf=%d br=%d\n", fbw, div, bf, br);
+
+	/* wake up */
+	buf[0] = 0xf0;      /* 12: testing disabled */
+	buf[1] = (br << 2); /* 13: br=x clr=0 tl=0 */
+	ret = zl1003x_write(fe, buf, 2);
+	if (ret < 0) goto error;
+
+	/* re-enable resistor switching */
+	buf[0] = 0xc0;      /* 6: rsd=0 */
+	buf[1] = (bf << 1); /* 7: bf=x */
+	ret = zl1003x_write(fe, buf, 2);
+	if (ret < 0) goto error;
+
+	/* PLL divider and br */
+	buf[0] = (div >> 8) & 0x7f; /* 2: pll */
+	buf[1] = (div >> 0) & 0xff; /* 3: pll */
+	buf[2] = 0xf0;      /* 12: testing disabled */
+	buf[3] = (br << 2); /* 13: br=x */
+
+	/* setting of r etc ... */
+	{
+	u8 ba=1, bg=1, c=1;
+	buf[4] = 0x80 | (ba << 3) | (bg << 1); /* 4: rfg=0 ba=x bg=x */
+	buf[5] = 0x1d | (c << 5);              /* 5: c=x r=112(1+4+8+16) */
+        buf[6] = 0xd3;   /*  6: from datasheet */
+        buf[7] = 0x40;   /*  7: from datasheet */
+        buf[8] = 0xe3;   /* 10: from datasheet */
+        buf[9] = 0x5b;   /* 11: from datasheet */
+        buf[10] = 0xe3;  /* 10: from datasheet */
+        buf[11] = 0xf9;  /* 11: from datasheet */
+	if (!priv->has_loopthrough) buf[0] |= 0x01;
+	ret = zl1003x_write(fe, buf, 12);
+	if (ret < 0) goto error;
+	}
+	
+	/* disable resistor switching */
+	udelay(60);
+	buf[0] = 0xc8;      /* 6: rsd=1 */
+	buf[1] = (bf << 1); /* 7: bf=x */
+	ret = zl1003x_write(fe, buf, 2);
+	if (ret < 0) goto error;
+
+	zl1003x_read_status(fe);
+
+	return 0;
+error:
+	printk("error setting tuner!");
+	return ret;
+}
+
+static int zl1003x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct zl1003x_priv *priv = fe->tuner_priv;
+
+	*frequency = priv->frequency;
+
+	return 0;
+}
+
+static struct dvb_tuner_ops zl1003x_tuner_ops = {
+	.info = {
+		.name = "Zarlink ZL1003X",
+		.frequency_min = 950000,
+		.frequency_max = 2150000
+	},
+	.release = zl1003x_release,
+	.sleep = zl1003x_sleep,
+	.set_params = zl1003x_set_params,
+	.get_frequency = zl1003x_get_frequency,
+};
+
+struct dvb_frontend *zl1003x_attach(struct dvb_frontend *fe,
+	const struct zl1003x_config *config, struct i2c_adapter *i2c)
+{
+	struct zl1003x_priv *priv = NULL;
+	int ret;
+
+	priv = kzalloc(sizeof(struct zl1003x_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->has_loopthrough = config->has_loopthrough;
+	priv->i2c_address = config->tuner_address;
+	priv->type = config->tuner_type;
+	priv->i2c = i2c;
+
+	memcpy(&fe->ops.tuner_ops, &zl1003x_tuner_ops, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = priv;
+
+	switch (priv->type) {
+	case ZL1003X_TYPE_ZL10036:
+		strcpy(fe->ops.tuner_ops.info.name, "Zarlink ZL10036");
+		break;
+	case ZL1003X_TYPE_ZL10038:
+		strcpy(fe->ops.tuner_ops.info.name, "Zarlink ZL10038");
+		break;
+	default:
+		printk(KERN_WARNING "%s: Warning, unsupported silicon tuner!\n",
+			__FUNCTION__);
+		goto error;
+	}
+
+	ret = zl1003x_read_status(fe);
+	if (ret < 0) {
+		printk("%s: tuner initialization failed\n", __FUNCTION__);
+		goto error;
+	}
+
+	printk("%s: tuner initialization (0x%02x) ok\n", __FUNCTION__, priv->i2c_address);
+
+	return fe;
+error:
+	zl1003x_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL(zl1003x_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB ZL1003X driver");
+MODULE_AUTHOR("Tino Reichardt");
+MODULE_LICENSE("GPL");
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl1003x.h v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.h
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl1003x.h	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.h	2007-12-31 15:11:34.000000000 +0100
@@ -0,0 +1,57 @@
+/**
+ * Driver for Zarlink ZL10036 DVB-S silicon tuner
+ *
+ * Copyright (C) 2006 Tino Reichardt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DVB_ZL1003X_H
+#define DVB_ZL1003X_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a zl10036 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config configuration of tuner_address, tuner_type and so on
+ * @param i2c i2c adapter to use.
+ * @return FE pointer on success, NULL on failure.
+ */
+
+struct zl1003x_config
+{
+	u8 tuner_address;
+	u8 tuner_type:3;
+	u8 has_loopthrough:1;
+};
+
+#define ZL1003X_TYPE_ZL10036 1
+#define ZL1003X_TYPE_ZL10038 2
+
+#if defined(CONFIG_DVB_ZL1003X) || (defined(CONFIG_DVB_ZL1003X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* zl1003x_attach(struct dvb_frontend *fe,
+	const struct zl1003x_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* zl1003x_attach(struct dvb_frontend *fe,
+	const struct zl1003x_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* DVB_ZL1003X_H */
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10313.c v4l-dvb/linux/drivers/media/dvb/frontends/zl10313.c
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10313.c	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl10313.c	2008-01-12 21:27:16.000000000 +0100
@@ -0,0 +1,572 @@
+/*
+ *  Driver for Zarlink ZL10313 DVB-S demodulator
+ *
+ *  Copyright 2007 Jan DaniÃ«l Louw <jd.louw@mweb.co.za>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/dvb/frontend.h>
+
+#include "dvb_frontend.h"
+#include "zl10313.h"
+#include "zl10313_priv.h"
+
+
+static int zl10313_read(const struct zl10313_state *state,
+			const enum zl10313_reg_addr reg,
+			u8 *buf, const size_t count)
+{
+	struct i2c_msg msg[2];
+	u8 regbuf[1] = { reg };
+	int i;
+
+	io_printk("%s\n", __FUNCTION__);
+	/* Write address to read */
+	msg[0].addr = state->config->demod_address;
+	msg[0].flags = 0;
+	msg[0].buf = regbuf;
+	msg[0].len = 1;
+	/* Read count bytes */
+	msg[1].addr = state->config->demod_address;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = buf;
+	msg[1].len = count;
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		eprintk("%s: i2c read error\n", __FUNCTION__);
+		return -EREMOTEIO;
+	}
+	for (i = 0; i < count; i++) {
+		io_printk("R[%s] = 0x%x\n", zl10313_reg_names[reg + i], buf[i]);
+	}
+	return 0;
+}
+
+static int zl10313_write(struct zl10313_state *state,
+			const enum zl10313_reg_addr reg, const void *src,
+			const size_t count)
+{
+	u8 buf[count + 1];
+	struct i2c_msg msg;
+	int i;
+
+	io_printk("%s\n", __FUNCTION__);
+	for (i = 0; i < count; i++) {
+		io_printk("R[%s] = 0x%x\n", zl10313_reg_names[reg + i], buf[i]);
+	}
+	buf[0] = reg;
+	memcpy(&buf[1], src, count);
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = count + 1;
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		eprintk("%s: i2c write error\n", __FUNCTION__);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static inline int zl10313_readreg(struct zl10313_state *state,
+				const enum zl10313_reg_addr reg, u8 *val)
+{
+	return zl10313_read(state, reg, val, 1);
+}
+
+static inline int zl10313_writereg(struct zl10313_state *state,
+				const enum zl10313_reg_addr reg, const u8 val)
+{
+	return zl10313_write(state, reg, &val, 1);
+}
+
+static inline u32 zl10313_div(u32 a, u32 b)
+{
+	return (a + (b / 2)) / b;
+}
+
+static int zl10313_read_status(struct dvb_frontend *fe, fe_status_t *s)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 status[3];
+
+	trace_printk("%s\n", __FUNCTION__);
+	*s = 0;
+	ret = zl10313_read(state, QPSK_STAT_H, status, sizeof(status));
+	if (ret < 0) return ret;
+	if (status[0] & 0xc0)
+		*s |= FE_HAS_SIGNAL;    /* signal noise ratio */
+	if (status[0] & 0x04)
+		*s |= FE_HAS_CARRIER;   /* qpsk carrier lock */
+	if (status[2] & 0x02)
+		*s |= FE_HAS_VITERBI;   /* viterbi lock */
+	if (status[2] & 0x04)
+		*s |= FE_HAS_SYNC;      /* byte align lock */
+	if (status[0] & 0x01)
+		*s |= FE_HAS_LOCK;      /* qpsk lock */
+
+	return 0;
+}
+
+/* Reports only Reed-Solomon error count (Viterbi BER) */
+/* IMPROVEMENT: Implement Viterbi error count (QPSK BER), a bit of a problem
+		without IRQs? */
+/* Viterbi BER = RS_BERCNT / (dt * CR * 2 * SR) */
+static int zl10313_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3];
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_read(state, RS_BERCNT_H, buf, 3);
+	if (ret < 0) return ret;
+	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]);
+	return 0;
+}
+
+/* Signal strength a number out of 1024 */
+static int zl10313_read_signal_strength(struct dvb_frontend *fe,
+					u16 * signal_strength)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[3];
+	u16 agc;
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_read(state, AGC_H, buf, sizeof(buf));
+	if (ret < 0) return ret;
+	agc = (buf[0] << 2) | (buf[1] >> 6);
+	*signal_strength = agc;
+	return 0;
+}
+
+/* Holds for Eb/No between 0 and 12 dB */
+static int zl10313_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_read(state, M_SNR_H, buf, sizeof(buf));
+	if (ret < 0) return ret;
+	*snr = (13312 - (((buf[0] & 0x7f) << 8) | buf[1])) / 683;
+	return 0;
+}
+
+/* Block error rate = (ucblocks * 1632) / (dt * SR * 2 * CR) */
+static int zl10313_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_read(state, RS_UBC_H, buf, sizeof(buf));
+	if (ret < 0) return ret;
+	*ucblocks = (buf[0] << 8) | buf[1];
+	return 0;
+}
+
+static int zl10313_get_inversion(struct zl10313_state *state,
+		fe_spectral_inversion_t *i)
+{
+	int ret;
+	u8 vit_mode;
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_readreg(state, VIT_MODE, &vit_mode);
+	if (ret < 0) return ret;
+	*i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
+	return 0;
+}
+
+static int zl10313_get_symbol_rate(struct zl10313_state *state, u32 *sr)
+{
+	int ret;
+	u16 monitor;
+	u8 buf[2];
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_writereg(state, MON_CTRL, 0x03);
+	if (ret < 0) return ret;
+	ret = zl10313_read(state, MONITOR_H, buf, sizeof(buf));
+	if (ret < 0) return ret;
+	monitor = (buf[0] << 8) | buf[1];
+	/* SR = monitor * 1000000 / 1024 */
+	*sr = zl10313_div(monitor * 15625, 16);
+	return 0;
+}
+
+static int zl10313_get_code_rate(struct zl10313_state *state,
+					fe_code_rate_t *cr)
+{
+	const fe_code_rate_t fec_tab[8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6,
+			FEC_6_7, FEC_7_8, FEC_AUTO, FEC_AUTO };
+	int ret;
+	u8 fec_status;
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_readreg(state, FEC_STATUS, &fec_status);
+	if (ret < 0) return ret;
+	*cr = fec_tab[(fec_status >> 4) & 0x07];
+	return 0;
+}
+
+static int zl10313_get_frontend(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_get_inversion(state, &p->inversion);
+	if (ret < 0) return ret;
+	ret = zl10313_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
+	if (ret < 0) return ret;
+	ret = zl10313_get_code_rate(state, &p->u.qpsk.fec_inner);
+	if (ret < 0) return ret;
+	p->frequency = state->prev_frequency;
+	return 0;
+}
+
+static int zl10313_set_frontend(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[5];
+	u16 sr;
+	const u8 fec_tab[10] = { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10,
+				0x20, 0x3f, 0x3f };
+	const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
+
+	trace_printk("%s\n", __FUNCTION__);
+	params_printk("Setting freq: %d, fec: %s, inversion: %s\n",
+		p->frequency, fec_str[p->u.qpsk.fec_inner],
+		inv_str[p->inversion]);
+
+	if ((p->frequency < fe->ops.info.frequency_min) ||
+		(p->frequency > fe->ops.info.frequency_max)) return -EINVAL;
+
+	if ((p->inversion < INVERSION_OFF) || (p->inversion > INVERSION_AUTO))
+		return -EINVAL;
+
+	if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+		(p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
+		return -EINVAL;
+
+	if ((p->u.qpsk.fec_inner < FEC_NONE) ||
+		(p->u.qpsk.fec_inner > FEC_AUTO)) return -EINVAL;
+
+	if ((p->u.qpsk.fec_inner == FEC_4_5) ||
+		(p->u.qpsk.fec_inner == FEC_8_9)) return -EINVAL;
+
+	/* Set the tuner up first */
+	fe->ops.tuner_ops.set_params(fe, p);
+
+	/* sr = SR * 256 / 1000000 */
+	sr = zl10313_div(p->u.qpsk.symbol_rate * 4, 15625);
+	/* SYM_RATE */
+	buf[0] = (sr >> 8) & 0x3f;
+	buf[1] = (sr >> 0) & 0xff;
+	/* VIT_MODE */
+	buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner];
+	/* QPSK_CTRL */
+	buf[3] = 0x40; /* swap I and Q before QPSK demodulation */
+	if (p->u.qpsk.symbol_rate < 10000000)
+		buf[3] |= 0x04; /* use afc mode */
+	/* GO */
+	buf[4] = 0x01;
+
+	ret = zl10313_write(state, SYM_RATE_H, buf, sizeof(buf));
+	if (ret < 0) {
+		eprintk("Demodulator failed setup\n");
+		return ret;
+	}
+	state->prev_frequency = p->frequency;
+	zl10313_dump_registers(state);
+
+	return 0;
+}
+
+static int zl10313_sleep(struct dvb_frontend *fe)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 config;
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_readreg(state, CONFIG, &config);
+	if (ret < 0) return ret;
+	/* enter standby */
+	ret = zl10313_writereg(state, CONFIG, config & 0x7f);
+	if (ret < 0) return ret;
+	return 0;
+}
+
+static int zl10313_init(struct dvb_frontend *fe)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 buf[2];
+
+	trace_printk("%s\n", __FUNCTION__);
+	/* Set up for QPSK DVB-S with 10MHz crystal ref */
+	ret = zl10313_writereg(state, CONFIG, 0x8c);
+	if (ret < 0) return ret;
+	/* Wait 150 us to settle */
+	udelay(150);
+	/* Full reset */
+	ret = zl10313_writereg(state, RESET, 0x80);
+	if (ret < 0) return ret;
+	/* Crucial for correct operation - differs from mt312 datasheet */
+	ret = zl10313_writereg(state, GPP_CTRL, 0x80);
+	if (ret < 0) return ret;
+	/* Crucial for correct operation - unknown register in zl10313 */
+	/* Don't know what this register is for in the zl10313 */
+	ret = zl10313_writereg(state, VIT_ERRPER_M, 0x00);
+	if (ret < 0) return ret;
+	buf[0] = 182;
+	buf[1] = zl10313_div(10111000, 88000);
+	/*Set DISECQ ratio for 22KHz tone */
+	ret = zl10313_write(state, SYS_CLK, buf, sizeof(buf));
+	if (ret < 0) return ret;
+	/* Supposed to set register 49 to value 50 - can't see any difference */
+	ret = zl10313_writereg(state, SNR_THS_HIGH, 50);
+	if (ret < 0) return ret;
+
+	zl10313_dump_registers(state);
+
+	return 0;
+}
+
+static int zl10313_send_master_cmd(struct dvb_frontend *fe,
+				struct dvb_diseqc_master_cmd *c)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	int ret;
+	u8 diseqc_mode;
+
+	trace_printk("%s\n", __FUNCTION__);
+	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) return -EINVAL;
+
+	ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0) return ret;
+
+	ret = zl10313_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
+	if (ret < 0) return ret;
+
+	ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) |
+				((c->msg_len - 1) << 3) | 0x04);
+	if (ret < 0) return ret;
+
+	msleep(100);
+
+	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
+	if (c->msg[0] & 0x02) {
+		ret = zl10313_writereg(state, DISEQC_MODE, diseqc_mode & 0x40);
+		if (ret < 0) return ret;
+	}
+	return 0;
+}
+
+static int zl10313_send_burst(struct dvb_frontend *fe,
+				const fe_sec_mini_cmd_t c)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	const u8 mini_tab[2] = { 0x02, 0x03 };
+	int ret;
+	u8 diseqc_mode;
+
+	trace_printk("%s\n", __FUNCTION__);
+	params_printk("Set mini burst %s (enum %d)\n",  mini_cmd_name[c], c);
+	if (c > SEC_MINI_B) return -EINVAL;
+	ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0) return ret;
+	ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) |
+				mini_tab[c]);
+	if (ret < 0) return ret;
+	return 0;
+}
+
+static int zl10313_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	const u8 tone_tab[2] = { 0x01, 0x00 };
+	int ret;
+	u8 diseqc_mode;
+
+	trace_printk("%s\n", __FUNCTION__);
+	params_printk("Set tone %s (enum %d)\n", tone_name[tone], tone);
+	if (tone > SEC_TONE_OFF) return -EINVAL;
+	ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0) return ret;
+	ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) |
+				tone_tab[tone]);
+	if (ret < 0) return ret;
+	return 0;
+}
+
+static int zl10313_set_voltage(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
+	int ret;
+	u8 diseqc_mode;
+
+	trace_printk("%s\n", __FUNCTION__);
+	params_printk("Set voltage %s (enum %d)\n", volt_name[voltage],
+			voltage);
+	if (voltage > SEC_VOLTAGE_OFF) return -EINVAL;
+	ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0) return ret;
+	ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x07) |
+				volt_tab[voltage]);
+	if (ret < 0) return ret;
+	return 0;
+}
+
+static void zl10313_release(struct dvb_frontend *fe)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+
+	trace_printk("%s\n", __FUNCTION__);
+	kfree(state);
+}
+
+static int zl10313_get_tune_settings(struct dvb_frontend *fe,
+				struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 100;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static int zl10313_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct zl10313_state *state = fe->demodulator_priv;
+	u8 gpp_ctrl;
+	int ret;
+
+	trace_printk("%s,\n", __FUNCTION__);
+	params_printk("Switching %d\n", enable);
+	ret = zl10313_readreg(state, GPP_CTRL, &gpp_ctrl);
+	if (ret < 0) return ret;
+	if (enable) {
+		return zl10313_writereg(state, GPP_CTRL, gpp_ctrl | 0x40);
+	} else {
+		return zl10313_writereg(state, GPP_CTRL, gpp_ctrl & ~0x40);
+	}
+}
+
+
+static struct dvb_frontend_ops zl10313_ops;
+
+struct dvb_frontend * zl10313_attach(const struct zl10313_config *config,
+					struct i2c_adapter *i2c)
+{
+	struct zl10313_state *state = NULL;
+
+	trace_printk("%s\n", __FUNCTION__);
+
+	state = kmalloc(sizeof(struct zl10313_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->frontend.ops, &zl10313_ops,
+		sizeof(struct dvb_frontend_ops));
+
+	/* check if this is a valid demodulator */
+	if (zl10313_readreg(state, ID, &state->id) < 0) goto error;
+
+	switch (state->id) {
+	case ID_ZL10312:
+		strcpy(state->frontend.ops.info.name, "Zarlink ZL10312 DVB-S");
+		break;
+	case ID_ZL10313:
+		strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
+		break;
+	default:
+		eprintk("Chip ID does not match a known type\n");
+		goto error;
+	}
+	state->frontend.demodulator_priv = state;
+	iprintk("Demodulator attached @ i2c address 0x%02x\n",
+		config->demod_address);
+
+	zl10313_dump_registers(state);
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops zl10313_ops = {
+
+	.info = {
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 125,      /* kHz for QPSK frontends */
+		.frequency_tolerance	= 29500,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 |
+			FE_CAN_QPSK | FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO |
+			FE_CAN_RECOVER
+	},
+
+	.release = zl10313_release,
+
+	.init = zl10313_init,
+	.sleep = zl10313_sleep,
+
+	.set_frontend = zl10313_set_frontend,
+	.get_frontend = zl10313_get_frontend,
+	.get_tune_settings = zl10313_get_tune_settings,
+
+	.read_status = zl10313_read_status,
+	.read_ber = zl10313_read_ber,
+	.read_signal_strength = zl10313_read_signal_strength,
+	.read_snr = zl10313_read_snr,
+	.read_ucblocks = zl10313_read_ucblocks,
+
+	.diseqc_send_master_cmd = zl10313_send_master_cmd,
+	.diseqc_send_burst = zl10313_send_burst,
+	.set_voltage = zl10313_set_voltage,
+	.set_tone = zl10313_set_tone,
+	.i2c_gate_ctrl = zl10313_i2c_gate_ctrl,
+
+};
+
+MODULE_DESCRIPTION("Zarlink ZL10313 DVB-S demodulator driver");
+MODULE_AUTHOR("Jan DaniÃ«l Louw <jd.louw@mweb.co.za>");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(zl10313_attach);
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10313.h v4l-dvb/linux/drivers/media/dvb/frontends/zl10313.h
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10313.h	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl10313.h	2007-12-31 15:04:12.000000000 +0100
@@ -0,0 +1,47 @@
+/*
+    Driver for Zarlink ZL10313 DVB-S demodulator
+
+    Copyright (C) 2007 Jan DaniÃ«l Louw <jd.louw@mweb.co.za>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef ZL10313_H
+#define ZL10313_H
+
+
+struct zl10313_config
+{
+	/* demodulator's i2c address */
+	u8 demod_address;
+};
+
+
+#if defined(CONFIG_DVB_ZL10313) || (defined(CONFIG_DVB_ZL10313_MODULE) && \
+defined(MODULE))
+struct dvb_frontend * zl10313_attach(const struct zl10313_config *config,
+					struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend * zl10313_attach(
+					const struct zl10313_config *config,
+					struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ZL10313 */
+
+#endif /* ZL10313_H */
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10313_priv.h v4l-dvb/linux/drivers/media/dvb/frontends/zl10313_priv.h
--- v4l-dvb.20071229/linux/drivers/media/dvb/frontends/zl10313_priv.h	1970-01-01 01:00:00.000000000 +0100
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl10313_priv.h	2008-01-12 21:30:58.000000000 +0100
@@ -0,0 +1,275 @@
+/*
+    Driver for Zarlink ZL10313 DVB-S Frontend
+
+    Copyright (C) 2007 Jan DaniÃ«l Louw <jd.louw@mweb.co.za>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef DVB_FRONTENDS_ZL10313_PRIV
+#define DVB_FRONTENDS_ZL10313_PRIV
+
+/* Trace function calls */
+#define DEBUG_CALL_TRACE	0
+/* Trace read/write function calls - information overload */
+#define DEBUG_IO_TRACE		0
+/* Print register values at critical points */
+#define DEBUG_DUMP_REGISTERS	0
+/* Print important params passed to functions */
+#define DEBUG_PRINT_PARAMS	1
+
+#if DEBUG_CALL_TRACE
+	#define trace_printk(args...) printk(KERN_DEBUG "demodulator: " \
+						"zl10313: " args)
+#else
+	#define trace_printk(args...)
+#endif
+
+#if DEBUG_IO_TRACE
+	#define io_printk(args...) printk(KERN_DEBUG "demodulator: zl10313: " \
+						args)
+#else
+	#define io_printk(args...)
+#endif
+
+#if DEBUG_PRINT_PARAMS
+	#define params_printk(args...) printk(KERN_DEBUG \
+					"demodulator: zl10313: " args)
+#else
+	#define params_printk(args...)
+#endif
+
+#define eprintk(args...) printk(KERN_ERR "demodulator: zl10313: " args)
+#define iprintk(args...) printk(KERN_INFO "demodulator: zl10313: " args)
+
+enum zl10313_model_id {
+	ID_VP310 = 1,
+	ID_MT312 = 3,
+	ID_ZL10312 = 4,
+	ID_ZL10313 = 5
+};
+
+struct zl10313_state
+{
+	struct i2c_adapter *i2c;
+	const struct zl10313_config *config;
+	u8 id;
+	u32 prev_frequency; /* Store previously set frequency */
+	struct dvb_frontend frontend;
+};
+
+enum zl10313_reg_addr {
+	QPSK_INT_H = 0,
+	QPSK_INT_M = 1,
+	QPSK_INT_L = 2,
+	FEC_INT = 3,
+	QPSK_STAT_H = 4,
+	QPSK_STAT_L = 5,
+	FEC_STATUS = 6,
+	LNB_FREQ_H = 7,
+	LNB_FREQ_L = 8,
+	M_SNR_H = 9,
+	M_SNR_L = 10,
+	VIT_ERRCNT_H = 11,
+	VIT_ERRCNT_M = 12,
+	VIT_ERRCNT_L = 13,
+	RS_BERCNT_H = 14,
+	RS_BERCNT_M = 15,
+	RS_BERCNT_L = 16,
+	RS_UBC_H = 17,
+	RS_UBC_L = 18,
+	SIG_LEVEL = 19,
+	GPP_CTRL = 20,
+	RESET = 21,
+	DISEQC_MODE = 22,
+	SYM_RATE_H = 23,
+	SYM_RATE_L = 24,
+	VIT_MODE = 25,
+	QPSK_CTRL = 26,
+	GO = 27,
+	IE_QPSK_H = 28,
+	IE_QPSK_M = 29,
+	IE_QPSK_L = 30,
+	IE_FEC = 31,
+	QPSK_STAT_EN = 32,
+	FEC_STAT_EN = 33,
+	SYS_CLK = 34,
+	DISEQC_RATIO = 35,
+	DISEQC_INSTR = 36,
+	FR_LIM = 37,
+	FR_OFF = 38,
+	AGC_CTRL = 39,
+	AGC_INIT = 40,
+	AGC_REF = 41,
+	AGC_MAX = 42,
+	AGC_MIN = 43,
+	AGC_LK_TH = 44,
+	TS_AGC_LK_TH = 45,
+	AGC_PWR_SET = 46,
+	QPSK_MISC = 47,
+	SNR_THS_LOW = 48,
+	SNR_THS_HIGH = 49,
+	TS_SW_RATE = 50,
+	TS_SW_LIM_L = 51,
+	TS_SW_LIM_H = 52,
+	CS_SW_RATE_1 = 53,
+	CS_SW_RATE_2 = 54,
+	CS_SW_RATE_3 = 55,
+	CS_SW_RATE_4 = 56,
+	CS_SW_LIM = 57,
+	TS_LPK = 58,
+	TS_LPK_M = 59,
+	TS_LPK_L = 60,
+	CS_KPROP_H = 61,
+	CS_KPROP_L = 62,
+	CS_KINT_H = 63,
+	CS_KINT_L = 64,
+	QPSK_SCALE = 65,
+	TLD_OUTCLK_TH = 66,
+	TLD_INCLK_TH = 67,
+	FLD_TH = 68,
+	PLD_OUTLK3 = 69,
+	PLD_OUTLK2 = 70,
+	PLD_OUTLK1 = 71,
+	PLD_OUTLK0 = 72,
+	PLD_INLK3 = 73,
+	PLD_INLK2 = 74,
+	PLD_INLK1 = 75,
+	PLD_INLK0 = 76,
+	PLD_ACC_TIME = 77,
+	SWEEP_PAR = 78,
+	STARTUP_TIME = 79,
+	LOSSLOCK_TH = 80,
+	FEC_LOCK_TM = 81,
+	LOSSLOCK_TM = 82,
+	VIT_ERRPER_H = 83,
+	VIT_ERRPER_M = 84,
+	VIT_ERRPER_L = 85,
+	VIT_SETUP = 86,
+	VIT_REF0 = 87,
+	VIT_REF1 = 88,
+	VIT_REF2 = 89,
+	VIT_REF3 = 90,
+	VIT_REF4 = 91,
+	VIT_REF5 = 92,
+	VIT_REF6 = 93,
+	VIT_MAXERR = 94,
+	BA_SETUPT = 95,
+	OP_CTRL = 96,
+	FEC_SETUP = 97,
+	PROG_SYNC = 98,
+	AFC_SEAR_TH = 99,
+	CSACC_DIF_TH = 100,
+	QPSK_LK_CT = 101,
+	QPSK_ST_CT = 102,
+	MON_CTRL = 103,
+	QPSK_RESET = 104,
+	QPSK_TST_CT = 105,
+	QPSK_TST_ST = 106,
+	TEST_R = 107,
+	AGC_H = 108,
+	AGC_M = 109,
+	AGC_L = 110,
+	FREQ_ERR1_H = 111,
+	FREQ_ERR1_M = 112,
+	FREQ_ERR1_L = 113,
+	FREQ_ERR2_H = 114,
+	FREQ_ERR2_L = 115,
+	SYM_RAT_OP_H = 116,
+	SYM_RAT_OP_L = 117,
+	DESEQC2_INT = 118,
+	DISEQC2_STAT = 119,
+	DISEQC2_FIFO = 120,
+	DISEQC2_CTRL1 = 121,
+	DISEQC2_CTRL2 = 122,
+	MONITOR_H = 123,
+	MONITOR_L = 124,
+	TEST_MODE = 125,
+	ID = 126,
+	CONFIG = 127
+};
+
+
+#if DEBUG_PRINT_PARAMS
+	static const char *inv_str[] = {"OFF", "ON", "AUTO"};
+	static const char *fec_str[] = {"NONE", "1/2", "2/3", "3/4", "4/5",
+					"5/6", "6/7", "7/8", "8/9", "AUTO"};
+	static const char *mini_cmd_name[] = {"SEC_MINI_A", "SEC_MINI_B"};
+	static const char *tone_name[] = {"SEC_TONE_ON", "SEC_TONE_OFF"};
+	static const char *volt_name[] = {"SEC_VOLTAGE_13", "SEC_VOLTAGE_18",
+						"SEC_VOLTAGE_OFF"};
+#endif
+
+#if DEBUG_DUMP_REGISTERS || DEBUG_IO_TRACE
+static const char *zl10313_reg_names[] = {
+	"QPSK_INT_H", "QPSK_INT_M", "QPSK_INT_L", "FEC_INT", "QPSK_STAT_H",
+	"QPSK_STAT_L", "FEC_STATUS", "LNB_FREQ_H", "LNB_FREQ_L", "M_SNR_H",
+	"M_SNR_L", "VIT_ERRCNT_H", "VIT_ERRCNT_M", "VIT_ERRCNT_L",
+	"RS_BERCNT_H", "RS_BERCNT_M", "RS_BERCNT_L", "RS_UBC_H", "RS_UBC_L",
+	"SIG_LEVEL", "GPP_CTRL", "RESET", "DISEQC_MODE", "SYM_RATE_H",
+	"SYM_RATE_L", "VIT_MODE", "QPSK_CTRL", "GO", "IE_QPSK_H", "IE_QPSK_M",
+	"IE_QPSK_L", "IE_FEC", "QPSK_STAT_EN", "FEC_STAT_EN", "SYS_CLK",
+	"DISEQC_RATIO", "DISEQC_INSTR", "FR_LIM", "FR_OFF", "AGC_CTRL",
+	"AGC_INIT", "AGC_REF", "AGC_MAX", "AGC_MIN", "AGC_LK_TH",
+	"TS_AGC_LK_TH", "AGC_PWR_SET", "QPSK_MISC", "SNR_THS_LOW",
+	"SNR_THS_HIGH", "TS_SW_RATE", "TS_SW_LIM_L", "TS_SW_LIM_H",
+	"CS_SW_RATE_1", "CS_SW_RATE_2", "CS_SW_RATE_3", "CS_SW_RATE_4",
+	"CS_SW_LIM", "TS_LPK", "TS_LPK_M", "TS_LPK_L", "CS_KPROP_H",
+	"CS_KPROP_L", "CS_KINT_H", "CS_KINT_L", "QPSK_SCALE", "TLD_OUTCLK_TH",
+	"TLD_INCLK_TH", "FLD_TH", "PLD_OUTLK3", "PLD_OUTLK2", "PLD_OUTLK1",
+	"PLD_OUTLK0", "PLD_INLK3", "PLD_INLK2", "PLD_INLK1", "PLD_INLK0",
+	"PLD_ACC_TIME", "SWEEP_PAR", "STARTUP_TIME", "LOSSLOCK_TH",
+	"FEC_LOCK_TM", "LOSSLOCK_TM", "VIT_ERRPER_H", "VIT_ERRPER_M",
+	"VIT_ERRPER_L", "VIT_SETUP", "VIT_REF0", "VIT_REF1", "VIT_REF2",
+	"VIT_REF3", "VIT_REF4", "VIT_REF5", "VIT_REF6", "VIT_MAXERR",
+	"BA_SETUPT", "OP_CTRL", "FEC_SETUP", "PROG_SYNC", "AFC_SEAR_TH",
+	"CSACC_DIF_TH", "QPSK_LK_CT", "QPSK_ST_CT", "MON_CTRL", "QPSK_RESET",
+	"QPSK_TST_CT", "QPSK_TST_ST", "TEST_R", "AGC_H", "AGC_M", "AGC_L",
+	"FREQ_ERR1_H", "FREQ_ERR1_M", "FREQ_ERR1_L", "FREQ_ERR2_H",
+	"FREQ_ERR2_L", "SYM_RAT_OP_H", "SYM_RAT_OP_L", "DESEQC2_INT",
+	"DISEQC2_STAT", "DISEQC2_FIFO", "DISEQC2_CTRL1", "DISEQC2_CTRL2",
+	"MONITOR_H", "MONITOR_L", "TEST_MODE", "ID", "CONFIG", ""
+};
+#endif
+
+#if DEBUG_DUMP_REGISTERS
+static int zl10313_read(const struct zl10313_state *state,
+			const enum zl10313_reg_addr reg, u8 *buf,
+			const size_t count);
+
+static void zl10313_dump_registers(const struct zl10313_state *state)
+{
+	int ret;
+	u8 buf[128];
+	u8 reg ;
+
+	trace_printk("%s\n", __FUNCTION__);
+	ret = zl10313_read(state, QPSK_INT_H, buf, sizeof(buf));
+	if (ret < 0) return;
+	for (reg = QPSK_INT_H; reg <= CONFIG; reg += 4) {
+		printk(KERN_DEBUG "%03x: [%02x %13s] [%02x %13s] [%02x %13s] "
+			"[%02x %13s]\n", reg, buf[reg], zl10313_reg_names[reg],
+			buf[reg+1], zl10313_reg_names[reg+1], buf[reg+2],
+			zl10313_reg_names[reg+2], buf[reg+3],
+			zl10313_reg_names[reg+3]);
+	}
+}
+#else
+static inline void zl10313_dump_registers(const struct zl10313_state *state) {}
+#endif /* DEBUG_DUMP_REGISTERS */
+
+#endif /* DVB_FRONTENDS_ZL10313_PRIV */
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/video/saa7134/Kconfig v4l-dvb/linux/drivers/media/video/saa7134/Kconfig
--- v4l-dvb.20071229/linux/drivers/media/video/saa7134/Kconfig	2007-12-29 22:34:27.000000000 +0100
+++ v4l-dvb/linux/drivers/media/video/saa7134/Kconfig	2007-12-31 15:05:52.000000000 +0100
@@ -37,6 +37,9 @@
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_TDA827X if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10313 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10039 if !DVB_FE_CUSTOMISE
+	select DVB_ZL1003X if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB cards based on the
 	  Philips saa7134 chip.
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134-cards.c v4l-dvb/linux/drivers/media/video/saa7134/saa7134-cards.c
--- v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134-cards.c	2007-12-29 22:34:27.000000000 +0100
+++ v4l-dvb/linux/drivers/media/video/saa7134/saa7134-cards.c	2007-12-31 15:05:36.000000000 +0100
@@ -3269,7 +3269,6 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.tuner_config   = 1,
 		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs         = {{
 			.name = name_tv,
@@ -3601,6 +3600,59 @@
 			.tv     = 1,
 		}},
 	},
+	[SAA7134_BOARD_AVERMEDIA_A700] = {
+		.name           = "Avermedia AVerTV DVB-S Pro (A700)",
+		//.audio_clock    = 0x90909090,
+		.audio_clock	= 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		/* GPIO @ winxp:
+		 *
+		 * SAA7134_GPIO_GPMODE:     80040100   (10000000 00000100 00000001 00000000)
+		 * SAA7134_GPIO_GPSTATUS:   0454fb00   (00000100 01010100 11111011 00000000)
+		 * 
+		 * Linux: gpio is 200fe00
+		 */
+		.inputs         = {
+		{
+			.name 	= name_tv,
+			.vmux 	= 4,
+			.amux 	= 1,
+			.tv   	= 1,
+		},
+		{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = 2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 6,
+			.amux   = 2,
+		}},
+	},
+	[SAA7134_BOARD_VIDEOMATE_S350] = {
+		/* Jan DaniÃ«l Louw <jd.louw@mweb.co.za */
+		.name		= "Compro VideoMate S350/S300",
+		.audio_clock	= 0x00187de7,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg		= SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name	= name_comp1,
+			.vmux	= 0,
+			.amux	= LINE1,
+		},{
+			.name	= name_svideo,
+			.vmux	= 8, /* Not tested */
+			.amux	= LINE1
+		}},
+	},
+
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3615,6 +3667,12 @@
 		.subvendor    = PCI_VENDOR_ID_PHILIPS,
 		.subdevice    = 0x2001,
 		.driver_data  = SAA7134_BOARD_PROTEUS_PRO,
+ 	},{
+ 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa7a1,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A700,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -4372,6 +4430,12 @@
 		.subdevice    = 0x3502,
 		.driver_data  = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc900,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_S350,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4620,10 +4684,14 @@
 		break;
 	case SAA7134_BOARD_AVERMEDIA_M102:
 		/* enable tuner */
-	       dev->has_remote = SAA7134_REMOTE_GPIO;
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
 		break;
+	case SAA7134_BOARD_VIDEOMATE_S350:
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00008000, 0x00008000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
 	}
 	return 0;
 }
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134-dvb.c v4l-dvb/linux/drivers/media/video/saa7134/saa7134-dvb.c
--- v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134-dvb.c	2007-12-29 22:34:27.000000000 +0100
+++ v4l-dvb/linux/drivers/media/video/saa7134/saa7134-dvb.c	2007-12-31 15:05:36.000000000 +0100
@@ -38,6 +38,9 @@
 #include "mt352_priv.h" /* FIXME */
 #include "tda1004x.h"
 #include "nxt200x.h"
+#include "zl10313.h"
+#include "zl10039.h"
+#include "zl1003x.h"
 
 #include "tda10086.h"
 #include "tda826x.h"
@@ -662,7 +665,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
@@ -841,6 +843,27 @@
 };
 
 /* ==================================================================
+ * ZL10313 based DVB-S cards
+ */
+static struct zl10313_config zl10313_compro_s350_config = {
+	.demod_address = 0x0E,
+};
+
+static struct zl10313_config zl10313_avertv_a700_config = {
+	.demod_address = 0x0e, /* Avermedia DVB-S Pro A700-B */
+};
+
+static struct zl10039_config zl10039_compro_s350_config = {
+	.tuner_address = 0x60,
+};
+
+static struct zl1003x_config zl1003x_avertv_a700_config = {
+	.tuner_address = 0x60,
+	.tuner_type = ZL1003X_TYPE_ZL10036,
+	.has_loopthrough = 0,
+};
+
+/* ==================================================================
  * Core code
  */
 
@@ -1044,6 +1067,24 @@
 	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
 		configure_tda827x_fe(dev, &avermedia_super_007_config);
 		break;
+	case SAA7134_BOARD_VIDEOMATE_S350:
+		dev->dvb.frontend = dvb_attach(zl10313_attach,
+				&zl10313_compro_s350_config, &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend = dvb_attach(zl10039_attach,
+			dev->dvb.frontend, &zl10039_compro_s350_config,
+			&dev->i2c_adap);
+		}
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A700:
+		dev->dvb.frontend = dvb_attach(zl10313_attach,
+				&zl10313_avertv_a700_config, &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend = dvb_attach(zl1003x_attach,
+			dev->dvb.frontend, &zl1003x_avertv_a700_config,
+			&dev->i2c_adap);
+		}
+		break;
 	default:
 		wprintk("Huh? unknown DVB card?\n");
 		break;
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134.h v4l-dvb/linux/drivers/media/video/saa7134/saa7134.h
--- v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134.h	2007-12-29 22:34:27.000000000 +0100
+++ v4l-dvb/linux/drivers/media/video/saa7134/saa7134.h	2007-12-31 15:05:29.000000000 +0100
@@ -247,6 +247,8 @@
 #define SAA7134_BOARD_SABRENT_TV_PCB05     115
 #define SAA7134_BOARD_10MOONSTVMASTER3     116
 #define SAA7134_BOARD_AVERMEDIA_SUPER_007  117
+#define SAA7134_BOARD_VIDEOMATE_S350 118
+#define SAA7134_BOARD_AVERMEDIA_A700       119
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134-input.c v4l-dvb/linux/drivers/media/video/saa7134/saa7134-input.c
--- v4l-dvb.20071229/linux/drivers/media/video/saa7134/saa7134-input.c	2007-12-29 22:34:27.000000000 +0100
+++ v4l-dvb/linux/drivers/media/video/saa7134/saa7134-input.c	2007-12-31 15:05:36.000000000 +0100
@@ -260,7 +260,6 @@
 	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
 	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
-	case SAA7134_BOARD_AVERMEDIA_M102:
 		ir_codes     = ir_codes_avermedia;
 		mask_keycode = 0x0007C8;
 		mask_keydown = 0x000010;
@@ -352,6 +351,11 @@
 		mask_keyup   = 0x8000000;
 		polling      = 50; //ms
 		break;
+	case SAA7134_BOARD_VIDEOMATE_S350:
+		ir_codes     = ir_codes_videomate_s350;
+		mask_keycode = 0x003F00;
+		mask_keydown = 0x040000;
+		break;
 	}
 	if (NULL == ir_codes) {
 		printk("%s: Oops: IR config error [card=%d]\n",
diff --exclude-from=MakeDiff-Excludes -urN v4l-dvb.20071229/linux/include/media/ir-common.h v4l-dvb/linux/include/media/ir-common.h
--- v4l-dvb.20071229/linux/include/media/ir-common.h	2007-12-29 22:34:27.000000000 +0100
+++ v4l-dvb/linux/include/media/ir-common.h	2007-12-31 15:06:31.000000000 +0100
@@ -140,6 +140,7 @@
 extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_videomate_s350[IR_KEYTAB_SIZE];
 
 #endif
 
