All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] Add support for PCTV452E.
       [not found] <201105242151.22826.hselasky@c2i.net>
@ 2011-06-01 20:16 ` Mauro Carvalho Chehab
       [not found] ` <4DF399EA.6090508@net1.cc>
  2011-07-23 11:24 ` Steffen Barszus
  2 siblings, 0 replies; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2011-06-01 20:16 UTC (permalink / raw)
  To: Hans Petter Selasky; +Cc: linux-media, Igor M. Liplianin

Em 24-05-2011 16:51, Hans Petter Selasky escreveu:
> NOTES:
> 
> Sources were taken from the following repositorium as of today:
> http://mercurial.intuxication.org/hg/s2-liplianin/
> 

We need Igor's Signed-off-by on his patch. Also, if you're forwarding
a patch made by someone, you need to add a From: with the name of the
original author at the patch body, otherwise it gets the wrong authorship.

However, based on the copyright information inside the driver, it seems that
they're not authored by Igor. So, you need or to get the SOB's from the
original author(s) or to forward the original patches from Igor's tree.

> And depend on the zig-zag fix posted today.
> 
> --HPS
> 
> From 2e184928a71f9463b008434b3f0e676a643fadd9 Mon Sep 17 00:00:00 2001
> From: Hans Petter Selasky <hselasky@c2i.net>
> Date: Tue, 24 May 2011 13:08:11 +0200
> Subject: [PATCH] Add support for PCTV452E.
> 
> Signed-off-by: Hans Petter Selasky <hselasky@c2i.net>
> ---
>  drivers/media/dvb/dvb-usb/Kconfig       |   12 +
>  drivers/media/dvb/dvb-usb/Makefile      |    3 +
>  drivers/media/dvb/dvb-usb/dvb-usb-ids.h |    3 +
>  drivers/media/dvb/dvb-usb/pctv452e.c    | 1454 +++++++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/Makefile    |    1 +
>  drivers/media/dvb/frontends/lnbp22.c    |  140 +++
>  drivers/media/dvb/frontends/lnbp22.h    |   51 ++
>  drivers/media/dvb/ttpci/ttpci-eeprom.c  |   25 +
>  drivers/media/dvb/ttpci/ttpci-eeprom.h  |    1 +
>  9 files changed, 1690 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/dvb/dvb-usb/pctv452e.c
>  create mode 100644 drivers/media/dvb/frontends/lnbp22.c
>  create mode 100644 drivers/media/dvb/frontends/lnbp22.h
> 
> diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
> index c545039..6d725ad 100644
> --- a/drivers/media/dvb/dvb-usb/Kconfig
> +++ b/drivers/media/dvb/dvb-usb/Kconfig
> @@ -250,6 +250,18 @@ config DVB_USB_AF9005
>  	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
>  	  and the TerraTec Cinergy T USB XE (Rev.1)
>  
> +config DVB_USB_PCTV452E
> +	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
> +	depends on DVB_USB
> +	select TTPCI_EEPROM
> +	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
> +	select DVB_STB0899 if !DVB_FE_CUSTOMISE
> +	select DVB_STB6100 if !DVB_FE_CUSTOMISE
> +	help
> +	  Support for external USB adapter designed by Pinnacle,
> +	  shipped under the brand name 'PCTV HDTV Pro USB'.
> +	  Say Y if you own such a device and want to use it.
> +
>  config DVB_USB_AF9005_REMOTE
>  	tristate "Afatech AF9005 default remote control support"
>  	depends on DVB_USB_AF9005
> diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
> index 4bac13d..2497694 100644
> --- a/drivers/media/dvb/dvb-usb/Makefile
> +++ b/drivers/media/dvb/dvb-usb/Makefile
> @@ -73,6 +73,9 @@ obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
>  dvb-usb-af9015-objs = af9015.o
>  obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
>  
> +dvb-usb-pctv452e-objs = pctv452e.o
> +obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
> +
>  dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
>  obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
>  
> diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> index 3a8b744..1c8a241 100644
> --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> @@ -237,6 +237,9 @@
>  #define USB_PID_PCTV_200E				0x020e
>  #define USB_PID_PCTV_400E				0x020f
>  #define USB_PID_PCTV_450E				0x0222
> +#define USB_PID_PCTV_452E				0x021f
> +#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
> +#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
>  #define USB_PID_NEBULA_DIGITV				0x0201
>  #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
>  #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
> diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
> new file mode 100644
> index 0000000..1be24e5
> --- /dev/null
> +++ b/drivers/media/dvb/dvb-usb/pctv452e.c
> @@ -0,0 +1,1454 @@
> +/*
> + * PCTV 452e DVB driver
> + *
> + * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
> + *
> + * TT connect S2-3650-CI Common Interface support, MAC readout
> + * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
> + *
> + * 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.
> + */
> +
> +/* dvb usb framework */
> +#define DVB_USB_LOG_PREFIX "pctv452e"
> +#include "dvb-usb.h"
> +
> +/* Demodulator */
> +#include "stb0899_drv.h"
> +#include "stb0899_reg.h"
> +/* Tuner */
> +#include "stb6100.h"
> +#include "stb6100_cfg.h"
> +/* FE Power */
> +#include "lnbp22.h"
> +
> +#include "dvb_ca_en50221.h"
> +#include "ttpci-eeprom.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
> +
> +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
> +
> +#define ISO_BUF_COUNT      4
> +#define FRAMES_PER_ISO_BUF 4
> +#define ISO_FRAME_SIZE     940
> +#define ISOC_INTERFACE_ALTERNATIVE 3
> +
> +#define SYNC_BYTE_OUT 0xaa
> +#define SYNC_BYTE_IN  0x55
> +
> +/* guessed: (copied from ttusb-budget) */
> +#define PCTV_CMD_RESET 0x15
> +/* command to poll IR receiver */
> +#define PCTV_CMD_IR    0x1b
> +/* command to send I2C  */
> +#define PCTV_CMD_I2C   0x31
> +
> +#define I2C_ADDR_STB0899 (0xd0 >> 1)
> +#define I2C_ADDR_STB6100 (0xc0 >> 1)
> +#define I2C_ADDR_LNBP22  (0x10 >> 1)
> +#define I2C_ADDR_24C16   (0xa0 >> 1)
> +#define I2C_ADDR_24C64   (0xa2 >> 1)
> +
> +
> +/* pctv452e sends us this amount of data for each issued usb-command */
> +#define PCTV_ANSWER_LEN 64
> +/* Wait up to 1000ms for device  */
> +#define PCTV_TIMEOUT 1000
> +
> +
> +#define PCTV_LED_GPIO   STB0899_GPIO01
> +#define PCTV_LED_GREEN  0x82
> +#define PCTV_LED_ORANGE 0x02
> +
> +#define ci_dbg(format, arg...)				\
> +do {							\
> +	if (0)						\
> +		printk (KERN_DEBUG DVB_USB_LOG_PREFIX	\
> +			": " format "\n" , ## arg);	\
> +} while (0)
> +
> +enum {
> +	TT3650_CMD_CI_TEST = 0x40,
> +	TT3650_CMD_CI_RD_CTRL,
> +	TT3650_CMD_CI_WR_CTRL,
> +	TT3650_CMD_CI_RD_ATTR,
> +	TT3650_CMD_CI_WR_ATTR,
> +	TT3650_CMD_CI_RESET,
> +	TT3650_CMD_CI_SET_VIDEO_PORT
> +};
> +
> +
> +static struct stb0899_postproc pctv45e_postproc[] = {
> +	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
> +	{ 0, 0 }
> +};
> +
> +/*
> + * stores all private variables for communication with the PCTV452e DVB-S2
> + */
> +struct pctv452e_state {
> +	struct dvb_ca_en50221 ca;
> +	struct mutex ca_mutex;
> +
> +	u8 c;	   /* transaction counter, wraps around...  */
> +	u8 initialized; /* set to 1 if 0x15 has been sent */
> +};
> +
> +static int
> +tt3650_ci_msg			(struct dvb_usb_device *d,
> +				 u8			cmd,
> +				 u8 *			data,
> +				 unsigned int		write_len,
> +				 unsigned int		read_len)
> +{
> +	struct pctv452e_state *state = (struct pctv452e_state *) d->priv;
> +	u8 buf[64];
> +	u8 id;
> +	unsigned int rlen;
> +	int ret;
> +
> +	BUG_ON (NULL == data && 0 != (write_len | read_len));
> +	BUG_ON (write_len > 64 - 4);
> +	BUG_ON (read_len > 64 - 4);
> +
> +	id = state->c++;
> +
> +	buf[0] = SYNC_BYTE_OUT;
> +	buf[1] = id;
> +	buf[2] = cmd;
> +	buf[3] = write_len;
> +
> +	memcpy (buf + 4, data, write_len);
> +
> +	rlen = (read_len > 0) ? 64 : 0;
> +	ret = dvb_usb_generic_rw (d, buf, 4 + write_len,
> +				  buf, rlen, /* delay_ms */ 0);
> +	if (0 != ret)
> +		goto failed;
> +
> +	ret = -EIO;
> +	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
> +		goto failed;
> +
> +	memcpy (data, buf + 4, read_len);
> +
> +	return 0;
> +
> + failed:
> +	err ("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
> +	     ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
> +
> +	return ret;
> +}
> +
> +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
> +				 u8			cmd,
> +				 u8 *			data,
> +				 unsigned int		write_len,
> +				 unsigned int		read_len)
> +{
> +	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	int ret;
> +
> +	mutex_lock(&state->ca_mutex);
> +	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
> +	mutex_unlock(&state->ca_mutex);
> +
> +	return ret;
> +}
> +
> +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			address)
> +{
> +	u8 buf[3];
> +	int ret;
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = (address >> 8) & 0x0F;
> +	buf[1] = address;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
> +
> +	ci_dbg ("%s %04x -> %d 0x%02x",
> +		__func__, address, ret, buf[2]);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return buf[2];
> +}
> +
> +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			address,
> +				 u8			value)
> +{
> +	u8 buf[3];
> +
> +	ci_dbg("%s %d 0x%04x 0x%02x",
> +		__func__, slot, address, value);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = (address >> 8) & 0x0F;
> +	buf[1] = address;
> +	buf[2] = value;
> +
> +	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
> +}
> +
> +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 u8			address)
> +{
> +	u8 buf[2];
> +	int ret;
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = address & 3;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
> +
> +	ci_dbg("%s 0x%02x -> %d 0x%02x",
> +		__func__, address, ret, buf[1]);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return buf[1];
> +}
> +
> +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 u8			address,
> +				 u8			value)
> +{
> +	u8 buf[2];
> +
> +	ci_dbg("%s %d 0x%02x 0x%02x",
> +		__func__, slot, address, value);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = address;
> +	buf[1] = value;
> +
> +	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
> +}
> +
> +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			enable)
> +{
> +	u8 buf[1];
> +	int ret;
> +
> +	ci_dbg("%s %d %d", __func__, slot, enable);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	enable = !!enable;
> +	buf[0] = enable;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (enable != buf[0]) {
> +		err("CI not %sabled.", enable ? "en" : "dis");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca,
> +				 int			slot)
> +{
> +	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
> +}
> +
> +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca,
> +				 int			slot)
> +{
> +	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
> +}
> +
> +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca,
> +				 int			slot)
> +{
> +	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	u8 buf[1];
> +	int ret;
> +
> +	ci_dbg ("%s %d", __func__, slot);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = 0;
> +
> +	mutex_lock (&state->ca_mutex);
> +
> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
> +	if (0 != ret)
> +		goto failed;
> +
> +	msleep (500);
> +
> +	buf[0] = 1;
> +
> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
> +	if (0 != ret)
> +		goto failed;
> +
> +	msleep (500);
> +
> +	buf[0] = 0; /* FTA */
> +
> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
> +
> + failed:
> +	mutex_unlock (&state->ca_mutex);
> +
> +	return ret;
> +}
> +
> +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			open)
> +{
> +	u8 buf[1];
> +	int ret;
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
> +	if (0 != ret)
> +		return ret;
> +
> +	if (1 == buf[0]) {
> +		return (DVB_CA_EN50221_POLL_CAM_PRESENT |
> +			DVB_CA_EN50221_POLL_CAM_READY);
> +	} else {
> +		return 0;
> +	}
> +}
> +
> +static void tt3650_ci_uninit(struct dvb_usb_device *d)
> +{
> +	struct pctv452e_state *state;
> +
> +	ci_dbg("%s", __func__);
> +
> +	if (NULL == d)
> +		return;
> +
> +	state = (struct pctv452e_state *)d->priv;
> +	if (NULL == state)
> +		return;
> +
> +	if (NULL == state->ca.data)
> +		return;
> +
> +	/* Error ignored. */
> +	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
> +
> +	dvb_ca_en50221_release(&state->ca);
> +
> +	memset(&state->ca, 0, sizeof(state->ca));
> +}
> +
> +static int tt3650_ci_init(struct dvb_usb_adapter *a)
> +{
> +	struct dvb_usb_device *d = a->dev;
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	int ret;
> +
> +	ci_dbg ("%s", __func__);
> +
> +	mutex_init(&state->ca_mutex);
> +
> +	state->ca.owner = THIS_MODULE;
> +	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
> +	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
> +	state->ca.read_cam_control = tt3650_ci_read_cam_control;
> +	state->ca.write_cam_control = tt3650_ci_write_cam_control;
> +	state->ca.slot_reset = tt3650_ci_slot_reset;
> +	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
> +	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
> +	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
> +	state->ca.data = d;
> +
> +	ret = dvb_ca_en50221_init (&a->dvb_adap,
> +				   &state->ca,
> +				   /* flags */ 0,
> +				   /* n_slots */ 1);
> +	if (0 != ret) {
> +		err ("Cannot initialize CI: Error %d.", ret);
> +		memset (&state->ca, 0, sizeof (state->ca));
> +		return ret;
> +	}
> +
> +	info ("CI initialized.");
> +
> +	return 0;
> +}
> +
> +  #define CMD_BUFFER_SIZE 0x28
> +static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, const u8 * snd_buf,
> +				u8 snd_len, u8 * rcv_buf, u8 rcv_len) {
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	u8 buf[64];
> +	u8 id;
> +	int ret;
> +
> +	id = state->c++;
> +
> +	ret = -EINVAL;
> +	if (snd_len > 64 - 7 || rcv_len > 64 - 7)
> +		goto failed;
> +
> +	buf[0] = SYNC_BYTE_OUT;
> +	buf[1] = id;
> +	buf[2] = PCTV_CMD_I2C;
> +	buf[3] = snd_len + 3;
> +	buf[4] = addr << 1;
> +	buf[5] = snd_len;
> +	buf[6] = rcv_len;
> +
> +	memcpy (buf + 7, snd_buf, snd_len);
> +
> +	ret = dvb_usb_generic_rw (d, buf, 7 + snd_len,
> +				  buf, /* rcv_len */ 64,
> +				  /* delay_ms */ 0);
> +	if (ret < 0)
> +		goto failed;
> +
> +	/* TT USB protocol error. */
> +	ret = -EIO;
> +	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
> +		goto failed;
> +
> +	/* I2C device didn't respond as expected. */
> +	ret = -EREMOTEIO;
> +	if (buf[5] < snd_len || buf[6] < rcv_len)
> +		goto failed;
> +
> +	memcpy (rcv_buf, buf + 7, rcv_len);
> +
> +	return rcv_len;
> +
> + failed:
> +	err ("I2C error %d; %02X %02X  %02X %02X %02X -> "
> +	     "%02X %02X  %02X %02X %02X.",
> +	     ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
> +	     buf[0], buf[1], buf[4], buf[5], buf[6]);
> +
> +	return ret;
> +}
> +
> +static int pctv452e_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) {
> +	struct dvb_usb_device *d= i2c_get_adapdata(adapter);
> +	int i;
> +
> +	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
> +		return -EAGAIN;
> +
> +	for (i = 0; i < num; i++) {
> +		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
> +		int err;
> +
> +		if (msg[i].flags & I2C_M_RD) {
> +			addr = msg[i].addr;
> +			snd_buf = NULL;
> +			snd_len = 0;
> +			rcv_buf = msg[i].buf;
> +			rcv_len = msg[i].len;
> +		} else {
> +			addr = msg[i].addr;
> +			snd_buf = msg[i].buf;
> +			snd_len = msg[i].len;
> +			rcv_buf = NULL;
> +			rcv_len = 0;
> +		}
> +
> +		err = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf, rcv_len);
> +		if (err < rcv_len)
> +			break;
> +	}
> +
> +	mutex_unlock(&d->i2c_mutex);
> +	return i;
> +}
> +
> +static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) {
> +	return I2C_FUNC_I2C;
> +}
> +
> +int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) {
> +	struct pctv452e_state *state = (struct pctv452e_state*)d->priv;
> +	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
> +	u8 rx[PCTV_ANSWER_LEN];
> +	int ret;
> +		printk("%s: %d\n", __func__, i);
> +	if (i) {
> +		if (!state->initialized) {
> +			// hmm where shoud this should go?
> +			ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
> +			if (ret != 0) {
> +				printk("%s: Warning set interface returned: %d\n", __func__, ret);
> +			}
> +
> +			// this is a one-time initialization, dont know where to put
> +			b0[1] = state->c++;
> +			// reset board
> +			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
> +
> +			b0[1] = state->c++;
> +			b0[4] = 1;
> +			// reset board (again?)
> +			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
> +
> +			state->initialized = 1;
> +		}
> +	} else {
> +		// power down ?
> +	}
> +	return 0;
> +}
> +
> +/* Remote control stuff */
> +static struct rc_map_table pctv452e_rc_keys[] = {
> +	{0x0700, KEY_MUTE},
> +	{0x0701, KEY_VENDOR},  // pinnacle logo (top middle)
> +	{0x0739, KEY_POWER},
> +	{0x0703, KEY_VOLUMEUP},
> +	{0x0709, KEY_VOLUMEDOWN},
> +	{0x0706, KEY_CHANNELUP},
> +	{0x070c, KEY_CHANNELDOWN},
> +	{0x070f, KEY_1},
> +	{0x0715, KEY_2},
> +	{0x0710, KEY_3},
> +	{0x0718, KEY_4},
> +	{0x071b, KEY_5},
> +	{0x071e, KEY_6},
> +	{0x0711, KEY_7},
> +	{0x0721, KEY_8},
> +	{0x0712, KEY_9},
> +	{0x0727, KEY_0},
> +	{0x0724, KEY_TV}, // left of '0'
> +	{0x072a, KEY_T}, // right of '0'
> +	{0x072d, KEY_REWIND},
> +	{0x0733, KEY_FORWARD},
> +	{0x0730, KEY_PLAY},
> +	{0x0736, KEY_RECORD},
> +	{0x073c, KEY_STOP},
> +	{0x073f, KEY_HELP}
> +};
> +
> +/* Remote Control Stuff fo S2-3600 (copied from TT-S1500): */
> +static struct rc_map_table tt_connect_s2_3600_rc_key[] = {
> +	{0x1501, KEY_POWER},
> +	{0x1502, KEY_SHUFFLE}, /* ? double-arrow key */
> +	{0x1503, KEY_1},
> +	{0x1504, KEY_2},
> +	{0x1505, KEY_3},
> +	{0x1506, KEY_4},
> +	{0x1507, KEY_5},
> +	{0x1508, KEY_6},
> +	{0x1509, KEY_7},
> +	{0x150a, KEY_8},
> +	{0x150b, KEY_9},
> +	{0x150c, KEY_0},
> +	{0x150d, KEY_UP},
> +	{0x150e, KEY_LEFT},
> +	{0x150f, KEY_OK},
> +	{0x1510, KEY_RIGHT},
> +	{0x1511, KEY_DOWN},
> +	{0x1512, KEY_INFO},
> +	{0x1513, KEY_EXIT},
> +	{0x1514, KEY_RED},
> +	{0x1515, KEY_GREEN},
> +	{0x1516, KEY_YELLOW},
> +	{0x1517, KEY_BLUE},
> +	{0x1518, KEY_MUTE},
> +	{0x1519, KEY_TEXT},
> +	{0x151a, KEY_MODE},  /* ? TV/Radio */
> +	{0x1521, KEY_OPTION},
> +	{0x1522, KEY_EPG},
> +	{0x1523, KEY_CHANNELUP},
> +	{0x1524, KEY_CHANNELDOWN},
> +	{0x1525, KEY_VOLUMEUP},
> +	{0x1526, KEY_VOLUMEDOWN},
> +	{0x1527, KEY_SETUP},
> +	{0x153a, KEY_RECORD},/* these keys are only in the black remote */
> +	{0x153b, KEY_PLAY},
> +	{0x153c, KEY_STOP},
> +	{0x153d, KEY_REWIND},
> +	{0x153e, KEY_PAUSE},
> +	{0x153f, KEY_FORWARD}
> +};
> +
> +static int pctv452e_rc_query(struct dvb_usb_device *d, u32 *keyevent, int *keystate) {
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	u8 b[CMD_BUFFER_SIZE];
> +	u8 rx[PCTV_ANSWER_LEN];
> +	u8 keybuf[5];
> +	int ret, i;
> +	u8 id = state->c++;
> +
> +	/* prepare command header  */
> +	b[0] = SYNC_BYTE_OUT;
> +	b[1] = id;
> +	b[2] = PCTV_CMD_IR;
> +	b[3] = 0;
> +
> +	*keystate = REMOTE_NO_KEY_PRESSED;
> +
> +	/* send ir request */
> +	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
> +	if (ret != 0) return ret;
> +
> +	if (debug > 3) {
> +		printk("%s: read: %2d: %02x %02x %02x: ", __func__, ret, rx[0], rx[1], rx[2]);
> +		for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) {
> +			printk(" %02x", rx[i+3]);
> +		}
> +		printk("\n");
> +	}
> +
> +	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
> +		/* got a "press" event */
> +		if (debug > 2) {
> +	 		printk("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[6], rx[7]);
> +		}
> +		keybuf[0] = 0x01;// DVB_USB_RC_NEC_KEY_PRESSED; why is this #define'd privately?
> +		keybuf[1] = rx[7];
> +		keybuf[2] = ~keybuf[1]; // fake checksum
> +		keybuf[3] = rx[6];
> +		keybuf[4] = ~keybuf[3]; // fake checksum
> +		dvb_usb_nec_rc_key_to_event(d, keybuf, keyevent, keystate);
> +
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +pctv452e_read_mac_address	(struct dvb_usb_device *d,
> +				 u8			mac[6])
> +{
> +	const u8 mem_addr[] = { 0x1F, 0xCC };
> +	u8 encoded_mac[20];
> +	int ret;
> +
> +	ret = -EAGAIN;
> +	if (mutex_lock_interruptible (&d->i2c_mutex) < 0)
> +		goto failed;
> +
> +	ret = pctv452e_i2c_msg (d, I2C_ADDR_24C16,
> +				mem_addr + 1, /* snd_len */ 1,
> +				encoded_mac, /* rcv_len */ 20);
> +	if (-EREMOTEIO == ret) {
> +		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
> +		   byte write if /WC is low. */
> +		ret = pctv452e_i2c_msg (d, I2C_ADDR_24C64,
> +					mem_addr, 2,
> +					encoded_mac, 20);
> +	}
> +
> +	mutex_unlock (&d->i2c_mutex);
> +
> +	if (20 != ret)
> +		goto failed;
> +
> +	ret = ttpci_eeprom_decode_mac (mac, encoded_mac);
> +	if (0 != ret)
> +		goto failed;
> +
> +	return 0;
> +
> + failed:
> +	memset (mac, 0, 6);
> +
> +	return ret;
> +}
> +
> +
> +static struct stb0899_config stb0899_config;
> +static struct stb6100_config stb6100_config;
> +static struct dvb_usb_device_properties pctv452e_properties;
> +static struct dvb_usb_device_properties tt_connect_s2_3600_properties;
> +
> +int pctv452e_frontend_attach(struct dvb_usb_adapter *a) {
> +	struct usb_device_id *id;
> +
> +		printk("%s Enter\n", __func__);
> +
> +	a->fe = dvb_attach(stb0899_attach, &stb0899_config, &a->dev->i2c_adap);
> +	if (!a->fe) return -ENODEV;
> +	if ((dvb_attach(lnbp22_attach, a->fe, &a->dev->i2c_adap)) == 0) {
> +		printk("Warning: cannot attach lnbp22\n");
> +	}
> +
> +	id = a->dev->desc->warm_ids[0];
> +	if (USB_VID_TECHNOTREND == id->idVendor
> +	    && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct) {
> +		/* Error ignored. */
> +		tt3650_ci_init (a);
> +	}
> +
> +		printk("%s Leave Ok\n", __func__);
> +	return 0;
> +}
> +
> +int pctv452e_tuner_attach(struct dvb_usb_adapter *a) {
> +		printk("%s Enter\n", __func__);
> +	if (!a->fe) return -ENODEV;
> +	if (dvb_attach(stb6100_attach, a->fe, &stb6100_config, &a->dev->i2c_adap) == 0) {
> +		printk("%s failed\n", __func__);
> +		return -ENODEV;
> +	}
> +		printk("%s Leave\n", __func__);
> +	return 0;
> +}
> +
> +static void
> +pctv452e_usb_disconnect		(struct usb_interface *	intf)
> +{
> +	struct dvb_usb_device *d = usb_get_intfdata (intf);
> +
> +	tt3650_ci_uninit (d);
> +	dvb_usb_device_exit (intf);
> +}
> +
> +static int pctv452e_usb_probe(struct usb_interface *intf,const struct usb_device_id *id) {
> +	int ret=-ENOMEM;
> +	if ((ret=dvb_usb_device_init(intf, &pctv452e_properties, THIS_MODULE, NULL, adapter_nr))==0){
> +		return ret;
> +	}
> +	return dvb_usb_device_init(intf, &tt_connect_s2_3600_properties, THIS_MODULE, NULL, adapter_nr);
> +}
> +
> +
> +
> +static const struct stb0899_s1_reg pctv452e_init_dev [] = {
> +	{ STB0899_DISCNTRL1	, 0x26 },
> +	{ STB0899_DISCNTRL2	, 0x80 },
> +	{ STB0899_DISRX_ST0	, 0x04 },
> +	{ STB0899_DISRX_ST1	, 0x20 },
> +	{ STB0899_DISPARITY	, 0x00 },
> +	{ STB0899_DISFIFO	, 0x00 },
> +	{ STB0899_DISF22	, 0x99 },
> +	{ STB0899_DISF22RX	, 0x85 }, // 0xa8
> +	{ STB0899_ACRPRESC	, 0x11 },
> +	{ STB0899_ACRDIV1	, 0x0a },
> +	{ STB0899_ACRDIV2	, 0x05 },
> +	{ STB0899_DACR1		, 0x00 },
> +	{ STB0899_DACR2		, 0x00 },
> +	{ STB0899_OUTCFG	, 0x00 },
> +	{ STB0899_MODECFG	, 0x00 }, // Inversion
> + 	{ STB0899_IRQMSK_3	, 0xf3 },
> + 	{ STB0899_IRQMSK_2	, 0xfc },
> + 	{ STB0899_IRQMSK_1	, 0xff },
> + 	{ STB0899_IRQMSK_0	, 0xff },
> +	{ STB0899_I2CCFG	, 0x88 },
> +	{ STB0899_I2CRPT	, 0x58 },
> +	{ STB0899_GPIO00CFG	, 0x82 },
> +	{ STB0899_GPIO01CFG	, 0x82 }, /* 0x02 -> LED green 0x82 -> LED orange */
> +	{ STB0899_GPIO02CFG	, 0x82 },
> +	{ STB0899_GPIO03CFG	, 0x82 },
> +	{ STB0899_GPIO04CFG	, 0x82 },
> +	{ STB0899_GPIO05CFG	, 0x82 },
> +	{ STB0899_GPIO06CFG	, 0x82 },
> +	{ STB0899_GPIO07CFG	, 0x82 },
> +	{ STB0899_GPIO08CFG	, 0x82 },
> +	{ STB0899_GPIO09CFG	, 0x82 },
> +	{ STB0899_GPIO10CFG	, 0x82 },
> +	{ STB0899_GPIO11CFG	, 0x82 },
> +	{ STB0899_GPIO12CFG	, 0x82 },
> +	{ STB0899_GPIO13CFG	, 0x82 },
> +	{ STB0899_GPIO14CFG	, 0x82 },
> +	{ STB0899_GPIO15CFG	, 0x82 },
> +	{ STB0899_GPIO16CFG	, 0x82 },
> +	{ STB0899_GPIO17CFG	, 0x82 },
> +	{ STB0899_GPIO18CFG	, 0x82 },
> +	{ STB0899_GPIO19CFG	, 0x82 },
> +	{ STB0899_GPIO20CFG	, 0x82 },
> +	{ STB0899_SDATCFG	, 0xb8 },
> +	{ STB0899_SCLTCFG	, 0xba },
> +	{ STB0899_AGCRFCFG	, 0x1c }, // 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm)
> +	{ STB0899_GPIO22	, 0x82 },
> +	{ STB0899_GPIO21	, 0x91 },
> +	{ STB0899_DIRCLKCFG	, 0x82 },
> +	{ STB0899_CLKOUT27CFG	, 0x7e },
> +	{ STB0899_STDBYCFG	, 0x82 },
> +	{ STB0899_CS0CFG	, 0x82 },
> +	{ STB0899_CS1CFG	, 0x82 },
> +	{ STB0899_DISEQCOCFG	, 0x20 },
> +	{ STB0899_NCOARSE	, 0x15 }, // 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 108MHz
> +	{ STB0899_SYNTCTRL	, 0x00 }, // 0x00 = CLK from CLKI, 0x02 = CLK from XTALI
> +	{ STB0899_FILTCTRL	, 0x00 },
> +	{ STB0899_SYSCTRL	, 0x00 },
> +	{ STB0899_STOPCLK1	, 0x20 }, // orig: 0x00 budget-ci: 0x20
> +	{ STB0899_STOPCLK2	, 0x00 },
> +	{ STB0899_INTBUFCTRL	, 0x0a },
> +	{ STB0899_AGC2I1	, 0x00 },
> +	{ STB0899_AGC2I2	, 0x00 },
> +	{ STB0899_AGCIQIN       , 0x00 },
> +	{ STB0899_TSTRES	, 0x40 }, //rjkm
> +	{0xffff, 0xff},
> +};
> +
> +static const struct stb0899_s2_reg pctv452e_init_s2_demod[]  = {
> +	{ STB0899_OFF0_DMD_STATUS	, STB0899_BASE_DMD_STATUS	, 0x00000103 },	/* DMDSTATUS	*/
> +	{ STB0899_OFF0_CRL_FREQ		, STB0899_BASE_CRL_FREQ		, 0x3ed1da56 },	/* CRLFREQ	*/
> +	{ STB0899_OFF0_BTR_FREQ		, STB0899_BASE_BTR_FREQ		, 0x00004000 },	/* BTRFREQ	*/
> +	{ STB0899_OFF0_IF_AGC_GAIN	, STB0899_BASE_IF_AGC_GAIN	, 0x00002ade },	/* IFAGCGAIN	*/
> +	{ STB0899_OFF0_BB_AGC_GAIN	, STB0899_BASE_BB_AGC_GAIN	, 0x000001bc },	/* BBAGCGAIN	*/
> +	{ STB0899_OFF0_DC_OFFSET	, STB0899_BASE_DC_OFFSET	, 0x00000200 },	/* DCOFFSET	*/
> +	{ STB0899_OFF0_DMD_CNTRL	, STB0899_BASE_DMD_CNTRL	, 0x0000000f },	/* DMDCNTRL	*/
> +
> +	{ STB0899_OFF0_IF_AGC_CNTRL	, STB0899_BASE_IF_AGC_CNTRL	, 0x03fb4a20 },	/* IFAGCCNTRL	*/
> +	{ STB0899_OFF0_BB_AGC_CNTRL	, STB0899_BASE_BB_AGC_CNTRL	, 0x00200c97 },	/* BBAGCCNTRL	*/
> +
> +	{ STB0899_OFF0_CRL_CNTRL	, STB0899_BASE_CRL_CNTRL	, 0x00000016 },	/* CRLCNTRL	*/
> +	{ STB0899_OFF0_CRL_PHS_INIT	, STB0899_BASE_CRL_PHS_INIT	, 0x00000000 },	/* CRLPHSINIT	*/
> +	{ STB0899_OFF0_CRL_FREQ_INIT	, STB0899_BASE_CRL_FREQ_INIT	, 0x00000000 },	/* CRLFREQINIT	*/
> +	{ STB0899_OFF0_CRL_LOOP_GAIN	, STB0899_BASE_CRL_LOOP_GAIN	, 0x00000000 },	/* CRLLOOPGAIN	*/
> +	{ STB0899_OFF0_CRL_NOM_FREQ	, STB0899_BASE_CRL_NOM_FREQ	, 0x3ed097b6 },	/* CRLNOMFREQ	*/
> +	{ STB0899_OFF0_CRL_SWP_RATE	, STB0899_BASE_CRL_SWP_RATE	, 0x00000000 },	/* CRLSWPRATE	*/
> +	{ STB0899_OFF0_CRL_MAX_SWP	, STB0899_BASE_CRL_MAX_SWP	, 0x00000000 },	/* CRLMAXSWP	*/
> +	{ STB0899_OFF0_CRL_LK_CNTRL	, STB0899_BASE_CRL_LK_CNTRL	, 0x0f6cdc01 },	/* CRLLKCNTRL	*/
> +	{ STB0899_OFF0_DECIM_CNTRL	, STB0899_BASE_DECIM_CNTRL	, 0x00000000 },	/* DECIMCNTRL	*/
> +	{ STB0899_OFF0_BTR_CNTRL	, STB0899_BASE_BTR_CNTRL	, 0x00003993 },	/* BTRCNTRL	*/
> +	{ STB0899_OFF0_BTR_LOOP_GAIN	, STB0899_BASE_BTR_LOOP_GAIN	, 0x000d3c6f },	/* BTRLOOPGAIN	*/
> +	{ STB0899_OFF0_BTR_PHS_INIT	, STB0899_BASE_BTR_PHS_INIT	, 0x00000000 },	/* BTRPHSINIT	*/
> +	{ STB0899_OFF0_BTR_FREQ_INIT	, STB0899_BASE_BTR_FREQ_INIT	, 0x00000000 },	/* BTRFREQINIT	*/
> +	{ STB0899_OFF0_BTR_NOM_FREQ	, STB0899_BASE_BTR_NOM_FREQ	, 0x0238e38e },	/* BTRNOMFREQ	*/
> +	{ STB0899_OFF0_BTR_LK_CNTRL	, STB0899_BASE_BTR_LK_CNTRL	, 0x00000000 },	/* BTRLKCNTRL	*/
> +	{ STB0899_OFF0_DECN_CNTRL	, STB0899_BASE_DECN_CNTRL	, 0x00000000 },	/* DECNCNTRL	*/
> +	{ STB0899_OFF0_TP_CNTRL		, STB0899_BASE_TP_CNTRL		, 0x00000000 },	/* TPCNTRL	*/
> +	{ STB0899_OFF0_TP_BUF_STATUS	, STB0899_BASE_TP_BUF_STATUS	, 0x00000000 },	/* TPBUFSTATUS	*/
> +	{ STB0899_OFF0_DC_ESTIM		, STB0899_BASE_DC_ESTIM		, 0x00000000 },	/* DCESTIM	*/
> +	{ STB0899_OFF0_FLL_CNTRL	, STB0899_BASE_FLL_CNTRL	, 0x00000000 },	/* FLLCNTRL	*/
> +	{ STB0899_OFF0_FLL_FREQ_WD	, STB0899_BASE_FLL_FREQ_WD	, 0x40070000 },	/* FLLFREQWD	*/
> +	{ STB0899_OFF0_ANTI_ALIAS_SEL	, STB0899_BASE_ANTI_ALIAS_SEL	, 0x00000001 },	/* ANTIALIASSEL */
> +	{ STB0899_OFF0_RRC_ALPHA	, STB0899_BASE_RRC_ALPHA	, 0x00000002 },	/* RRCALPHA	*/
> +	{ STB0899_OFF0_DC_ADAPT_LSHFT	, STB0899_BASE_DC_ADAPT_LSHFT	, 0x00000000 },	/* DCADAPTISHFT */
> +	{ STB0899_OFF0_IMB_OFFSET	, STB0899_BASE_IMB_OFFSET	, 0x0000fe01 },	/* IMBOFFSET	*/
> +	{ STB0899_OFF0_IMB_ESTIMATE	, STB0899_BASE_IMB_ESTIMATE	, 0x00000000 },	/* IMBESTIMATE	*/
> +	{ STB0899_OFF0_IMB_CNTRL	, STB0899_BASE_IMB_CNTRL	, 0x00000001 },	/* IMBCNTRL	*/
> +	{ STB0899_OFF0_IF_AGC_CNTRL2	, STB0899_BASE_IF_AGC_CNTRL2	, 0x00005007 },	/* IFAGCCNTRL2	*/
> +	{ STB0899_OFF0_DMD_CNTRL2	, STB0899_BASE_DMD_CNTRL2	, 0x00000002 },	/* DMDCNTRL2	*/
> +	{ STB0899_OFF0_TP_BUFFER	, STB0899_BASE_TP_BUFFER	, 0x00000000 },	/* TPBUFFER	*/
> +	{ STB0899_OFF0_TP_BUFFER1	, STB0899_BASE_TP_BUFFER1	, 0x00000000 },	/* TPBUFFER1	*/
> +	{ STB0899_OFF0_TP_BUFFER2	, STB0899_BASE_TP_BUFFER2	, 0x00000000 },	/* TPBUFFER2	*/
> +	{ STB0899_OFF0_TP_BUFFER3	, STB0899_BASE_TP_BUFFER3	, 0x00000000 },	/* TPBUFFER3	*/
> +	{ STB0899_OFF0_TP_BUFFER4	, STB0899_BASE_TP_BUFFER4	, 0x00000000 },	/* TPBUFFER4	*/
> +	{ STB0899_OFF0_TP_BUFFER5	, STB0899_BASE_TP_BUFFER5	, 0x00000000 },	/* TPBUFFER5	*/
> +	{ STB0899_OFF0_TP_BUFFER6	, STB0899_BASE_TP_BUFFER6	, 0x00000000 },	/* TPBUFFER6	*/
> +	{ STB0899_OFF0_TP_BUFFER7	, STB0899_BASE_TP_BUFFER7	, 0x00000000 },	/* TPBUFFER7	*/
> +	{ STB0899_OFF0_TP_BUFFER8	, STB0899_BASE_TP_BUFFER8	, 0x00000000 },	/* TPBUFFER8	*/
> +	{ STB0899_OFF0_TP_BUFFER9	, STB0899_BASE_TP_BUFFER9	, 0x00000000 },	/* TPBUFFER9	*/
> +	{ STB0899_OFF0_TP_BUFFER10	, STB0899_BASE_TP_BUFFER10	, 0x00000000 },	/* TPBUFFER10	*/
> +	{ STB0899_OFF0_TP_BUFFER11	, STB0899_BASE_TP_BUFFER11	, 0x00000000 },	/* TPBUFFER11	*/
> +	{ STB0899_OFF0_TP_BUFFER12	, STB0899_BASE_TP_BUFFER12	, 0x00000000 },	/* TPBUFFER12	*/
> +	{ STB0899_OFF0_TP_BUFFER13	, STB0899_BASE_TP_BUFFER13	, 0x00000000 },	/* TPBUFFER13	*/
> +	{ STB0899_OFF0_TP_BUFFER14	, STB0899_BASE_TP_BUFFER14	, 0x00000000 },	/* TPBUFFER14	*/
> +	{ STB0899_OFF0_TP_BUFFER15	, STB0899_BASE_TP_BUFFER15	, 0x00000000 },	/* TPBUFFER15	*/
> +	{ STB0899_OFF0_TP_BUFFER16	, STB0899_BASE_TP_BUFFER16	, 0x0000ff00 },	/* TPBUFFER16	*/
> +	{ STB0899_OFF0_TP_BUFFER17	, STB0899_BASE_TP_BUFFER17	, 0x00000100 },	/* TPBUFFER17	*/
> +	{ STB0899_OFF0_TP_BUFFER18	, STB0899_BASE_TP_BUFFER18	, 0x0000fe01 },	/* TPBUFFER18	*/
> +	{ STB0899_OFF0_TP_BUFFER19	, STB0899_BASE_TP_BUFFER19	, 0x000004fe },	/* TPBUFFER19	*/
> +	{ STB0899_OFF0_TP_BUFFER20	, STB0899_BASE_TP_BUFFER20	, 0x0000cfe7 },	/* TPBUFFER20	*/
> +	{ STB0899_OFF0_TP_BUFFER21	, STB0899_BASE_TP_BUFFER21	, 0x0000bec6 },	/* TPBUFFER21	*/
> +	{ STB0899_OFF0_TP_BUFFER22	, STB0899_BASE_TP_BUFFER22	, 0x0000c2bf },	/* TPBUFFER22	*/
> +	{ STB0899_OFF0_TP_BUFFER23	, STB0899_BASE_TP_BUFFER23	, 0x0000c1c1 },	/* TPBUFFER23	*/
> +	{ STB0899_OFF0_TP_BUFFER24	, STB0899_BASE_TP_BUFFER24	, 0x0000c1c1 },	/* TPBUFFER24	*/
> +	{ STB0899_OFF0_TP_BUFFER25	, STB0899_BASE_TP_BUFFER25	, 0x0000c1c1 },	/* TPBUFFER25	*/
> +	{ STB0899_OFF0_TP_BUFFER26	, STB0899_BASE_TP_BUFFER26	, 0x0000c1c1 },	/* TPBUFFER26	*/
> +	{ STB0899_OFF0_TP_BUFFER27	, STB0899_BASE_TP_BUFFER27	, 0x0000c1c0 },	/* TPBUFFER27	*/
> +	{ STB0899_OFF0_TP_BUFFER28	, STB0899_BASE_TP_BUFFER28	, 0x0000c0c0 },	/* TPBUFFER28	*/
> +	{ STB0899_OFF0_TP_BUFFER29	, STB0899_BASE_TP_BUFFER29	, 0x0000c1c1 },	/* TPBUFFER29	*/
> +	{ STB0899_OFF0_TP_BUFFER30	, STB0899_BASE_TP_BUFFER30	, 0x0000c1c1 },	/* TPBUFFER30	*/
> +	{ STB0899_OFF0_TP_BUFFER31	, STB0899_BASE_TP_BUFFER31	, 0x0000c0c1 },	/* TPBUFFER31	*/
> +	{ STB0899_OFF0_TP_BUFFER32	, STB0899_BASE_TP_BUFFER32	, 0x0000c0c1 },	/* TPBUFFER32	*/
> +	{ STB0899_OFF0_TP_BUFFER33	, STB0899_BASE_TP_BUFFER33	, 0x0000c1c1 },	/* TPBUFFER33	*/
> +	{ STB0899_OFF0_TP_BUFFER34	, STB0899_BASE_TP_BUFFER34	, 0x0000c1c1 },	/* TPBUFFER34	*/
> +	{ STB0899_OFF0_TP_BUFFER35	, STB0899_BASE_TP_BUFFER35	, 0x0000c0c1 },	/* TPBUFFER35	*/
> +	{ STB0899_OFF0_TP_BUFFER36	, STB0899_BASE_TP_BUFFER36	, 0x0000c1c1 },	/* TPBUFFER36	*/
> +	{ STB0899_OFF0_TP_BUFFER37	, STB0899_BASE_TP_BUFFER37	, 0x0000c0c1 },	/* TPBUFFER37	*/
> +	{ STB0899_OFF0_TP_BUFFER38	, STB0899_BASE_TP_BUFFER38	, 0x0000c1c1 },	/* TPBUFFER38	*/
> +	{ STB0899_OFF0_TP_BUFFER39	, STB0899_BASE_TP_BUFFER39	, 0x0000c0c0 },	/* TPBUFFER39	*/
> +	{ STB0899_OFF0_TP_BUFFER40	, STB0899_BASE_TP_BUFFER40	, 0x0000c1c0 },	/* TPBUFFER40	*/
> +	{ STB0899_OFF0_TP_BUFFER41	, STB0899_BASE_TP_BUFFER41	, 0x0000c1c1 },	/* TPBUFFER41	*/
> +	{ STB0899_OFF0_TP_BUFFER42	, STB0899_BASE_TP_BUFFER42	, 0x0000c0c0 },	/* TPBUFFER42	*/
> +	{ STB0899_OFF0_TP_BUFFER43	, STB0899_BASE_TP_BUFFER43	, 0x0000c1c0 },	/* TPBUFFER43	*/
> +	{ STB0899_OFF0_TP_BUFFER44	, STB0899_BASE_TP_BUFFER44	, 0x0000c0c1 },	/* TPBUFFER44	*/
> +	{ STB0899_OFF0_TP_BUFFER45	, STB0899_BASE_TP_BUFFER45	, 0x0000c1be },	/* TPBUFFER45	*/
> +	{ STB0899_OFF0_TP_BUFFER46	, STB0899_BASE_TP_BUFFER46	, 0x0000c1c9 },	/* TPBUFFER46	*/
> +	{ STB0899_OFF0_TP_BUFFER47	, STB0899_BASE_TP_BUFFER47	, 0x0000c0da },	/* TPBUFFER47	*/
> +	{ STB0899_OFF0_TP_BUFFER48	, STB0899_BASE_TP_BUFFER48	, 0x0000c0ba },	/* TPBUFFER48	*/
> +	{ STB0899_OFF0_TP_BUFFER49	, STB0899_BASE_TP_BUFFER49	, 0x0000c1c4 },	/* TPBUFFER49	*/
> +	{ STB0899_OFF0_TP_BUFFER50	, STB0899_BASE_TP_BUFFER50	, 0x0000c1bf },	/* TPBUFFER50	*/
> +	{ STB0899_OFF0_TP_BUFFER51	, STB0899_BASE_TP_BUFFER51	, 0x0000c0c1 },	/* TPBUFFER51	*/
> +	{ STB0899_OFF0_TP_BUFFER52	, STB0899_BASE_TP_BUFFER52	, 0x0000c1c0 },	/* TPBUFFER52	*/
> +	{ STB0899_OFF0_TP_BUFFER53	, STB0899_BASE_TP_BUFFER53	, 0x0000c0c1 },	/* TPBUFFER53	*/
> +	{ STB0899_OFF0_TP_BUFFER54	, STB0899_BASE_TP_BUFFER54	, 0x0000c1c1 },	/* TPBUFFER54	*/
> +	{ STB0899_OFF0_TP_BUFFER55	, STB0899_BASE_TP_BUFFER55	, 0x0000c1c1 },	/* TPBUFFER55	*/
> +	{ STB0899_OFF0_TP_BUFFER56	, STB0899_BASE_TP_BUFFER56	, 0x0000c1c1 },	/* TPBUFFER56	*/
> +	{ STB0899_OFF0_TP_BUFFER57	, STB0899_BASE_TP_BUFFER57	, 0x0000c1c1 },	/* TPBUFFER57	*/
> +	{ STB0899_OFF0_TP_BUFFER58	, STB0899_BASE_TP_BUFFER58	, 0x0000c1c1 },	/* TPBUFFER58	*/
> +	{ STB0899_OFF0_TP_BUFFER59	, STB0899_BASE_TP_BUFFER59	, 0x0000c1c1 },	/* TPBUFFER59	*/
> +	{ STB0899_OFF0_TP_BUFFER60	, STB0899_BASE_TP_BUFFER60	, 0x0000c1c1 },	/* TPBUFFER60	*/
> +	{ STB0899_OFF0_TP_BUFFER61	, STB0899_BASE_TP_BUFFER61	, 0x0000c1c1 },	/* TPBUFFER61	*/
> +	{ STB0899_OFF0_TP_BUFFER62	, STB0899_BASE_TP_BUFFER62	, 0x0000c1c1 },	/* TPBUFFER62	*/
> +	{ STB0899_OFF0_TP_BUFFER63	, STB0899_BASE_TP_BUFFER63	, 0x0000c1c0 },	/* TPBUFFER63	*/
> +	{ STB0899_OFF0_RESET_CNTRL	, STB0899_BASE_RESET_CNTRL	, 0x00000001 },	/* RESETCNTRL	*/
> +	{ STB0899_OFF0_ACM_ENABLE	, STB0899_BASE_ACM_ENABLE	, 0x00005654 },	/* ACMENABLE	*/
> +	{ STB0899_OFF0_DESCR_CNTRL	, STB0899_BASE_DESCR_CNTRL	, 0x00000000 },	/* DESCRCNTRL	*/
> +	{ STB0899_OFF0_CSM_CNTRL1	, STB0899_BASE_CSM_CNTRL1	, 0x00020019 },	/* CSMCNTRL1	*/
> +	{ STB0899_OFF0_CSM_CNTRL2	, STB0899_BASE_CSM_CNTRL2	, 0x004b3237 },	/* CSMCNTRL2	*/
> +	{ STB0899_OFF0_CSM_CNTRL3	, STB0899_BASE_CSM_CNTRL3	, 0x0003dd17 },	/* CSMCNTRL3	*/
> +	{ STB0899_OFF0_CSM_CNTRL4	, STB0899_BASE_CSM_CNTRL4	, 0x00008008 },	/* CSMCNTRL4	*/
> +	{ STB0899_OFF0_UWP_CNTRL1	, STB0899_BASE_UWP_CNTRL1	, 0x002a3106 },	/* UWPCNTRL1	*/
> +	{ STB0899_OFF0_UWP_CNTRL2	, STB0899_BASE_UWP_CNTRL2	, 0x0006140a },	/* UWPCNTRL2	*/
> +	{ STB0899_OFF0_UWP_STAT1	, STB0899_BASE_UWP_STAT1	, 0x00008000 },	/* UWPSTAT1	*/
> +	{ STB0899_OFF0_UWP_STAT2	, STB0899_BASE_UWP_STAT2	, 0x00000000 },	/* UWPSTAT2	*/
> +	{ STB0899_OFF0_DMD_STAT2	, STB0899_BASE_DMD_STAT2	, 0x00000000 },	/* DMDSTAT2	*/
> +	{ STB0899_OFF0_FREQ_ADJ_SCALE	, STB0899_BASE_FREQ_ADJ_SCALE	, 0x00000471 },	/* FREQADJSCALE */
> +	{ STB0899_OFF0_UWP_CNTRL3	, STB0899_BASE_UWP_CNTRL3	, 0x017b0465 },	/* UWPCNTRL3	*/
> +	{ STB0899_OFF0_SYM_CLK_SEL	, STB0899_BASE_SYM_CLK_SEL	, 0x00000002 },	/* SYMCLKSEL	*/
> +	{ STB0899_OFF0_SOF_SRCH_TO	, STB0899_BASE_SOF_SRCH_TO	, 0x00196464 },	/* SOFSRCHTO	*/
> +	{ STB0899_OFF0_ACQ_CNTRL1	, STB0899_BASE_ACQ_CNTRL1	, 0x00000603 },	/* ACQCNTRL1	*/
> +	{ STB0899_OFF0_ACQ_CNTRL2	, STB0899_BASE_ACQ_CNTRL2	, 0x02046666 },	/* ACQCNTRL2	*/
> +	{ STB0899_OFF0_ACQ_CNTRL3	, STB0899_BASE_ACQ_CNTRL3	, 0x10046583 },	/* ACQCNTRL3	*/
> +	{ STB0899_OFF0_FE_SETTLE	, STB0899_BASE_FE_SETTLE	, 0x00010404 },	/* FESETTLE	*/
> +	{ STB0899_OFF0_AC_DWELL		, STB0899_BASE_AC_DWELL		, 0x0002aa8a },	/* ACDWELL	*/
> +	{ STB0899_OFF0_ACQUIRE_TRIG	, STB0899_BASE_ACQUIRE_TRIG	, 0x00000000 },	/* ACQUIRETRIG	*/
> +	{ STB0899_OFF0_LOCK_LOST	, STB0899_BASE_LOCK_LOST	, 0x00000001 },	/* LOCKLOST	*/
> +	{ STB0899_OFF0_ACQ_STAT1	, STB0899_BASE_ACQ_STAT1	, 0x00000500 },	/* ACQSTAT1	*/
> +	{ STB0899_OFF0_ACQ_TIMEOUT	, STB0899_BASE_ACQ_TIMEOUT	, 0x0028a0a0 },	/* ACQTIMEOUT	*/
> +	{ STB0899_OFF0_ACQ_TIME		, STB0899_BASE_ACQ_TIME		, 0x00000000 },	/* ACQTIME	*/
> +	{ STB0899_OFF0_FINAL_AGC_CNTRL	, STB0899_BASE_FINAL_AGC_CNTRL	, 0x00800c17 },	/* FINALAGCCNTRL*/
> +	{ STB0899_OFF0_FINAL_AGC_GAIN	, STB0899_BASE_FINAL_AGC_GAIN	, 0x00000000 },	/* FINALAGCCGAIN*/
> +	{ STB0899_OFF0_EQUALIZER_INIT	, STB0899_BASE_EQUALIZER_INIT	, 0x00000000 },	/* EQUILIZERINIT*/
> +	{ STB0899_OFF0_EQ_CNTRL		, STB0899_BASE_EQ_CNTRL		, 0x00054802 },	/* EQCNTL	*/
> +	{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF0 */
> +	{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF1 */
> +	{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF2 */
> +	{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF3 */
> +	{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF4 */
> +	{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 },	/* EQIINITCOEFF5 */
> +	{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF6 */
> +	{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF7 */
> +	{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF8 */
> +	{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF9 */
> +	{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF10*/
> +	{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF0 */
> +	{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF1 */
> +	{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF2 */
> +	{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF3 */
> +	{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF4 */
> +	{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF5 */
> +	{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF6 */
> +	{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF7 */
> +	{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF8 */
> +	{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF9 */
> +	{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF10*/
> +	{ STB0899_OFF0_EQ_I_OUT_COEFF_0	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT0 */
> +	{ STB0899_OFF1_EQ_I_OUT_COEFF_1	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT1 */
> +	{ STB0899_OFF2_EQ_I_OUT_COEFF_2	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT2 */
> +	{ STB0899_OFF3_EQ_I_OUT_COEFF_3	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT3 */
> +	{ STB0899_OFF4_EQ_I_OUT_COEFF_4	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT4 */
> +	{ STB0899_OFF5_EQ_I_OUT_COEFF_5	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT5 */
> +	{ STB0899_OFF6_EQ_I_OUT_COEFF_6	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT6 */
> +	{ STB0899_OFF7_EQ_I_OUT_COEFF_7	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT7 */
> +	{ STB0899_OFF8_EQ_I_OUT_COEFF_8	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT8 */
> +	{ STB0899_OFF9_EQ_I_OUT_COEFF_9	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT9 */
> +	{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT10*/
> +	{ STB0899_OFF0_EQ_Q_OUT_COEFF_0	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT0 */
> +	{ STB0899_OFF1_EQ_Q_OUT_COEFF_1	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT1 */
> +	{ STB0899_OFF2_EQ_Q_OUT_COEFF_2	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT2 */
> +	{ STB0899_OFF3_EQ_Q_OUT_COEFF_3	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT3 */
> +	{ STB0899_OFF4_EQ_Q_OUT_COEFF_4	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT4 */
> +	{ STB0899_OFF5_EQ_Q_OUT_COEFF_5	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT5 */
> +	{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT6 
> */
> +	{ STB0899_OFF7_EQ_Q_OUT_COEFF_7	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT7 */
> +	{ STB0899_OFF8_EQ_Q_OUT_COEFF_8	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT8 */
> +	{ STB0899_OFF9_EQ_Q_OUT_COEFF_9	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT9 */
> +	{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* 
> EQQCOEFFSOUT10*/
> +	{ 0xffff			, 0xffffffff		    , 0xffffffff },
> +};
> +
> +static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
> +	{ STB0899_DEMOD			, 0x00 },
> +	{ STB0899_RCOMPC		, 0xc9 },
> +	{ STB0899_AGC1CN		, 0x01 },
> +	{ STB0899_AGC1REF		, 0x10 },
> +	{ STB0899_RTC			, 0x23 },
> +	{ STB0899_TMGCFG		, 0x4e },
> +	{ STB0899_AGC2REF		, 0x34 },
> +	{ STB0899_TLSR			, 0x84 },
> +	{ STB0899_CFD			, 0xf7 },
> +	{ STB0899_ACLC			, 0x87 },
> +	{ STB0899_BCLC			, 0x94 },
> +	{ STB0899_EQON			, 0x41 },
> +	{ STB0899_LDT			, 0xf1 },
> +	{ STB0899_LDT2			, 0xe3 },
> +	{ STB0899_EQUALREF		, 0xb4 },
> +	{ STB0899_TMGRAMP		, 0x10 },
> +	{ STB0899_TMGTHD		, 0x30 },
> +	{ STB0899_IDCCOMP		, 0xfd },
> +	{ STB0899_QDCCOMP		, 0xff },
> +	{ STB0899_POWERI		, 0x0c },
> +	{ STB0899_POWERQ		, 0x0f },
> +	{ STB0899_RCOMP			, 0x6c },
> +	{ STB0899_AGCIQIN		, 0x80 },
> +	{ STB0899_AGC2I1		, 0x06 },
> +	{ STB0899_AGC2I2		, 0x00 },
> +	{ STB0899_TLIR			, 0x30 },
> +	{ STB0899_RTF			, 0x7f },
> +	{ STB0899_DSTATUS		, 0x00 },
> +	{ STB0899_LDI			, 0xbc },
> +	{ STB0899_CFRM			, 0xea },
> +	{ STB0899_CFRL			, 0x31 },
> +	{ STB0899_NIRM			, 0x2b },
> +	{ STB0899_NIRL			, 0x80 },
> +	{ STB0899_ISYMB			, 0x1d },
> +	{ STB0899_QSYMB			, 0xa6 },
> +	{ STB0899_SFRH			, 0x2f },
> +	{ STB0899_SFRM			, 0x68 },
> +	{ STB0899_SFRL			, 0x40 },
> +	{ STB0899_SFRUPH		, 0x2f },
> +	{ STB0899_SFRUPM		, 0x68 },
> +	{ STB0899_SFRUPL		, 0x40 },
> +	{ STB0899_EQUAI1		, 0x02 },
> +	{ STB0899_EQUAQ1		, 0xff },
> +	{ STB0899_EQUAI2		, 0x04 },
> +	{ STB0899_EQUAQ2		, 0x05 },
> +	{ STB0899_EQUAI3		, 0x02 },
> +	{ STB0899_EQUAQ3		, 0xfd },
> +	{ STB0899_EQUAI4		, 0x03 },
> +	{ STB0899_EQUAQ4		, 0x07 },
> +	{ STB0899_EQUAI5		, 0x08 },
> +	{ STB0899_EQUAQ5		, 0xf5 },
> +	{ STB0899_DSTATUS2		, 0x00 },
> +	{ STB0899_VSTATUS		, 0x00 },
> +	{ STB0899_VERROR		, 0x86 },
> +	{ STB0899_IQSWAP		, 0x2a },
> +	{ STB0899_ECNT1M		, 0x00 },
> +	{ STB0899_ECNT1L		, 0x00 },
> +	{ STB0899_ECNT2M		, 0x00 },
> +	{ STB0899_ECNT2L		, 0x00 },
> +	{ STB0899_ECNT3M		, 0x0a },
> +	{ STB0899_ECNT3L		, 0xad },
> +	{ STB0899_FECAUTO1		, 0x06 },
> +	{ STB0899_FECM			, 0x01 },
> +	{ STB0899_VTH12			, 0xb0 },
> +	{ STB0899_VTH23			, 0x7a },
> +	{ STB0899_VTH34			, 0x58 },
> +	{ STB0899_VTH56			, 0x38 },
> +	{ STB0899_VTH67			, 0x34 },
> +	{ STB0899_VTH78			, 0x24 },
> +	{ STB0899_PRVIT			, 0xff },
> +	{ STB0899_VITSYNC		, 0x19 },
> +	{ STB0899_RSULC			, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
> +	{ STB0899_TSULC			, 0x42 },
> +	{ STB0899_RSLLC			, 0x41 },
> +	{ STB0899_TSLPL			, 0x12 },
> +	{ STB0899_TSCFGH		, 0x0c },
> +	{ STB0899_TSCFGM		, 0x00 },
> +	{ STB0899_TSCFGL		, 0x00 },
> +	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
> +	{ STB0899_RSSYNCDEL		, 0x00 },
> +	{ STB0899_TSINHDELH		, 0x02 },
> +	{ STB0899_TSINHDELM		, 0x00 },
> +	{ STB0899_TSINHDELL		, 0x00 },
> +	{ STB0899_TSLLSTKM		, 0x1b },
> +	{ STB0899_TSLLSTKL		, 0xb3 },
> +	{ STB0899_TSULSTKM		, 0x00 },
> +	{ STB0899_TSULSTKL		, 0x00 },
> +	{ STB0899_PCKLENUL		, 0xbc },
> +	{ STB0899_PCKLENLL		, 0xcc },
> +	{ STB0899_RSPCKLEN		, 0xbd },
> +	{ STB0899_TSSTATUS		, 0x90 },
> +	{ STB0899_ERRCTRL1		, 0xb6 },
> +	{ STB0899_ERRCTRL2      	, 0x95 },
> +	{ STB0899_ERRCTRL3      	, 0x8d },
> +	{ STB0899_DMONMSK1		, 0x27 },
> +	{ STB0899_DMONMSK0		, 0x03 },
> +	{ STB0899_DEMAPVIT		, 0x5c },
> +	{ STB0899_PLPARM		, 0x19 },
> +	{ STB0899_PDELCTRL		, 0x48 },
> +	{ STB0899_PDELCTRL2		, 0x00 },
> +	{ STB0899_BBHCTRL1		, 0x00 },
> +	{ STB0899_BBHCTRL2		, 0x00 },
> +	{ STB0899_HYSTTHRESH		, 0x77 },
> +	{ STB0899_MATCSTM		, 0x00 },
> +	{ STB0899_MATCSTL		, 0x00 },
> +	{ STB0899_UPLCSTM		, 0x00 },
> +	{ STB0899_UPLCSTL		, 0x00 },
> +	{ STB0899_DFLCSTM		, 0x00 },
> +	{ STB0899_DFLCSTL		, 0x00 },
> +	{ STB0899_SYNCCST		, 0x00 },
> +	{ STB0899_SYNCDCSTM		, 0x00 },
> +	{ STB0899_SYNCDCSTL		, 0x00 },
> +	{ STB0899_ISI_ENTRY		, 0x00 },
> +	{ STB0899_ISI_BIT_EN		, 0x00 },
> +	{ STB0899_MATSTRM		, 0xf0 },
> +	{ STB0899_MATSTRL		, 0x02 },
> +	{ STB0899_UPLSTRM		, 0x45 },
> +	{ STB0899_UPLSTRL		, 0x60 },
> +	{ STB0899_DFLSTRM		, 0xe3 },
> +	{ STB0899_DFLSTRL		, 0x00 },
> +	{ STB0899_SYNCSTR		, 0x47 },
> +	{ STB0899_SYNCDSTRM		, 0x05 },
> +	{ STB0899_SYNCDSTRL		, 0x18 },
> +	{ STB0899_CFGPDELSTATUS1	, 0x19 },
> +	{ STB0899_CFGPDELSTATUS2	, 0x2b },
> +	{ STB0899_BBFERRORM		, 0x00 },
> +	{ STB0899_BBFERRORL		, 0x01 },
> +	{ STB0899_UPKTERRORM		, 0x00 },
> +	{ STB0899_UPKTERRORL		, 0x00 },
> +	{ 0xffff			, 0xff },
> +};
> +
> +
> +static const struct stb0899_s2_reg pctv452e_init_s2_fec[] = {
> +	{ STB0899_OFF0_BLOCK_LNGTH	, STB0899_BASE_BLOCK_LNGTH	, 0x00000008 },	/* BLOCKLNGTH	*/
> +	{ STB0899_OFF0_ROW_STR		, STB0899_BASE_ROW_STR		, 0x000000b4 },	/* ROWSTR	*/
> +	{ STB0899_OFF0_BN_END_ADDR	, STB0899_BASE_BN_END_ADDR	, 0x000004b5 },	/* BNANDADDR	*/
> +	{ STB0899_OFF0_CN_END_ADDR	, STB0899_BASE_CN_END_ADDR	, 0x00000b4b },	/* CNANDADDR	*/
> +	{ STB0899_OFF0_INFO_LENGTH	, STB0899_BASE_INFO_LENGTH	, 0x00000078 },	/* INFOLENGTH	*/
> +	{ STB0899_OFF0_BOT_ADDR		, STB0899_BASE_BOT_ADDR		, 0x000001e0 },	/* BOT_ADDR	*/
> +	{ STB0899_OFF0_BCH_BLK_LN	, STB0899_BASE_BCH_BLK_LN	, 0x0000a8c0 },	/* BCHBLKLN	*/
> +	{ STB0899_OFF0_BCH_T		, STB0899_BASE_BCH_T		, 0x0000000c },	/* BCHT		*/
> +	{ STB0899_OFF0_CNFG_MODE	, STB0899_BASE_CNFG_MODE	, 0x00000001 },	/* CNFGMODE	*/
> +	{ STB0899_OFF0_LDPC_STAT	, STB0899_BASE_LDPC_STAT	, 0x0000000d },	/* LDPCSTAT	*/
> +	{ STB0899_OFF0_ITER_SCALE	, STB0899_BASE_ITER_SCALE	, 0x00000040 },	/* ITERSCALE	*/
> +	{ STB0899_OFF0_INPUT_MODE	, STB0899_BASE_INPUT_MODE	, 0x00000000 },	/* INPUTMODE	*/
> +	{ STB0899_OFF0_LDPCDECRST	, STB0899_BASE_LDPCDECRST	, 0x00000000 },	/* LDPCDECRST	*/
> +	{ STB0899_OFF0_CLK_PER_BYTE_RW	, STB0899_BASE_CLK_PER_BYTE_RW	, 0x00000008 },	/* CLKPERBYTE	*/
> +	{ STB0899_OFF0_BCH_ERRORS	, STB0899_BASE_BCH_ERRORS	, 0x00000000 },	/* BCHERRORS	*/
> +	{ STB0899_OFF0_LDPC_ERRORS	, STB0899_BASE_LDPC_ERRORS	, 0x00000000 },	/* LDPCERRORS	*/
> +	{ STB0899_OFF0_BCH_MODE		, STB0899_BASE_BCH_MODE		, 0x00000000 },	/* BCHMODE	*/
> +	{ STB0899_OFF0_ERR_ACC_PER	, STB0899_BASE_ERR_ACC_PER	, 0x00000008 },	/* ERRACCPER	*/
> +	{ STB0899_OFF0_BCH_ERR_ACC	, STB0899_BASE_BCH_ERR_ACC	, 0x00000000 },	/* BCHERRACC	*/
> +	{ STB0899_OFF0_FEC_TP_SEL	, STB0899_BASE_FEC_TP_SEL	, 0x00000000 },	/* FECTPSEL	*/
> +	{ 0xffff			, 0xffffffff			, 0xffffffff },
> +};
> +
> +static const struct stb0899_s1_reg pctv452e_init_tst[] = {
> +	{ STB0899_TSTCK		, 0x00 },
> +	{ STB0899_TSTRES	, 0x00 },
> +	{ STB0899_TSTOUT	, 0x00 },
> +	{ STB0899_TSTIN		, 0x00 },
> +	{ STB0899_TSTSYS	, 0x00 },
> +	{ STB0899_TSTCHIP	, 0x00 },
> +	{ STB0899_TSTFREE	, 0x00 },
> +	{ STB0899_TSTI2C	, 0x00 },
> +	{ STB0899_BITSPEEDM	, 0x00 },
> +	{ STB0899_BITSPEEDL	, 0x00 },
> +	{ STB0899_TBUSBIT	, 0x00 },
> +	{ STB0899_TSTDIS	, 0x00 },
> +	{ STB0899_TSTDISRX	, 0x00 },
> +	{ STB0899_TSTJETON	, 0x00 },
> +	{ STB0899_TSTDCADJ	, 0x00 },
> +	{ STB0899_TSTAGC1	, 0x00 },
> +	{ STB0899_TSTAGC1N	, 0x00 },
> +	{ STB0899_TSTPOLYPH	, 0x00 },
> +	{ STB0899_TSTR		, 0x00 },
> +	{ STB0899_TSTAGC2	, 0x00 },
> +	{ STB0899_TSTCTL1	, 0x00 },
> +	{ STB0899_TSTCTL2	, 0x00 },
> +	{ STB0899_TSTCTL3	, 0x00 },
> +	{ STB0899_TSTDEMAP	, 0x00 },
> +	{ STB0899_TSTDEMAP2	, 0x00 },
> +	{ STB0899_TSTDEMMON	, 0x00 },
> +	{ STB0899_TSTRATE	, 0x00 },
> +	{ STB0899_TSTSELOUT	, 0x00 },
> +	{ STB0899_TSYNC		, 0x00 },
> +	{ STB0899_TSTERR	, 0x00 },
> +	{ STB0899_TSTRAM1	, 0x00 },
> +	{ STB0899_TSTVSELOUT	, 0x00 },
> +	{ STB0899_TSTFORCEIN	, 0x00 },
> +	{ STB0899_TSTRS1	, 0x00 },
> +	{ STB0899_TSTRS2	, 0x00 },
> +	{ STB0899_TSTRS3	, 0x00 },
> +	{ STB0899_GHOSTREG	, 0x81 },
> +	{ 0xffff		, 0xff },
> +};
> +
> +
> +#define PCTV452E_DVBS2_ESNO_AVE			3
> +#define PCTV452E_DVBS2_ESNO_QUANT		32
> +#define PCTV452E_DVBS2_AVFRAMES_COARSE		10
> +#define PCTV452E_DVBS2_AVFRAMES_FINE		20
> +#define PCTV452E_DVBS2_MISS_THRESHOLD		6
> +#define PCTV452E_DVBS2_UWP_THRESHOLD_ACQ	1125
> +#define PCTV452E_DVBS2_UWP_THRESHOLD_TRACK	758
> +#define PCTV452E_DVBS2_UWP_THRESHOLD_SOF	1350
> +#define PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT	1664100
> +
> +#define PCTV452E_DVBS2_BTR_NCO_BITS		28
> +#define PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET	15
> +#define PCTV452E_DVBS2_CRL_NCO_BITS		30
> +#define PCTV452E_DVBS2_LDPC_MAX_ITER		70
> +
> +
> +static struct stb0899_config stb0899_config = {
> +	.init_dev	= pctv452e_init_dev,
> +	.init_s2_demod   = pctv452e_init_s2_demod,
> +	.init_s1_demod   = pctv452e_init_s1_demod,
> +	.init_s2_fec     = pctv452e_init_s2_fec,
> +	.init_tst	= pctv452e_init_tst,
> +
> +	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
> +	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
> +
> +	.xtal_freq       = 27000000,	 /* Assume Hz ? */
> +	.inversion       = IQ_SWAP_ON,       /* ? */
> +
> +	.lo_clk	  = 76500000,
> +	.hi_clk	  = 99000000,
> +
> +	.ts_output_mode  = 0,		/* Use parallel mode */
> +	.clock_polarity  = 0,		/*  */
> +	.data_clk_parity = 0,		/*  */
> +	.fec_mode	= 0,		/*  */
> +
> +	.esno_ave	    = PCTV452E_DVBS2_ESNO_AVE,
> +	.esno_quant	  = PCTV452E_DVBS2_ESNO_QUANT,
> +	.avframes_coarse     = PCTV452E_DVBS2_AVFRAMES_COARSE,
> +	.avframes_fine       = PCTV452E_DVBS2_AVFRAMES_FINE,
> +	.miss_threshold      = PCTV452E_DVBS2_MISS_THRESHOLD,
> +	.uwp_threshold_acq   = PCTV452E_DVBS2_UWP_THRESHOLD_ACQ,
> +	.uwp_threshold_track = PCTV452E_DVBS2_UWP_THRESHOLD_TRACK,
> +	.uwp_threshold_sof   = PCTV452E_DVBS2_UWP_THRESHOLD_SOF,
> +	.sof_search_timeout  = PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT,
> +
> +	.btr_nco_bits	  = PCTV452E_DVBS2_BTR_NCO_BITS,
> +	.btr_gain_shift_offset = PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET,
> +	.crl_nco_bits	  = PCTV452E_DVBS2_CRL_NCO_BITS,
> +	.ldpc_max_iter	 = PCTV452E_DVBS2_LDPC_MAX_ITER,
> +
> +	.tuner_get_frequency	= stb6100_get_frequency,
> +	.tuner_set_frequency	= stb6100_set_frequency,
> +	.tuner_set_bandwidth	= stb6100_set_bandwidth,
> +	.tuner_get_bandwidth	= stb6100_get_bandwidth,
> +	.tuner_set_rfsiggain	= NULL,
> +
> +	/* helper for switching LED green/orange */
> +	.postproc = pctv45e_postproc
> +};
> +
> +static struct stb6100_config stb6100_config = {
> +	.tuner_address = I2C_ADDR_STB6100,
> +	.refclock      = 27000000
> +};
> +
> +
> +static struct i2c_algorithm pctv452e_i2c_algo = {
> +	.master_xfer   = pctv452e_i2c_xfer,
> +	.functionality = pctv452e_i2c_func
> +};
> +
> +
> +static struct usb_device_id pctv452e_usb_table[] = {
> +	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
> +	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
> +	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
> +
> +static struct dvb_usb_device_properties pctv452e_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +
> +	.size_of_priv     = sizeof(struct pctv452e_state),
> +
> +	.identify_state   = 0, // this is a warm only device
> +
> +	.power_ctrl       = pctv452e_power_ctrl,
> +	/* Untested. */
> +	/* .read_mac_address = pctv452e_read_mac_address, */
> +
> +	.rc.legacy = {
> +		.rc_map_table     = pctv452e_rc_keys,
> +		.rc_map_size      = ARRAY_SIZE(pctv452e_rc_keys),
> +		.rc_query         = pctv452e_rc_query,
> +		.rc_interval      = 100,
> +	},
> +
> +	.num_adapters     = 1,
> +	.adapter = {{
> +		.caps	     = 0,
> +		.pid_filter_count = 0,
> +
> +		.streaming_ctrl   = NULL,
> +
> +		.frontend_attach  = pctv452e_frontend_attach,
> +		.tuner_attach     = pctv452e_tuner_attach,
> +
> +		/* parameter for the MPEG2-data transfer */
> +		.stream = {
> +			.type     = USB_ISOC,
> +			.count    = ISO_BUF_COUNT,
> +			.endpoint = 0x02,
> +			.u = {
> +				.isoc = {
> +					.framesperurb = FRAMES_PER_ISO_BUF,
> +					.framesize    = ISO_FRAME_SIZE,
> +					.interval     = 1
> +				}
> +			}
> +		},
> +		.size_of_priv     = 0
> +	}},
> +
> +	.i2c_algo = &pctv452e_i2c_algo,
> +
> +	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
> +
> +	.num_device_descs = 1,
> +	.devices = {
> +		{ .name = "PCTV HDTV USB",
> +		  .cold_ids = { NULL, NULL }, // this is a warm only device
> +		  .warm_ids = { &pctv452e_usb_table[0], NULL }
> +		},
> +		{ 0 },
> +	}
> +};
> +
> +static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +
> +	.size_of_priv		= sizeof(struct pctv452e_state),
> +
> +	.identify_state		= 0, // this is a warm only device
> +
> +	.power_ctrl		= pctv452e_power_ctrl,
> +	.read_mac_address	= pctv452e_read_mac_address,
> +
> +	.rc.legacy = {
> +		.rc_map_table   = tt_connect_s2_3600_rc_key,
> +		.rc_map_size    = ARRAY_SIZE(tt_connect_s2_3600_rc_key),
> +		.rc_query       = pctv452e_rc_query,
> +		.rc_interval    = 500,
> +	},
> +
> +	.num_adapters		= 1,
> +	.adapter = {{
> +		.caps = 0,
> +		.pid_filter_count = 0,
> +
> +		.streaming_ctrl = NULL,
> +
> +		.frontend_attach = pctv452e_frontend_attach,
> +		.tuner_attach = pctv452e_tuner_attach,
> +
> +		/* parameter for the MPEG2-data transfer */
> +		.stream = {
> +			.type = USB_ISOC,
> +			.count = 7,
> +			.endpoint = 0x02,
> +			.u = {
> +				.isoc = {
> +					.framesperurb = 4,
> +					.framesize = 940,
> +					.interval = 1
> +				}
> +			}
> +		},
> +		.size_of_priv = 0
> +	}},
> +
> +	.i2c_algo = &pctv452e_i2c_algo,
> +
> +	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
> +
> +	.num_device_descs = 2,
> +	.devices = {
> +		{ .name = "Technotrend TT Connect S2-3600",
> +		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
> +		  .warm_ids = { &pctv452e_usb_table[1], NULL }
> +		},
> +		{ .name = "Technotrend TT Connect S2-3650-CI",
> +		  .cold_ids = { NULL, NULL },
> +		  .warm_ids = { &pctv452e_usb_table[2], NULL }
> +		},
> +		{ 0 },
> +	}
> +};
> +
> +
> +
> +static struct usb_driver pctv452e_usb_driver = {
> +#if LINUX_VERSION_CODE <=  KERNEL_VERSION(2,6,15)
> +	.owner      = THIS_MODULE,
> +#endif
> +	.name       = "pctv452e",
> +	.probe      = pctv452e_usb_probe,
> +	.disconnect = pctv452e_usb_disconnect,
> +	.id_table   = pctv452e_usb_table,
> +};
> +
> +static struct usb_driver tt_connects2_3600_usb_driver = {
> +#if LINUX_VERSION_CODE <=  KERNEL_VERSION(2,6,15)
> +	.owner      = THIS_MODULE,
> +#endif
> +	.name       = "dvb-usb-tt-connect-s2-3600-01.fw",
> +	.probe      = pctv452e_usb_probe,
> +	.disconnect = pctv452e_usb_disconnect,
> +	.id_table   = pctv452e_usb_table,
> +};
> +
> +static int __init pctv452e_usb_init(void) {
> +	int err=0;
> +
> +	if ((err = usb_register(&pctv452e_usb_driver))) {
> +		printk("%s: usb_register failed! Error number %d", __FILE__, err);
> +		return err;
> +	}
> +	if ((err = usb_register(&tt_connects2_3600_usb_driver))) {
> +		printk("%s: usb_register failed! Error number %d", __FILE__, err);
> +	}
> +
> +	return err;
> +}
> +
> +static void __exit pctv452e_usb_exit(void)  {
> +	usb_deregister(&pctv452e_usb_driver);
> +	usb_deregister(&tt_connects2_3600_usb_driver);
> +}
> +
> +module_init(pctv452e_usb_init);
> +module_exit(pctv452e_usb_exit);
> +
> +MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
> +MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
> +MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
> +MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
> index 3b0c4bd..8e6f588 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -49,6 +49,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
>  obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
>  obj-$(CONFIG_DVB_CX24123) += cx24123.o
>  obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
> +obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
>  obj-$(CONFIG_DVB_ISL6405) += isl6405.o
>  obj-$(CONFIG_DVB_ISL6421) += isl6421.o
>  obj-$(CONFIG_DVB_TDA10086) += tda10086.o
> diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
> new file mode 100644
> index 0000000..48377b2
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/lnbp22.c
> @@ -0,0 +1,140 @@
> +/*
> + * lnbp22.h - driver for lnb supply and control ic lnbp22
> + *
> + * Copyright (C) 2006 Dominik Kuhlen
> + * Based on lnbp21 driver
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
> + *
> + *
> + * the project's page is at http://www.linuxtv.org
> + */
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +
> +#include "dvb_frontend.h"
> +#include "lnbp22.h"
> +
> +static int debug = 0;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
> +
> +
> +#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
> +
> +struct lnbp22 {
> +	u8                 config[4];
> +	struct i2c_adapter *i2c;
> +};
> +
> +static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) {
> +	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
> +	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
> +				.buf = (char*)&lnbp22->config,
> +				.len = sizeof(lnbp22->config) };
> +
> +	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __FUNCTION__, voltage,
> +	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
> +
> +	lnbp22->config[3] = 0x60; // Power down
> +	switch(voltage) {
> +	case SEC_VOLTAGE_OFF:
> +		break;
> +	case SEC_VOLTAGE_13:
> +		lnbp22->config[3] |= LNBP22_EN;
> +		break;
> +	case SEC_VOLTAGE_18:
> +		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
> +		break;
> +	default:
> +		return -EINVAL;
> +	};
> +
> +	dprintk(1, "%s: 0x%02x)\n", __FUNCTION__, lnbp22->config[3]);
> +	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
> +}
> +
> +static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) {
> +	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
> +	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
> +				.buf = (char*)&lnbp22->config,
> +				.len = sizeof(lnbp22->config) };
> +
> +	dprintk(1, "%s: %d\n", __FUNCTION__, (int)arg);
> +	if (arg)
> +		lnbp22->config[3] |= LNBP22_LLC;
> +	else
> +		lnbp22->config[3] &= ~LNBP22_LLC;
> +
> +	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
> +}
> +
> +static void lnbp22_release(struct dvb_frontend *fe)
> +{
> +
> +	dprintk(1, "%s\n", __FUNCTION__);
> +	/* LNBP power off */
> +	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
> +
> +	/* free data */
> +	kfree(fe->sec_priv);
> +	fe->sec_priv = NULL;
> +}
> +
> +struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
> +{
> +	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
> +	if (!lnbp22)
> +		return NULL;
> +
> +	/* default configuration */
> +	lnbp22->config[0] = 0x00; /* ? */
> +	lnbp22->config[1] = 0x28; /* ? */
> +	lnbp22->config[2] = 0x48; /* ? */
> +	lnbp22->config[3] = 0x60; /* Power down */
> +	lnbp22->i2c = i2c;
> +	fe->sec_priv = lnbp22;
> +
> +	/* detect if it is present or not */
> +	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
> +		dprintk(0, "%s LNBP22 not found\n", __FUNCTION__);
> +		kfree(lnbp22);
> +		fe->sec_priv = NULL;
> +		return NULL;
> +	}
> +
> +	/* install release callback */
> +	fe->ops.release_sec = lnbp22_release;
> +
> +	/* override frontend ops */
> +	fe->ops.set_voltage = lnbp22_set_voltage;
> +	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
> +
> +	return fe;
> +}
> +EXPORT_SYMBOL(lnbp22_attach);
> +
> +MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
> +MODULE_AUTHOR("Dominik Kuhlen");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
> new file mode 100644
> index 0000000..4149c62
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/lnbp22.h
> @@ -0,0 +1,51 @@
> +/*
> + * lnbp22.h - driver for lnb supply and control ic lnbp22
> + *
> + * Copyright (C) 2006 Dominik Kuhlen
> + * Based on lnbp21.h
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
> + *
> + *
> + * the project's page is at http://www.linuxtv.org
> + */
> +
> +#ifndef _LNBP22_H
> +#define _LNBP22_H
> +
> +// Enable
> +#define LNBP22_EN	  0x10
> +// Voltage selection
> +#define LNBP22_VSEL	0x02
> +// Plus 1 Volt Bit
> +#define LNBP22_LLC	0x01
> +
> +#include <linux/dvb/frontend.h>
> +
> +#if defined(CONFIG_DVB_LNBP22) || (defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
> +/* override_set and override_clear control which system register bits (above) to always set & clear */
> +extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c);
> +#else
> +static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +#endif // CONFIG_DVB_LNBP22
> +
> +#endif // _LNBP22_H
> diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
> index 7dd54b3..0f54d4f 100644
> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
> @@ -85,6 +85,31 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
>  	return 0;
>  }
>  
> +int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC)
> +{
> +	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
> +		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
> +		       0x1d, 0x36, 0x64, 0x78};
> +	u8 data[20];
> +	int i;
> +
> +	/* In case there is a sig check failure have the orig contents available */
> +	memcpy(data, encodedMAC, 20);
> +
> +	for (i = 0; i < 20; i++)
> +		data[i] ^= xor[i];
> +	for (i = 0; i < 10; i++)
> +		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
> +			>> ((data[2 * i + 1] >> 6) & 3);
> +
> +	if (check_mac_tt(data))
> +		return -ENODEV;
> +
> +	decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0];
> +	decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4];
> +	return 0;
> +}
> +
>  static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
>  {
>  	int ret;
> diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h
> index e2dc6cf..fea8bfc 100644
> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h
> @@ -28,6 +28,7 @@
>  #include <linux/types.h>
>  #include <linux/i2c.h>
>  
> +extern int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC);
>  extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
>  
>  #endif


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
       [not found]     ` <4DF531BE.8090005@net1.cc>
@ 2011-06-12 22:34       ` Doychin Dokov
  2011-06-15 15:44       ` Igor M. Liplianin
  1 sibling, 0 replies; 18+ messages in thread
From: Doychin Dokov @ 2011-06-12 22:34 UTC (permalink / raw)
  Cc: linux-media, Konstantin Dimitrov

I also confirmed it works with s2-liplianin on Debian's 2.6.38-bpo2 
kernel without such problems.

Another thing I've tested is to compile the media_tree with the stb6100, 
but the problem persist, so it seems it's not related to the component 
that both devices share.

Any ideas what might be the reason for that, or at least where I should 
focus at searching?

На 13.6.2011 г. 00:38 ч., Doychin Dokov написа:
> On 2.6.32.5 with s2-liplianin tree this is not observed, i.e. everything
> works as expected - the S2-3650 does not cause the TBS device to stutter.
>
> На 12.6.2011 г. 23:27 ч., Doychin Dokov написа:
>> The same thing happens when the devices are on different USB buses:
>> Bus 002 Device 004: ID 0b48:300a TechnoTrend AG TT-connect S2-3650 CI
>> Bus 001 Device 007: ID 0b48:3006 TechnoTrend AG TT-connect S-2400 DVB-S
>> Bus 001 Device 004: ID 734c:5980 TBS Technologies China
>>
>> When the S2-3650 CI scans, the stream output from the TBS is gone. When
>> it's done scanning / locking, the TBS continues to work fine. The S-2400
>> is not affected in any way, nor it affects the other receivers.
>>
>> It seems the issue is not relative to the devices being on the same USB
>> bus, nor the kernel used. I've tried Debian's 2.6.32.5 and 2.6.38-bpo2
>> on a Debian Squeeze system.
>>
>> На 11.6.2011 г. 19:38 ч., Doychin Dokov написа:
>>> i've been using the patches in the latest media_tree for some hours -
>>> the S2-3650 CI seems to work. There's one thing that disturbs me, though
>>> - when it scans / locks on a frequency, another device on the same PC,
>>> using the same stb6100, gets stuck for a moment. Any ideas what might be
>>> the cause for that? The two devices do not share common RF input signal,
>>> but are on the same USB bus:
>>> Bus 001 Device 004: ID 734c:5980 TBS Technologies China
>>> Bus 001 Device 003: ID 0b48:300a TechnoTrend AG TT-connect S2-3650 CI
>>>
>>> The TBS device is a QBOX2 SI, which works with their official driver
>>> from their web-site.
>>>
>>> There's also a third DVB device in the system - a TT S-2400 (which is on
>>> the other USB bus, though), which does not exhibit any problems related
>>> with the first two devices, nor causes them to get stuck when it's
>>> scanning.
>>>
>>> I'll try to switch devices around and see if anything changes.
>>>
>>
>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
       [not found]     ` <4DF531BE.8090005@net1.cc>
  2011-06-12 22:34       ` Doychin Dokov
@ 2011-06-15 15:44       ` Igor M. Liplianin
  2011-09-13  6:04         ` Steffen Barszus
  1 sibling, 1 reply; 18+ messages in thread
From: Igor M. Liplianin @ 2011-06-15 15:44 UTC (permalink / raw)
  To: linux-media
  Cc: Doychin Dokov, Konstantin Dimitrov, Hans Petter Selasky,
	Dominik Kuhlen, Michael H. Schimek, Mauro Chehab

>From my point of view we can count the beginning was here:

http://www.spinics.net/lists/linux-dvb/msg26431.html

The later history is difficult to restore, but possible.

BR
Igor

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
       [not found] <201105242151.22826.hselasky@c2i.net>
  2011-06-01 20:16 ` [PATCH] Add support for PCTV452E Mauro Carvalho Chehab
       [not found] ` <4DF399EA.6090508@net1.cc>
@ 2011-07-23 11:24 ` Steffen Barszus
  2011-07-30 21:12   ` Oliver Freyermuth
  2011-09-05 21:27   ` Oliver Freyermuth
  2 siblings, 2 replies; 18+ messages in thread
From: Steffen Barszus @ 2011-07-23 11:24 UTC (permalink / raw)
  To: Hans Petter Selasky
  Cc: linux-media, Mauro Carvalho Chehab, Igor M. Liplianin, dkuhlen

On Tue, 24 May 2011 21:51:22 +0200
Hans Petter Selasky <hselasky@c2i.net> wrote:

> NOTES:
> 
> Sources were taken from the following repositorium as of today:
> http://mercurial.intuxication.org/hg/s2-liplianin/
> 
> And depend on the zig-zag fix posted today.

Did a first test on the patch. 
[   96.780040] usb 1-8: new high speed USB device using ehci_hcd and address 5
[   97.376058] dvb_usb_pctv452e: Unknown symbol ttpci_eeprom_decode_mac (err 0)

Looks like this patch didn't make it into patchwork - Mauro can you
check that ?


I think the patch for ttpci-eeprom.c is missing this: 

--- linux/drivers/media/dvb/ttpci/ttpci-eeprom.c.orig	2011-07-23 11:00:49.000000000 +0000
+++ linux/drivers/media/dvb/ttpci/ttpci-eeprom.c	2011-07-23 11:04:00.000000000 +0000
@@ -165,6 +165,7 @@ int ttpci_eeprom_parse_mac(struct i2c_ad
 }
 
 EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
+EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-07-23 11:24 ` Steffen Barszus
@ 2011-07-30 21:12   ` Oliver Freyermuth
  2011-09-05 21:27   ` Oliver Freyermuth
  1 sibling, 0 replies; 18+ messages in thread
From: Oliver Freyermuth @ 2011-07-30 21:12 UTC (permalink / raw)
  To: linux-media

Am 23.07.2011 13:24, schrieb Steffen Barszus:
> > On Tue, 24 May 2011 21:51:22 +0200
> > Hans Petter Selasky <hselasky@c2i.net> wrote:
> >
>> >> NOTES:
>> >>
>> >> Sources were taken from the following repositorium as of today:
>> >> http://mercurial.intuxication.org/hg/s2-liplianin/
>> >>
>> >> And depend on the zig-zag fix posted today.
> >
> > Did a first test on the patch.
> > [   96.780040] usb 1-8: new high speed USB device using ehci_hcd and
address 5
> > [   97.376058] dvb_usb_pctv452e: Unknown symbol
ttpci_eeprom_decode_mac (err 0)
> >
Same here.

> > Looks like this patch didn't make it into patchwork - Mauro can you
> > check that ?
> >
> >
> > I think the patch for ttpci-eeprom.c is missing this:
> >
> > --- linux/drivers/media/dvb/ttpci/ttpci-eeprom.c.orig	2011-07-23
11:00:49.000000000 +0000
> > +++ linux/drivers/media/dvb/ttpci/ttpci-eeprom.c	2011-07-23
11:04:00.000000000 +0000
> > @@ -165,6 +165,7 @@ int ttpci_eeprom_parse_mac(struct i2c_ad
> >  }
> >
> >  EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
> > +EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
> >
> >  MODULE_LICENSE("GPL");
> >  MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
This patch indeed fixed it for me.
Module now loads, detects the card and appears to be successful.

However, when I try to tune, syslog shows:
Jul 29 02:46:00 sandy kernel: [  122.986314] pctv452e_power_ctrl: 1
Jul 29 02:46:01 sandy kernel: [  124.041037] pctv452e: I2C error -121;
AA 31  CC 00 01 -> 55 31  CC 00 00.
Jul 29 02:46:01 sandy kernel: [  124.056408] pctv452e: I2C error -121;
AA 48  CC 00 01 -> 55 48  CC 00 00.
Jul 29 02:46:01 sandy kernel: [  124.100998] pctv452e: I2C error -121;
AA 63  CC 00 01 -> 55 63  CC 00 00.
[...cut...]
Jul 29 02:46:30 sandy kernel: [  153.265552] pctv452e: I2C error -121;
AA 95  CC 00 01 -> 55 95  CC 00 00.
Jul 29 02:46:31 sandy kernel: [  153.812108] pctv452e_power_ctrl: 0

Tuning is not possible here (Kernel 3.0 in use).
Anybody with the same issue?

Reference for the 'normal' users who just want to use their card:
I have now downgraded to 2.6.38 again on my Sandy Bridge board
(sacrificing working reboot...) for s2liplianin does not like
bkl-removal in 2.6.39 and definitely no 3.0-tree.

s2liplianin on 2.6.38 works perfectly with this card. It also has much
better support for my other az6027 than the in-tree-modules (still, no
signal for any DVB-S2 with the az6027).


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-07-23 11:24 ` Steffen Barszus
  2011-07-30 21:12   ` Oliver Freyermuth
@ 2011-09-05 21:27   ` Oliver Freyermuth
  2011-09-23 20:03     ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 18+ messages in thread
From: Oliver Freyermuth @ 2011-09-05 21:27 UTC (permalink / raw)
  To: linux-media

[-- Attachment #1: Type: text/plain, Size: 498 bytes --]

Got it working with kernel 3.0!

For me, some more changes on the current patchset appeared to be necessary.
In short, I had to change all a->fe to a->fe[0] (because of 3.0-kernel)
and I had to add lnbp22 to Kconfig (it would otherwise have been
disabled and not been built, although other modules depended on it...).

I also had to add the additional
"EXPORT_SYMBOL(ttpci_eeprom_decode_mac);" as mentioned by Doychin Dokov.

Attached is the 'new' version of the patch with the mentioned changes.


[-- Attachment #2: pctv452e.patch --]
[-- Type: text/x-patch, Size: 62038 bytes --]

diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index c545039..6d725ad 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -250,6 +250,18 @@ config DVB_USB_AF9005
 	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
 	  and the TerraTec Cinergy T USB XE (Rev.1)
 
+config DVB_USB_PCTV452E
+	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
+	depends on DVB_USB
+	select TTPCI_EEPROM
+	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	help
+	  Support for external USB adapter designed by Pinnacle,
+	  shipped under the brand name 'PCTV HDTV Pro USB'.
+	  Say Y if you own such a device and want to use it.
+
 config DVB_USB_AF9005_REMOTE
 	tristate "Afatech AF9005 default remote control support"
 	depends on DVB_USB_AF9005
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 4bac13d..2497694 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -73,6 +73,9 @@ obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
 dvb-usb-af9015-objs = af9015.o
 obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
 
+dvb-usb-pctv452e-objs = pctv452e.o
+obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
+
 dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
 obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 3a8b744..1c8a241 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -237,6 +237,9 @@
 #define USB_PID_PCTV_200E				0x020e
 #define USB_PID_PCTV_400E				0x020f
 #define USB_PID_PCTV_450E				0x0222
+#define USB_PID_PCTV_452E				0x021f
+#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
+#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
 #define USB_PID_NEBULA_DIGITV				0x0201
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
new file mode 100644
index 0000000..1be24e5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/pctv452e.c
@@ -0,0 +1,1454 @@
+/*
+ * PCTV 452e DVB driver
+ *
+ * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
+ *
+ * TT connect S2-3650-CI Common Interface support, MAC readout
+ * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
+ *
+ * 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.
+ */
+
+/* dvb usb framework */
+#define DVB_USB_LOG_PREFIX "pctv452e"
+#include "dvb-usb.h"
+
+/* Demodulator */
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+/* Tuner */
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+/* FE Power */
+#include "lnbp22.h"
+
+#include "dvb_ca_en50221.h"
+#include "ttpci-eeprom.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define ISO_BUF_COUNT      4
+#define FRAMES_PER_ISO_BUF 4
+#define ISO_FRAME_SIZE     940
+#define ISOC_INTERFACE_ALTERNATIVE 3
+
+#define SYNC_BYTE_OUT 0xaa
+#define SYNC_BYTE_IN  0x55
+
+/* guessed: (copied from ttusb-budget) */
+#define PCTV_CMD_RESET 0x15
+/* command to poll IR receiver */
+#define PCTV_CMD_IR    0x1b
+/* command to send I2C  */
+#define PCTV_CMD_I2C   0x31
+
+#define I2C_ADDR_STB0899 (0xd0 >> 1)
+#define I2C_ADDR_STB6100 (0xc0 >> 1)
+#define I2C_ADDR_LNBP22  (0x10 >> 1)
+#define I2C_ADDR_24C16   (0xa0 >> 1)
+#define I2C_ADDR_24C64   (0xa2 >> 1)
+
+
+/* pctv452e sends us this amount of data for each issued usb-command */
+#define PCTV_ANSWER_LEN 64
+/* Wait up to 1000ms for device  */
+#define PCTV_TIMEOUT 1000
+
+
+#define PCTV_LED_GPIO   STB0899_GPIO01
+#define PCTV_LED_GREEN  0x82
+#define PCTV_LED_ORANGE 0x02
+
+#define ci_dbg(format, arg...)				\
+do {							\
+	if (0)						\
+		printk (KERN_DEBUG DVB_USB_LOG_PREFIX	\
+			": " format "\n" , ## arg);	\
+} while (0)
+
+enum {
+	TT3650_CMD_CI_TEST = 0x40,
+	TT3650_CMD_CI_RD_CTRL,
+	TT3650_CMD_CI_WR_CTRL,
+	TT3650_CMD_CI_RD_ATTR,
+	TT3650_CMD_CI_WR_ATTR,
+	TT3650_CMD_CI_RESET,
+	TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
+
+static struct stb0899_postproc pctv45e_postproc[] = {
+	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
+	{ 0, 0 }
+};
+
+/*
+ * stores all private variables for communication with the PCTV452e DVB-S2
+ */
+struct pctv452e_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+
+	u8 c;	   /* transaction counter, wraps around...  */
+	u8 initialized; /* set to 1 if 0x15 has been sent */
+};
+
+static int
+tt3650_ci_msg			(struct dvb_usb_device *d,
+				 u8			cmd,
+				 u8 *			data,
+				 unsigned int		write_len,
+				 unsigned int		read_len)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *) d->priv;
+	u8 buf[64];
+	u8 id;
+	unsigned int rlen;
+	int ret;
+
+	BUG_ON (NULL == data && 0 != (write_len | read_len));
+	BUG_ON (write_len > 64 - 4);
+	BUG_ON (read_len > 64 - 4);
+
+	id = state->c++;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = cmd;
+	buf[3] = write_len;
+
+	memcpy (buf + 4, data, write_len);
+
+	rlen = (read_len > 0) ? 64 : 0;
+	ret = dvb_usb_generic_rw (d, buf, 4 + write_len,
+				  buf, rlen, /* delay_ms */ 0);
+	if (0 != ret)
+		goto failed;
+
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	memcpy (data, buf + 4, read_len);
+
+	return 0;
+
+ failed:
+	err ("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
+	     ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
+
+	return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
+				 u8			cmd,
+				 u8 *			data,
+				 unsigned int		write_len,
+				 unsigned int		read_len)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	mutex_lock(&state->ca_mutex);
+	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			address)
+{
+	u8 buf[3];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+	ci_dbg ("%s %04x -> %d 0x%02x",
+		__func__, address, ret, buf[2]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			address,
+				 u8			value)
+{
+	u8 buf[3];
+
+	ci_dbg("%s %d 0x%04x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+	buf[2] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address)
+{
+	u8 buf[2];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address & 3;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+	ci_dbg("%s 0x%02x -> %d 0x%02x",
+		__func__, address, ret, buf[1]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address,
+				 u8			value)
+{
+	u8 buf[2];
+
+	ci_dbg("%s %d 0x%02x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address;
+	buf[1] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			enable)
+{
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%s %d %d", __func__, slot, enable);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	enable = !!enable;
+	buf[0] = enable;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+	if (ret < 0)
+		return ret;
+
+	if (enable != buf[0]) {
+		err("CI not %sabled.", enable ? "en" : "dis");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca,
+				 int			slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca,
+				 int			slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca,
+				 int			slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[1];
+	int ret;
+
+	ci_dbg ("%s %d", __func__, slot);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = 0;
+
+	mutex_lock (&state->ca_mutex);
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep (500);
+
+	buf[0] = 1;
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep (500);
+
+	buf[0] = 0; /* FTA */
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+ failed:
+	mutex_unlock (&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			open)
+{
+	u8 buf[1];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+	if (0 != ret)
+		return ret;
+
+	if (1 == buf[0]) {
+		return (DVB_CA_EN50221_POLL_CAM_PRESENT |
+			DVB_CA_EN50221_POLL_CAM_READY);
+	} else {
+		return 0;
+	}
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+	struct pctv452e_state *state;
+
+	ci_dbg("%s", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = (struct pctv452e_state *)d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	/* Error ignored. */
+	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	ci_dbg ("%s", __func__);
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner = THIS_MODULE;
+	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+	state->ca.read_cam_control = tt3650_ci_read_cam_control;
+	state->ca.write_cam_control = tt3650_ci_write_cam_control;
+	state->ca.slot_reset = tt3650_ci_slot_reset;
+	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+	state->ca.data = d;
+
+	ret = dvb_ca_en50221_init (&a->dvb_adap,
+				   &state->ca,
+				   /* flags */ 0,
+				   /* n_slots */ 1);
+	if (0 != ret) {
+		err ("Cannot initialize CI: Error %d.", ret);
+		memset (&state->ca, 0, sizeof (state->ca));
+		return ret;
+	}
+
+	info ("CI initialized.");
+
+	return 0;
+}
+
+  #define CMD_BUFFER_SIZE 0x28
+static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, const u8 * snd_buf,
+				u8 snd_len, u8 * rcv_buf, u8 rcv_len) {
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[64];
+	u8 id;
+	int ret;
+
+	id = state->c++;
+
+	ret = -EINVAL;
+	if (snd_len > 64 - 7 || rcv_len > 64 - 7)
+		goto failed;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = PCTV_CMD_I2C;
+	buf[3] = snd_len + 3;
+	buf[4] = addr << 1;
+	buf[5] = snd_len;
+	buf[6] = rcv_len;
+
+	memcpy (buf + 7, snd_buf, snd_len);
+
+	ret = dvb_usb_generic_rw (d, buf, 7 + snd_len,
+				  buf, /* rcv_len */ 64,
+				  /* delay_ms */ 0);
+	if (ret < 0)
+		goto failed;
+
+	/* TT USB protocol error. */
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	/* I2C device didn't respond as expected. */
+	ret = -EREMOTEIO;
+	if (buf[5] < snd_len || buf[6] < rcv_len)
+		goto failed;
+
+	memcpy (rcv_buf, buf + 7, rcv_len);
+
+	return rcv_len;
+
+ failed:
+	err ("I2C error %d; %02X %02X  %02X %02X %02X -> "
+	     "%02X %02X  %02X %02X %02X.",
+	     ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
+	     buf[0], buf[1], buf[4], buf[5], buf[6]);
+
+	return ret;
+}
+
+static int pctv452e_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) {
+	struct dvb_usb_device *d= i2c_get_adapdata(adapter);
+	int i;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
+		int err;
+
+		if (msg[i].flags & I2C_M_RD) {
+			addr = msg[i].addr;
+			snd_buf = NULL;
+			snd_len = 0;
+			rcv_buf = msg[i].buf;
+			rcv_len = msg[i].len;
+		} else {
+			addr = msg[i].addr;
+			snd_buf = msg[i].buf;
+			snd_len = msg[i].len;
+			rcv_buf = NULL;
+			rcv_len = 0;
+		}
+
+		err = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf, rcv_len);
+		if (err < rcv_len)
+			break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) {
+	return I2C_FUNC_I2C;
+}
+
+int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) {
+	struct pctv452e_state *state = (struct pctv452e_state*)d->priv;
+	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
+	u8 rx[PCTV_ANSWER_LEN];
+	int ret;
+		printk("%s: %d\n", __func__, i);
+	if (i) {
+		if (!state->initialized) {
+			// hmm where shoud this should go?
+			ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
+			if (ret != 0) {
+				printk("%s: Warning set interface returned: %d\n", __func__, ret);
+			}
+
+			// this is a one-time initialization, dont know where to put
+			b0[1] = state->c++;
+			// reset board
+			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
+
+			b0[1] = state->c++;
+			b0[4] = 1;
+			// reset board (again?)
+			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
+
+			state->initialized = 1;
+		}
+	} else {
+		// power down ?
+	}
+	return 0;
+}
+
+/* Remote control stuff */
+static struct rc_map_table pctv452e_rc_keys[] = {
+	{0x0700, KEY_MUTE},
+	{0x0701, KEY_VENDOR},  // pinnacle logo (top middle)
+	{0x0739, KEY_POWER},
+	{0x0703, KEY_VOLUMEUP},
+	{0x0709, KEY_VOLUMEDOWN},
+	{0x0706, KEY_CHANNELUP},
+	{0x070c, KEY_CHANNELDOWN},
+	{0x070f, KEY_1},
+	{0x0715, KEY_2},
+	{0x0710, KEY_3},
+	{0x0718, KEY_4},
+	{0x071b, KEY_5},
+	{0x071e, KEY_6},
+	{0x0711, KEY_7},
+	{0x0721, KEY_8},
+	{0x0712, KEY_9},
+	{0x0727, KEY_0},
+	{0x0724, KEY_TV}, // left of '0'
+	{0x072a, KEY_T}, // right of '0'
+	{0x072d, KEY_REWIND},
+	{0x0733, KEY_FORWARD},
+	{0x0730, KEY_PLAY},
+	{0x0736, KEY_RECORD},
+	{0x073c, KEY_STOP},
+	{0x073f, KEY_HELP}
+};
+
+/* Remote Control Stuff fo S2-3600 (copied from TT-S1500): */
+static struct rc_map_table tt_connect_s2_3600_rc_key[] = {
+	{0x1501, KEY_POWER},
+	{0x1502, KEY_SHUFFLE}, /* ? double-arrow key */
+	{0x1503, KEY_1},
+	{0x1504, KEY_2},
+	{0x1505, KEY_3},
+	{0x1506, KEY_4},
+	{0x1507, KEY_5},
+	{0x1508, KEY_6},
+	{0x1509, KEY_7},
+	{0x150a, KEY_8},
+	{0x150b, KEY_9},
+	{0x150c, KEY_0},
+	{0x150d, KEY_UP},
+	{0x150e, KEY_LEFT},
+	{0x150f, KEY_OK},
+	{0x1510, KEY_RIGHT},
+	{0x1511, KEY_DOWN},
+	{0x1512, KEY_INFO},
+	{0x1513, KEY_EXIT},
+	{0x1514, KEY_RED},
+	{0x1515, KEY_GREEN},
+	{0x1516, KEY_YELLOW},
+	{0x1517, KEY_BLUE},
+	{0x1518, KEY_MUTE},
+	{0x1519, KEY_TEXT},
+	{0x151a, KEY_MODE},  /* ? TV/Radio */
+	{0x1521, KEY_OPTION},
+	{0x1522, KEY_EPG},
+	{0x1523, KEY_CHANNELUP},
+	{0x1524, KEY_CHANNELDOWN},
+	{0x1525, KEY_VOLUMEUP},
+	{0x1526, KEY_VOLUMEDOWN},
+	{0x1527, KEY_SETUP},
+	{0x153a, KEY_RECORD},/* these keys are only in the black remote */
+	{0x153b, KEY_PLAY},
+	{0x153c, KEY_STOP},
+	{0x153d, KEY_REWIND},
+	{0x153e, KEY_PAUSE},
+	{0x153f, KEY_FORWARD}
+};
+
+static int pctv452e_rc_query(struct dvb_usb_device *d, u32 *keyevent, int *keystate) {
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 b[CMD_BUFFER_SIZE];
+	u8 rx[PCTV_ANSWER_LEN];
+	u8 keybuf[5];
+	int ret, i;
+	u8 id = state->c++;
+
+	/* prepare command header  */
+	b[0] = SYNC_BYTE_OUT;
+	b[1] = id;
+	b[2] = PCTV_CMD_IR;
+	b[3] = 0;
+
+	*keystate = REMOTE_NO_KEY_PRESSED;
+
+	/* send ir request */
+	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
+	if (ret != 0) return ret;
+
+	if (debug > 3) {
+		printk("%s: read: %2d: %02x %02x %02x: ", __func__, ret, rx[0], rx[1], rx[2]);
+		for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) {
+			printk(" %02x", rx[i+3]);
+		}
+		printk("\n");
+	}
+
+	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
+		/* got a "press" event */
+		if (debug > 2) {
+	 		printk("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[6], rx[7]);
+		}
+		keybuf[0] = 0x01;// DVB_USB_RC_NEC_KEY_PRESSED; why is this #define'd privately?
+		keybuf[1] = rx[7];
+		keybuf[2] = ~keybuf[1]; // fake checksum
+		keybuf[3] = rx[6];
+		keybuf[4] = ~keybuf[3]; // fake checksum
+		dvb_usb_nec_rc_key_to_event(d, keybuf, keyevent, keystate);
+
+	}
+
+	return 0;
+}
+
+static int
+pctv452e_read_mac_address	(struct dvb_usb_device *d,
+				 u8			mac[6])
+{
+	const u8 mem_addr[] = { 0x1F, 0xCC };
+	u8 encoded_mac[20];
+	int ret;
+
+	ret = -EAGAIN;
+	if (mutex_lock_interruptible (&d->i2c_mutex) < 0)
+		goto failed;
+
+	ret = pctv452e_i2c_msg (d, I2C_ADDR_24C16,
+				mem_addr + 1, /* snd_len */ 1,
+				encoded_mac, /* rcv_len */ 20);
+	if (-EREMOTEIO == ret) {
+		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
+		   byte write if /WC is low. */
+		ret = pctv452e_i2c_msg (d, I2C_ADDR_24C64,
+					mem_addr, 2,
+					encoded_mac, 20);
+	}
+
+	mutex_unlock (&d->i2c_mutex);
+
+	if (20 != ret)
+		goto failed;
+
+	ret = ttpci_eeprom_decode_mac (mac, encoded_mac);
+	if (0 != ret)
+		goto failed;
+
+	return 0;
+
+ failed:
+	memset (mac, 0, 6);
+
+	return ret;
+}
+
+
+static struct stb0899_config stb0899_config;
+static struct stb6100_config stb6100_config;
+static struct dvb_usb_device_properties pctv452e_properties;
+static struct dvb_usb_device_properties tt_connect_s2_3600_properties;
+
+int pctv452e_frontend_attach(struct dvb_usb_adapter *a) {
+	struct usb_device_id *id;
+
+		printk("%s Enter\n", __func__);
+
+	a->fe[0] = dvb_attach(stb0899_attach, &stb0899_config, &a->dev->i2c_adap);
+	if (!a->fe[0]) return -ENODEV;
+	if ((dvb_attach(lnbp22_attach, a->fe[0], &a->dev->i2c_adap)) == 0) {
+		printk("Warning: cannot attach lnbp22\n");
+	}
+
+	id = a->dev->desc->warm_ids[0];
+	if (USB_VID_TECHNOTREND == id->idVendor
+	    && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct) {
+		/* Error ignored. */
+		tt3650_ci_init (a);
+	}
+
+		printk("%s Leave Ok\n", __func__);
+	return 0;
+}
+
+int pctv452e_tuner_attach(struct dvb_usb_adapter *a) {
+		printk("%s Enter\n", __func__);
+	if (!a->fe[0]) return -ENODEV;
+	if (dvb_attach(stb6100_attach, a->fe[0], &stb6100_config, &a->dev->i2c_adap) == 0) {
+		printk("%s failed\n", __func__);
+		return -ENODEV;
+	}
+		printk("%s Leave\n", __func__);
+	return 0;
+}
+
+static void
+pctv452e_usb_disconnect		(struct usb_interface *	intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata (intf);
+
+	tt3650_ci_uninit (d);
+	dvb_usb_device_exit (intf);
+}
+
+static int pctv452e_usb_probe(struct usb_interface *intf,const struct usb_device_id *id) {
+	int ret=-ENOMEM;
+	if ((ret=dvb_usb_device_init(intf, &pctv452e_properties, THIS_MODULE, NULL, adapter_nr))==0){
+		return ret;
+	}
+	return dvb_usb_device_init(intf, &tt_connect_s2_3600_properties, THIS_MODULE, NULL, adapter_nr);
+}
+
+
+
+static const struct stb0899_s1_reg pctv452e_init_dev [] = {
+	{ STB0899_DISCNTRL1	, 0x26 },
+	{ STB0899_DISCNTRL2	, 0x80 },
+	{ STB0899_DISRX_ST0	, 0x04 },
+	{ STB0899_DISRX_ST1	, 0x20 },
+	{ STB0899_DISPARITY	, 0x00 },
+	{ STB0899_DISFIFO	, 0x00 },
+	{ STB0899_DISF22	, 0x99 },
+	{ STB0899_DISF22RX	, 0x85 }, // 0xa8
+	{ STB0899_ACRPRESC	, 0x11 },
+	{ STB0899_ACRDIV1	, 0x0a },
+	{ STB0899_ACRDIV2	, 0x05 },
+	{ STB0899_DACR1		, 0x00 },
+	{ STB0899_DACR2		, 0x00 },
+	{ STB0899_OUTCFG	, 0x00 },
+	{ STB0899_MODECFG	, 0x00 }, // Inversion
+ 	{ STB0899_IRQMSK_3	, 0xf3 },
+ 	{ STB0899_IRQMSK_2	, 0xfc },
+ 	{ STB0899_IRQMSK_1	, 0xff },
+ 	{ STB0899_IRQMSK_0	, 0xff },
+	{ STB0899_I2CCFG	, 0x88 },
+	{ STB0899_I2CRPT	, 0x58 },
+	{ STB0899_GPIO00CFG	, 0x82 },
+	{ STB0899_GPIO01CFG	, 0x82 }, /* 0x02 -> LED green 0x82 -> LED orange */
+	{ STB0899_GPIO02CFG	, 0x82 },
+	{ STB0899_GPIO03CFG	, 0x82 },
+	{ STB0899_GPIO04CFG	, 0x82 },
+	{ STB0899_GPIO05CFG	, 0x82 },
+	{ STB0899_GPIO06CFG	, 0x82 },
+	{ STB0899_GPIO07CFG	, 0x82 },
+	{ STB0899_GPIO08CFG	, 0x82 },
+	{ STB0899_GPIO09CFG	, 0x82 },
+	{ STB0899_GPIO10CFG	, 0x82 },
+	{ STB0899_GPIO11CFG	, 0x82 },
+	{ STB0899_GPIO12CFG	, 0x82 },
+	{ STB0899_GPIO13CFG	, 0x82 },
+	{ STB0899_GPIO14CFG	, 0x82 },
+	{ STB0899_GPIO15CFG	, 0x82 },
+	{ STB0899_GPIO16CFG	, 0x82 },
+	{ STB0899_GPIO17CFG	, 0x82 },
+	{ STB0899_GPIO18CFG	, 0x82 },
+	{ STB0899_GPIO19CFG	, 0x82 },
+	{ STB0899_GPIO20CFG	, 0x82 },
+	{ STB0899_SDATCFG	, 0xb8 },
+	{ STB0899_SCLTCFG	, 0xba },
+	{ STB0899_AGCRFCFG	, 0x1c }, // 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm)
+	{ STB0899_GPIO22	, 0x82 },
+	{ STB0899_GPIO21	, 0x91 },
+	{ STB0899_DIRCLKCFG	, 0x82 },
+	{ STB0899_CLKOUT27CFG	, 0x7e },
+	{ STB0899_STDBYCFG	, 0x82 },
+	{ STB0899_CS0CFG	, 0x82 },
+	{ STB0899_CS1CFG	, 0x82 },
+	{ STB0899_DISEQCOCFG	, 0x20 },
+	{ STB0899_NCOARSE	, 0x15 }, // 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 108MHz
+	{ STB0899_SYNTCTRL	, 0x00 }, // 0x00 = CLK from CLKI, 0x02 = CLK from XTALI
+	{ STB0899_FILTCTRL	, 0x00 },
+	{ STB0899_SYSCTRL	, 0x00 },
+	{ STB0899_STOPCLK1	, 0x20 }, // orig: 0x00 budget-ci: 0x20
+	{ STB0899_STOPCLK2	, 0x00 },
+	{ STB0899_INTBUFCTRL	, 0x0a },
+	{ STB0899_AGC2I1	, 0x00 },
+	{ STB0899_AGC2I2	, 0x00 },
+	{ STB0899_AGCIQIN       , 0x00 },
+	{ STB0899_TSTRES	, 0x40 }, //rjkm
+	{0xffff, 0xff},
+};
+
+static const struct stb0899_s2_reg pctv452e_init_s2_demod[]  = {
+	{ STB0899_OFF0_DMD_STATUS	, STB0899_BASE_DMD_STATUS	, 0x00000103 },	/* DMDSTATUS	*/
+	{ STB0899_OFF0_CRL_FREQ		, STB0899_BASE_CRL_FREQ		, 0x3ed1da56 },	/* CRLFREQ	*/
+	{ STB0899_OFF0_BTR_FREQ		, STB0899_BASE_BTR_FREQ		, 0x00004000 },	/* BTRFREQ	*/
+	{ STB0899_OFF0_IF_AGC_GAIN	, STB0899_BASE_IF_AGC_GAIN	, 0x00002ade },	/* IFAGCGAIN	*/
+	{ STB0899_OFF0_BB_AGC_GAIN	, STB0899_BASE_BB_AGC_GAIN	, 0x000001bc },	/* BBAGCGAIN	*/
+	{ STB0899_OFF0_DC_OFFSET	, STB0899_BASE_DC_OFFSET	, 0x00000200 },	/* DCOFFSET	*/
+	{ STB0899_OFF0_DMD_CNTRL	, STB0899_BASE_DMD_CNTRL	, 0x0000000f },	/* DMDCNTRL	*/
+
+	{ STB0899_OFF0_IF_AGC_CNTRL	, STB0899_BASE_IF_AGC_CNTRL	, 0x03fb4a20 },	/* IFAGCCNTRL	*/
+	{ STB0899_OFF0_BB_AGC_CNTRL	, STB0899_BASE_BB_AGC_CNTRL	, 0x00200c97 },	/* BBAGCCNTRL	*/
+
+	{ STB0899_OFF0_CRL_CNTRL	, STB0899_BASE_CRL_CNTRL	, 0x00000016 },	/* CRLCNTRL	*/
+	{ STB0899_OFF0_CRL_PHS_INIT	, STB0899_BASE_CRL_PHS_INIT	, 0x00000000 },	/* CRLPHSINIT	*/
+	{ STB0899_OFF0_CRL_FREQ_INIT	, STB0899_BASE_CRL_FREQ_INIT	, 0x00000000 },	/* CRLFREQINIT	*/
+	{ STB0899_OFF0_CRL_LOOP_GAIN	, STB0899_BASE_CRL_LOOP_GAIN	, 0x00000000 },	/* CRLLOOPGAIN	*/
+	{ STB0899_OFF0_CRL_NOM_FREQ	, STB0899_BASE_CRL_NOM_FREQ	, 0x3ed097b6 },	/* CRLNOMFREQ	*/
+	{ STB0899_OFF0_CRL_SWP_RATE	, STB0899_BASE_CRL_SWP_RATE	, 0x00000000 },	/* CRLSWPRATE	*/
+	{ STB0899_OFF0_CRL_MAX_SWP	, STB0899_BASE_CRL_MAX_SWP	, 0x00000000 },	/* CRLMAXSWP	*/
+	{ STB0899_OFF0_CRL_LK_CNTRL	, STB0899_BASE_CRL_LK_CNTRL	, 0x0f6cdc01 },	/* CRLLKCNTRL	*/
+	{ STB0899_OFF0_DECIM_CNTRL	, STB0899_BASE_DECIM_CNTRL	, 0x00000000 },	/* DECIMCNTRL	*/
+	{ STB0899_OFF0_BTR_CNTRL	, STB0899_BASE_BTR_CNTRL	, 0x00003993 },	/* BTRCNTRL	*/
+	{ STB0899_OFF0_BTR_LOOP_GAIN	, STB0899_BASE_BTR_LOOP_GAIN	, 0x000d3c6f },	/* BTRLOOPGAIN	*/
+	{ STB0899_OFF0_BTR_PHS_INIT	, STB0899_BASE_BTR_PHS_INIT	, 0x00000000 },	/* BTRPHSINIT	*/
+	{ STB0899_OFF0_BTR_FREQ_INIT	, STB0899_BASE_BTR_FREQ_INIT	, 0x00000000 },	/* BTRFREQINIT	*/
+	{ STB0899_OFF0_BTR_NOM_FREQ	, STB0899_BASE_BTR_NOM_FREQ	, 0x0238e38e },	/* BTRNOMFREQ	*/
+	{ STB0899_OFF0_BTR_LK_CNTRL	, STB0899_BASE_BTR_LK_CNTRL	, 0x00000000 },	/* BTRLKCNTRL	*/
+	{ STB0899_OFF0_DECN_CNTRL	, STB0899_BASE_DECN_CNTRL	, 0x00000000 },	/* DECNCNTRL	*/
+	{ STB0899_OFF0_TP_CNTRL		, STB0899_BASE_TP_CNTRL		, 0x00000000 },	/* TPCNTRL	*/
+	{ STB0899_OFF0_TP_BUF_STATUS	, STB0899_BASE_TP_BUF_STATUS	, 0x00000000 },	/* TPBUFSTATUS	*/
+	{ STB0899_OFF0_DC_ESTIM		, STB0899_BASE_DC_ESTIM		, 0x00000000 },	/* DCESTIM	*/
+	{ STB0899_OFF0_FLL_CNTRL	, STB0899_BASE_FLL_CNTRL	, 0x00000000 },	/* FLLCNTRL	*/
+	{ STB0899_OFF0_FLL_FREQ_WD	, STB0899_BASE_FLL_FREQ_WD	, 0x40070000 },	/* FLLFREQWD	*/
+	{ STB0899_OFF0_ANTI_ALIAS_SEL	, STB0899_BASE_ANTI_ALIAS_SEL	, 0x00000001 },	/* ANTIALIASSEL */
+	{ STB0899_OFF0_RRC_ALPHA	, STB0899_BASE_RRC_ALPHA	, 0x00000002 },	/* RRCALPHA	*/
+	{ STB0899_OFF0_DC_ADAPT_LSHFT	, STB0899_BASE_DC_ADAPT_LSHFT	, 0x00000000 },	/* DCADAPTISHFT */
+	{ STB0899_OFF0_IMB_OFFSET	, STB0899_BASE_IMB_OFFSET	, 0x0000fe01 },	/* IMBOFFSET	*/
+	{ STB0899_OFF0_IMB_ESTIMATE	, STB0899_BASE_IMB_ESTIMATE	, 0x00000000 },	/* IMBESTIMATE	*/
+	{ STB0899_OFF0_IMB_CNTRL	, STB0899_BASE_IMB_CNTRL	, 0x00000001 },	/* IMBCNTRL	*/
+	{ STB0899_OFF0_IF_AGC_CNTRL2	, STB0899_BASE_IF_AGC_CNTRL2	, 0x00005007 },	/* IFAGCCNTRL2	*/
+	{ STB0899_OFF0_DMD_CNTRL2	, STB0899_BASE_DMD_CNTRL2	, 0x00000002 },	/* DMDCNTRL2	*/
+	{ STB0899_OFF0_TP_BUFFER	, STB0899_BASE_TP_BUFFER	, 0x00000000 },	/* TPBUFFER	*/
+	{ STB0899_OFF0_TP_BUFFER1	, STB0899_BASE_TP_BUFFER1	, 0x00000000 },	/* TPBUFFER1	*/
+	{ STB0899_OFF0_TP_BUFFER2	, STB0899_BASE_TP_BUFFER2	, 0x00000000 },	/* TPBUFFER2	*/
+	{ STB0899_OFF0_TP_BUFFER3	, STB0899_BASE_TP_BUFFER3	, 0x00000000 },	/* TPBUFFER3	*/
+	{ STB0899_OFF0_TP_BUFFER4	, STB0899_BASE_TP_BUFFER4	, 0x00000000 },	/* TPBUFFER4	*/
+	{ STB0899_OFF0_TP_BUFFER5	, STB0899_BASE_TP_BUFFER5	, 0x00000000 },	/* TPBUFFER5	*/
+	{ STB0899_OFF0_TP_BUFFER6	, STB0899_BASE_TP_BUFFER6	, 0x00000000 },	/* TPBUFFER6	*/
+	{ STB0899_OFF0_TP_BUFFER7	, STB0899_BASE_TP_BUFFER7	, 0x00000000 },	/* TPBUFFER7	*/
+	{ STB0899_OFF0_TP_BUFFER8	, STB0899_BASE_TP_BUFFER8	, 0x00000000 },	/* TPBUFFER8	*/
+	{ STB0899_OFF0_TP_BUFFER9	, STB0899_BASE_TP_BUFFER9	, 0x00000000 },	/* TPBUFFER9	*/
+	{ STB0899_OFF0_TP_BUFFER10	, STB0899_BASE_TP_BUFFER10	, 0x00000000 },	/* TPBUFFER10	*/
+	{ STB0899_OFF0_TP_BUFFER11	, STB0899_BASE_TP_BUFFER11	, 0x00000000 },	/* TPBUFFER11	*/
+	{ STB0899_OFF0_TP_BUFFER12	, STB0899_BASE_TP_BUFFER12	, 0x00000000 },	/* TPBUFFER12	*/
+	{ STB0899_OFF0_TP_BUFFER13	, STB0899_BASE_TP_BUFFER13	, 0x00000000 },	/* TPBUFFER13	*/
+	{ STB0899_OFF0_TP_BUFFER14	, STB0899_BASE_TP_BUFFER14	, 0x00000000 },	/* TPBUFFER14	*/
+	{ STB0899_OFF0_TP_BUFFER15	, STB0899_BASE_TP_BUFFER15	, 0x00000000 },	/* TPBUFFER15	*/
+	{ STB0899_OFF0_TP_BUFFER16	, STB0899_BASE_TP_BUFFER16	, 0x0000ff00 },	/* TPBUFFER16	*/
+	{ STB0899_OFF0_TP_BUFFER17	, STB0899_BASE_TP_BUFFER17	, 0x00000100 },	/* TPBUFFER17	*/
+	{ STB0899_OFF0_TP_BUFFER18	, STB0899_BASE_TP_BUFFER18	, 0x0000fe01 },	/* TPBUFFER18	*/
+	{ STB0899_OFF0_TP_BUFFER19	, STB0899_BASE_TP_BUFFER19	, 0x000004fe },	/* TPBUFFER19	*/
+	{ STB0899_OFF0_TP_BUFFER20	, STB0899_BASE_TP_BUFFER20	, 0x0000cfe7 },	/* TPBUFFER20	*/
+	{ STB0899_OFF0_TP_BUFFER21	, STB0899_BASE_TP_BUFFER21	, 0x0000bec6 },	/* TPBUFFER21	*/
+	{ STB0899_OFF0_TP_BUFFER22	, STB0899_BASE_TP_BUFFER22	, 0x0000c2bf },	/* TPBUFFER22	*/
+	{ STB0899_OFF0_TP_BUFFER23	, STB0899_BASE_TP_BUFFER23	, 0x0000c1c1 },	/* TPBUFFER23	*/
+	{ STB0899_OFF0_TP_BUFFER24	, STB0899_BASE_TP_BUFFER24	, 0x0000c1c1 },	/* TPBUFFER24	*/
+	{ STB0899_OFF0_TP_BUFFER25	, STB0899_BASE_TP_BUFFER25	, 0x0000c1c1 },	/* TPBUFFER25	*/
+	{ STB0899_OFF0_TP_BUFFER26	, STB0899_BASE_TP_BUFFER26	, 0x0000c1c1 },	/* TPBUFFER26	*/
+	{ STB0899_OFF0_TP_BUFFER27	, STB0899_BASE_TP_BUFFER27	, 0x0000c1c0 },	/* TPBUFFER27	*/
+	{ STB0899_OFF0_TP_BUFFER28	, STB0899_BASE_TP_BUFFER28	, 0x0000c0c0 },	/* TPBUFFER28	*/
+	{ STB0899_OFF0_TP_BUFFER29	, STB0899_BASE_TP_BUFFER29	, 0x0000c1c1 },	/* TPBUFFER29	*/
+	{ STB0899_OFF0_TP_BUFFER30	, STB0899_BASE_TP_BUFFER30	, 0x0000c1c1 },	/* TPBUFFER30	*/
+	{ STB0899_OFF0_TP_BUFFER31	, STB0899_BASE_TP_BUFFER31	, 0x0000c0c1 },	/* TPBUFFER31	*/
+	{ STB0899_OFF0_TP_BUFFER32	, STB0899_BASE_TP_BUFFER32	, 0x0000c0c1 },	/* TPBUFFER32	*/
+	{ STB0899_OFF0_TP_BUFFER33	, STB0899_BASE_TP_BUFFER33	, 0x0000c1c1 },	/* TPBUFFER33	*/
+	{ STB0899_OFF0_TP_BUFFER34	, STB0899_BASE_TP_BUFFER34	, 0x0000c1c1 },	/* TPBUFFER34	*/
+	{ STB0899_OFF0_TP_BUFFER35	, STB0899_BASE_TP_BUFFER35	, 0x0000c0c1 },	/* TPBUFFER35	*/
+	{ STB0899_OFF0_TP_BUFFER36	, STB0899_BASE_TP_BUFFER36	, 0x0000c1c1 },	/* TPBUFFER36	*/
+	{ STB0899_OFF0_TP_BUFFER37	, STB0899_BASE_TP_BUFFER37	, 0x0000c0c1 },	/* TPBUFFER37	*/
+	{ STB0899_OFF0_TP_BUFFER38	, STB0899_BASE_TP_BUFFER38	, 0x0000c1c1 },	/* TPBUFFER38	*/
+	{ STB0899_OFF0_TP_BUFFER39	, STB0899_BASE_TP_BUFFER39	, 0x0000c0c0 },	/* TPBUFFER39	*/
+	{ STB0899_OFF0_TP_BUFFER40	, STB0899_BASE_TP_BUFFER40	, 0x0000c1c0 },	/* TPBUFFER40	*/
+	{ STB0899_OFF0_TP_BUFFER41	, STB0899_BASE_TP_BUFFER41	, 0x0000c1c1 },	/* TPBUFFER41	*/
+	{ STB0899_OFF0_TP_BUFFER42	, STB0899_BASE_TP_BUFFER42	, 0x0000c0c0 },	/* TPBUFFER42	*/
+	{ STB0899_OFF0_TP_BUFFER43	, STB0899_BASE_TP_BUFFER43	, 0x0000c1c0 },	/* TPBUFFER43	*/
+	{ STB0899_OFF0_TP_BUFFER44	, STB0899_BASE_TP_BUFFER44	, 0x0000c0c1 },	/* TPBUFFER44	*/
+	{ STB0899_OFF0_TP_BUFFER45	, STB0899_BASE_TP_BUFFER45	, 0x0000c1be },	/* TPBUFFER45	*/
+	{ STB0899_OFF0_TP_BUFFER46	, STB0899_BASE_TP_BUFFER46	, 0x0000c1c9 },	/* TPBUFFER46	*/
+	{ STB0899_OFF0_TP_BUFFER47	, STB0899_BASE_TP_BUFFER47	, 0x0000c0da },	/* TPBUFFER47	*/
+	{ STB0899_OFF0_TP_BUFFER48	, STB0899_BASE_TP_BUFFER48	, 0x0000c0ba },	/* TPBUFFER48	*/
+	{ STB0899_OFF0_TP_BUFFER49	, STB0899_BASE_TP_BUFFER49	, 0x0000c1c4 },	/* TPBUFFER49	*/
+	{ STB0899_OFF0_TP_BUFFER50	, STB0899_BASE_TP_BUFFER50	, 0x0000c1bf },	/* TPBUFFER50	*/
+	{ STB0899_OFF0_TP_BUFFER51	, STB0899_BASE_TP_BUFFER51	, 0x0000c0c1 },	/* TPBUFFER51	*/
+	{ STB0899_OFF0_TP_BUFFER52	, STB0899_BASE_TP_BUFFER52	, 0x0000c1c0 },	/* TPBUFFER52	*/
+	{ STB0899_OFF0_TP_BUFFER53	, STB0899_BASE_TP_BUFFER53	, 0x0000c0c1 },	/* TPBUFFER53	*/
+	{ STB0899_OFF0_TP_BUFFER54	, STB0899_BASE_TP_BUFFER54	, 0x0000c1c1 },	/* TPBUFFER54	*/
+	{ STB0899_OFF0_TP_BUFFER55	, STB0899_BASE_TP_BUFFER55	, 0x0000c1c1 },	/* TPBUFFER55	*/
+	{ STB0899_OFF0_TP_BUFFER56	, STB0899_BASE_TP_BUFFER56	, 0x0000c1c1 },	/* TPBUFFER56	*/
+	{ STB0899_OFF0_TP_BUFFER57	, STB0899_BASE_TP_BUFFER57	, 0x0000c1c1 },	/* TPBUFFER57	*/
+	{ STB0899_OFF0_TP_BUFFER58	, STB0899_BASE_TP_BUFFER58	, 0x0000c1c1 },	/* TPBUFFER58	*/
+	{ STB0899_OFF0_TP_BUFFER59	, STB0899_BASE_TP_BUFFER59	, 0x0000c1c1 },	/* TPBUFFER59	*/
+	{ STB0899_OFF0_TP_BUFFER60	, STB0899_BASE_TP_BUFFER60	, 0x0000c1c1 },	/* TPBUFFER60	*/
+	{ STB0899_OFF0_TP_BUFFER61	, STB0899_BASE_TP_BUFFER61	, 0x0000c1c1 },	/* TPBUFFER61	*/
+	{ STB0899_OFF0_TP_BUFFER62	, STB0899_BASE_TP_BUFFER62	, 0x0000c1c1 },	/* TPBUFFER62	*/
+	{ STB0899_OFF0_TP_BUFFER63	, STB0899_BASE_TP_BUFFER63	, 0x0000c1c0 },	/* TPBUFFER63	*/
+	{ STB0899_OFF0_RESET_CNTRL	, STB0899_BASE_RESET_CNTRL	, 0x00000001 },	/* RESETCNTRL	*/
+	{ STB0899_OFF0_ACM_ENABLE	, STB0899_BASE_ACM_ENABLE	, 0x00005654 },	/* ACMENABLE	*/
+	{ STB0899_OFF0_DESCR_CNTRL	, STB0899_BASE_DESCR_CNTRL	, 0x00000000 },	/* DESCRCNTRL	*/
+	{ STB0899_OFF0_CSM_CNTRL1	, STB0899_BASE_CSM_CNTRL1	, 0x00020019 },	/* CSMCNTRL1	*/
+	{ STB0899_OFF0_CSM_CNTRL2	, STB0899_BASE_CSM_CNTRL2	, 0x004b3237 },	/* CSMCNTRL2	*/
+	{ STB0899_OFF0_CSM_CNTRL3	, STB0899_BASE_CSM_CNTRL3	, 0x0003dd17 },	/* CSMCNTRL3	*/
+	{ STB0899_OFF0_CSM_CNTRL4	, STB0899_BASE_CSM_CNTRL4	, 0x00008008 },	/* CSMCNTRL4	*/
+	{ STB0899_OFF0_UWP_CNTRL1	, STB0899_BASE_UWP_CNTRL1	, 0x002a3106 },	/* UWPCNTRL1	*/
+	{ STB0899_OFF0_UWP_CNTRL2	, STB0899_BASE_UWP_CNTRL2	, 0x0006140a },	/* UWPCNTRL2	*/
+	{ STB0899_OFF0_UWP_STAT1	, STB0899_BASE_UWP_STAT1	, 0x00008000 },	/* UWPSTAT1	*/
+	{ STB0899_OFF0_UWP_STAT2	, STB0899_BASE_UWP_STAT2	, 0x00000000 },	/* UWPSTAT2	*/
+	{ STB0899_OFF0_DMD_STAT2	, STB0899_BASE_DMD_STAT2	, 0x00000000 },	/* DMDSTAT2	*/
+	{ STB0899_OFF0_FREQ_ADJ_SCALE	, STB0899_BASE_FREQ_ADJ_SCALE	, 0x00000471 },	/* FREQADJSCALE */
+	{ STB0899_OFF0_UWP_CNTRL3	, STB0899_BASE_UWP_CNTRL3	, 0x017b0465 },	/* UWPCNTRL3	*/
+	{ STB0899_OFF0_SYM_CLK_SEL	, STB0899_BASE_SYM_CLK_SEL	, 0x00000002 },	/* SYMCLKSEL	*/
+	{ STB0899_OFF0_SOF_SRCH_TO	, STB0899_BASE_SOF_SRCH_TO	, 0x00196464 },	/* SOFSRCHTO	*/
+	{ STB0899_OFF0_ACQ_CNTRL1	, STB0899_BASE_ACQ_CNTRL1	, 0x00000603 },	/* ACQCNTRL1	*/
+	{ STB0899_OFF0_ACQ_CNTRL2	, STB0899_BASE_ACQ_CNTRL2	, 0x02046666 },	/* ACQCNTRL2	*/
+	{ STB0899_OFF0_ACQ_CNTRL3	, STB0899_BASE_ACQ_CNTRL3	, 0x10046583 },	/* ACQCNTRL3	*/
+	{ STB0899_OFF0_FE_SETTLE	, STB0899_BASE_FE_SETTLE	, 0x00010404 },	/* FESETTLE	*/
+	{ STB0899_OFF0_AC_DWELL		, STB0899_BASE_AC_DWELL		, 0x0002aa8a },	/* ACDWELL	*/
+	{ STB0899_OFF0_ACQUIRE_TRIG	, STB0899_BASE_ACQUIRE_TRIG	, 0x00000000 },	/* ACQUIRETRIG	*/
+	{ STB0899_OFF0_LOCK_LOST	, STB0899_BASE_LOCK_LOST	, 0x00000001 },	/* LOCKLOST	*/
+	{ STB0899_OFF0_ACQ_STAT1	, STB0899_BASE_ACQ_STAT1	, 0x00000500 },	/* ACQSTAT1	*/
+	{ STB0899_OFF0_ACQ_TIMEOUT	, STB0899_BASE_ACQ_TIMEOUT	, 0x0028a0a0 },	/* ACQTIMEOUT	*/
+	{ STB0899_OFF0_ACQ_TIME		, STB0899_BASE_ACQ_TIME		, 0x00000000 },	/* ACQTIME	*/
+	{ STB0899_OFF0_FINAL_AGC_CNTRL	, STB0899_BASE_FINAL_AGC_CNTRL	, 0x00800c17 },	/* FINALAGCCNTRL*/
+	{ STB0899_OFF0_FINAL_AGC_GAIN	, STB0899_BASE_FINAL_AGC_GAIN	, 0x00000000 },	/* FINALAGCCGAIN*/
+	{ STB0899_OFF0_EQUALIZER_INIT	, STB0899_BASE_EQUALIZER_INIT	, 0x00000000 },	/* EQUILIZERINIT*/
+	{ STB0899_OFF0_EQ_CNTRL		, STB0899_BASE_EQ_CNTRL		, 0x00054802 },	/* EQCNTL	*/
+	{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF0 */
+	{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF1 */
+	{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF2 */
+	{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF3 */
+	{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF4 */
+	{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 },	/* EQIINITCOEFF5 */
+	{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF6 */
+	{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF7 */
+	{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF8 */
+	{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF9 */
+	{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF10*/
+	{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF0 */
+	{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF1 */
+	{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF2 */
+	{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF3 */
+	{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF4 */
+	{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF5 */
+	{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF6 */
+	{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF7 */
+	{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF8 */
+	{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF9 */
+	{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF10*/
+	{ STB0899_OFF0_EQ_I_OUT_COEFF_0	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT0 */
+	{ STB0899_OFF1_EQ_I_OUT_COEFF_1	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT1 */
+	{ STB0899_OFF2_EQ_I_OUT_COEFF_2	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT2 */
+	{ STB0899_OFF3_EQ_I_OUT_COEFF_3	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT3 */
+	{ STB0899_OFF4_EQ_I_OUT_COEFF_4	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT4 */
+	{ STB0899_OFF5_EQ_I_OUT_COEFF_5	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT5 */
+	{ STB0899_OFF6_EQ_I_OUT_COEFF_6	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT6 */
+	{ STB0899_OFF7_EQ_I_OUT_COEFF_7	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT7 */
+	{ STB0899_OFF8_EQ_I_OUT_COEFF_8	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT8 */
+	{ STB0899_OFF9_EQ_I_OUT_COEFF_9	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT9 */
+	{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT10*/
+	{ STB0899_OFF0_EQ_Q_OUT_COEFF_0	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT0 */
+	{ STB0899_OFF1_EQ_Q_OUT_COEFF_1	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT1 */
+	{ STB0899_OFF2_EQ_Q_OUT_COEFF_2	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT2 */
+	{ STB0899_OFF3_EQ_Q_OUT_COEFF_3	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT3 */
+	{ STB0899_OFF4_EQ_Q_OUT_COEFF_4	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT4 */
+	{ STB0899_OFF5_EQ_Q_OUT_COEFF_5	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT5 */
+	{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT6 */
+	{ STB0899_OFF7_EQ_Q_OUT_COEFF_7	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT7 */
+	{ STB0899_OFF8_EQ_Q_OUT_COEFF_8	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT8 */
+	{ STB0899_OFF9_EQ_Q_OUT_COEFF_9	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT9 */
+	{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT10*/
+	{ 0xffff			, 0xffffffff		    , 0xffffffff },
+};
+
+static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
+	{ STB0899_DEMOD			, 0x00 },
+	{ STB0899_RCOMPC		, 0xc9 },
+	{ STB0899_AGC1CN		, 0x01 },
+	{ STB0899_AGC1REF		, 0x10 },
+	{ STB0899_RTC			, 0x23 },
+	{ STB0899_TMGCFG		, 0x4e },
+	{ STB0899_AGC2REF		, 0x34 },
+	{ STB0899_TLSR			, 0x84 },
+	{ STB0899_CFD			, 0xf7 },
+	{ STB0899_ACLC			, 0x87 },
+	{ STB0899_BCLC			, 0x94 },
+	{ STB0899_EQON			, 0x41 },
+	{ STB0899_LDT			, 0xf1 },
+	{ STB0899_LDT2			, 0xe3 },
+	{ STB0899_EQUALREF		, 0xb4 },
+	{ STB0899_TMGRAMP		, 0x10 },
+	{ STB0899_TMGTHD		, 0x30 },
+	{ STB0899_IDCCOMP		, 0xfd },
+	{ STB0899_QDCCOMP		, 0xff },
+	{ STB0899_POWERI		, 0x0c },
+	{ STB0899_POWERQ		, 0x0f },
+	{ STB0899_RCOMP			, 0x6c },
+	{ STB0899_AGCIQIN		, 0x80 },
+	{ STB0899_AGC2I1		, 0x06 },
+	{ STB0899_AGC2I2		, 0x00 },
+	{ STB0899_TLIR			, 0x30 },
+	{ STB0899_RTF			, 0x7f },
+	{ STB0899_DSTATUS		, 0x00 },
+	{ STB0899_LDI			, 0xbc },
+	{ STB0899_CFRM			, 0xea },
+	{ STB0899_CFRL			, 0x31 },
+	{ STB0899_NIRM			, 0x2b },
+	{ STB0899_NIRL			, 0x80 },
+	{ STB0899_ISYMB			, 0x1d },
+	{ STB0899_QSYMB			, 0xa6 },
+	{ STB0899_SFRH			, 0x2f },
+	{ STB0899_SFRM			, 0x68 },
+	{ STB0899_SFRL			, 0x40 },
+	{ STB0899_SFRUPH		, 0x2f },
+	{ STB0899_SFRUPM		, 0x68 },
+	{ STB0899_SFRUPL		, 0x40 },
+	{ STB0899_EQUAI1		, 0x02 },
+	{ STB0899_EQUAQ1		, 0xff },
+	{ STB0899_EQUAI2		, 0x04 },
+	{ STB0899_EQUAQ2		, 0x05 },
+	{ STB0899_EQUAI3		, 0x02 },
+	{ STB0899_EQUAQ3		, 0xfd },
+	{ STB0899_EQUAI4		, 0x03 },
+	{ STB0899_EQUAQ4		, 0x07 },
+	{ STB0899_EQUAI5		, 0x08 },
+	{ STB0899_EQUAQ5		, 0xf5 },
+	{ STB0899_DSTATUS2		, 0x00 },
+	{ STB0899_VSTATUS		, 0x00 },
+	{ STB0899_VERROR		, 0x86 },
+	{ STB0899_IQSWAP		, 0x2a },
+	{ STB0899_ECNT1M		, 0x00 },
+	{ STB0899_ECNT1L		, 0x00 },
+	{ STB0899_ECNT2M		, 0x00 },
+	{ STB0899_ECNT2L		, 0x00 },
+	{ STB0899_ECNT3M		, 0x0a },
+	{ STB0899_ECNT3L		, 0xad },
+	{ STB0899_FECAUTO1		, 0x06 },
+	{ STB0899_FECM			, 0x01 },
+	{ STB0899_VTH12			, 0xb0 },
+	{ STB0899_VTH23			, 0x7a },
+	{ STB0899_VTH34			, 0x58 },
+	{ STB0899_VTH56			, 0x38 },
+	{ STB0899_VTH67			, 0x34 },
+	{ STB0899_VTH78			, 0x24 },
+	{ STB0899_PRVIT			, 0xff },
+	{ STB0899_VITSYNC		, 0x19 },
+	{ STB0899_RSULC			, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC			, 0x42 },
+	{ STB0899_RSLLC			, 0x41 },
+	{ STB0899_TSLPL			, 0x12 },
+	{ STB0899_TSCFGH		, 0x0c },
+	{ STB0899_TSCFGM		, 0x00 },
+	{ STB0899_TSCFGL		, 0x00 },
+	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL		, 0x00 },
+	{ STB0899_TSINHDELH		, 0x02 },
+	{ STB0899_TSINHDELM		, 0x00 },
+	{ STB0899_TSINHDELL		, 0x00 },
+	{ STB0899_TSLLSTKM		, 0x1b },
+	{ STB0899_TSLLSTKL		, 0xb3 },
+	{ STB0899_TSULSTKM		, 0x00 },
+	{ STB0899_TSULSTKL		, 0x00 },
+	{ STB0899_PCKLENUL		, 0xbc },
+	{ STB0899_PCKLENLL		, 0xcc },
+	{ STB0899_RSPCKLEN		, 0xbd },
+	{ STB0899_TSSTATUS		, 0x90 },
+	{ STB0899_ERRCTRL1		, 0xb6 },
+	{ STB0899_ERRCTRL2      	, 0x95 },
+	{ STB0899_ERRCTRL3      	, 0x8d },
+	{ STB0899_DMONMSK1		, 0x27 },
+	{ STB0899_DMONMSK0		, 0x03 },
+	{ STB0899_DEMAPVIT		, 0x5c },
+	{ STB0899_PLPARM		, 0x19 },
+	{ STB0899_PDELCTRL		, 0x48 },
+	{ STB0899_PDELCTRL2		, 0x00 },
+	{ STB0899_BBHCTRL1		, 0x00 },
+	{ STB0899_BBHCTRL2		, 0x00 },
+	{ STB0899_HYSTTHRESH		, 0x77 },
+	{ STB0899_MATCSTM		, 0x00 },
+	{ STB0899_MATCSTL		, 0x00 },
+	{ STB0899_UPLCSTM		, 0x00 },
+	{ STB0899_UPLCSTL		, 0x00 },
+	{ STB0899_DFLCSTM		, 0x00 },
+	{ STB0899_DFLCSTL		, 0x00 },
+	{ STB0899_SYNCCST		, 0x00 },
+	{ STB0899_SYNCDCSTM		, 0x00 },
+	{ STB0899_SYNCDCSTL		, 0x00 },
+	{ STB0899_ISI_ENTRY		, 0x00 },
+	{ STB0899_ISI_BIT_EN		, 0x00 },
+	{ STB0899_MATSTRM		, 0xf0 },
+	{ STB0899_MATSTRL		, 0x02 },
+	{ STB0899_UPLSTRM		, 0x45 },
+	{ STB0899_UPLSTRL		, 0x60 },
+	{ STB0899_DFLSTRM		, 0xe3 },
+	{ STB0899_DFLSTRL		, 0x00 },
+	{ STB0899_SYNCSTR		, 0x47 },
+	{ STB0899_SYNCDSTRM		, 0x05 },
+	{ STB0899_SYNCDSTRL		, 0x18 },
+	{ STB0899_CFGPDELSTATUS1	, 0x19 },
+	{ STB0899_CFGPDELSTATUS2	, 0x2b },
+	{ STB0899_BBFERRORM		, 0x00 },
+	{ STB0899_BBFERRORL		, 0x01 },
+	{ STB0899_UPKTERRORM		, 0x00 },
+	{ STB0899_UPKTERRORL		, 0x00 },
+	{ 0xffff			, 0xff },
+};
+
+
+static const struct stb0899_s2_reg pctv452e_init_s2_fec[] = {
+	{ STB0899_OFF0_BLOCK_LNGTH	, STB0899_BASE_BLOCK_LNGTH	, 0x00000008 },	/* BLOCKLNGTH	*/
+	{ STB0899_OFF0_ROW_STR		, STB0899_BASE_ROW_STR		, 0x000000b4 },	/* ROWSTR	*/
+	{ STB0899_OFF0_BN_END_ADDR	, STB0899_BASE_BN_END_ADDR	, 0x000004b5 },	/* BNANDADDR	*/
+	{ STB0899_OFF0_CN_END_ADDR	, STB0899_BASE_CN_END_ADDR	, 0x00000b4b },	/* CNANDADDR	*/
+	{ STB0899_OFF0_INFO_LENGTH	, STB0899_BASE_INFO_LENGTH	, 0x00000078 },	/* INFOLENGTH	*/
+	{ STB0899_OFF0_BOT_ADDR		, STB0899_BASE_BOT_ADDR		, 0x000001e0 },	/* BOT_ADDR	*/
+	{ STB0899_OFF0_BCH_BLK_LN	, STB0899_BASE_BCH_BLK_LN	, 0x0000a8c0 },	/* BCHBLKLN	*/
+	{ STB0899_OFF0_BCH_T		, STB0899_BASE_BCH_T		, 0x0000000c },	/* BCHT		*/
+	{ STB0899_OFF0_CNFG_MODE	, STB0899_BASE_CNFG_MODE	, 0x00000001 },	/* CNFGMODE	*/
+	{ STB0899_OFF0_LDPC_STAT	, STB0899_BASE_LDPC_STAT	, 0x0000000d },	/* LDPCSTAT	*/
+	{ STB0899_OFF0_ITER_SCALE	, STB0899_BASE_ITER_SCALE	, 0x00000040 },	/* ITERSCALE	*/
+	{ STB0899_OFF0_INPUT_MODE	, STB0899_BASE_INPUT_MODE	, 0x00000000 },	/* INPUTMODE	*/
+	{ STB0899_OFF0_LDPCDECRST	, STB0899_BASE_LDPCDECRST	, 0x00000000 },	/* LDPCDECRST	*/
+	{ STB0899_OFF0_CLK_PER_BYTE_RW	, STB0899_BASE_CLK_PER_BYTE_RW	, 0x00000008 },	/* CLKPERBYTE	*/
+	{ STB0899_OFF0_BCH_ERRORS	, STB0899_BASE_BCH_ERRORS	, 0x00000000 },	/* BCHERRORS	*/
+	{ STB0899_OFF0_LDPC_ERRORS	, STB0899_BASE_LDPC_ERRORS	, 0x00000000 },	/* LDPCERRORS	*/
+	{ STB0899_OFF0_BCH_MODE		, STB0899_BASE_BCH_MODE		, 0x00000000 },	/* BCHMODE	*/
+	{ STB0899_OFF0_ERR_ACC_PER	, STB0899_BASE_ERR_ACC_PER	, 0x00000008 },	/* ERRACCPER	*/
+	{ STB0899_OFF0_BCH_ERR_ACC	, STB0899_BASE_BCH_ERR_ACC	, 0x00000000 },	/* BCHERRACC	*/
+	{ STB0899_OFF0_FEC_TP_SEL	, STB0899_BASE_FEC_TP_SEL	, 0x00000000 },	/* FECTPSEL	*/
+	{ 0xffff			, 0xffffffff			, 0xffffffff },
+};
+
+static const struct stb0899_s1_reg pctv452e_init_tst[] = {
+	{ STB0899_TSTCK		, 0x00 },
+	{ STB0899_TSTRES	, 0x00 },
+	{ STB0899_TSTOUT	, 0x00 },
+	{ STB0899_TSTIN		, 0x00 },
+	{ STB0899_TSTSYS	, 0x00 },
+	{ STB0899_TSTCHIP	, 0x00 },
+	{ STB0899_TSTFREE	, 0x00 },
+	{ STB0899_TSTI2C	, 0x00 },
+	{ STB0899_BITSPEEDM	, 0x00 },
+	{ STB0899_BITSPEEDL	, 0x00 },
+	{ STB0899_TBUSBIT	, 0x00 },
+	{ STB0899_TSTDIS	, 0x00 },
+	{ STB0899_TSTDISRX	, 0x00 },
+	{ STB0899_TSTJETON	, 0x00 },
+	{ STB0899_TSTDCADJ	, 0x00 },
+	{ STB0899_TSTAGC1	, 0x00 },
+	{ STB0899_TSTAGC1N	, 0x00 },
+	{ STB0899_TSTPOLYPH	, 0x00 },
+	{ STB0899_TSTR		, 0x00 },
+	{ STB0899_TSTAGC2	, 0x00 },
+	{ STB0899_TSTCTL1	, 0x00 },
+	{ STB0899_TSTCTL2	, 0x00 },
+	{ STB0899_TSTCTL3	, 0x00 },
+	{ STB0899_TSTDEMAP	, 0x00 },
+	{ STB0899_TSTDEMAP2	, 0x00 },
+	{ STB0899_TSTDEMMON	, 0x00 },
+	{ STB0899_TSTRATE	, 0x00 },
+	{ STB0899_TSTSELOUT	, 0x00 },
+	{ STB0899_TSYNC		, 0x00 },
+	{ STB0899_TSTERR	, 0x00 },
+	{ STB0899_TSTRAM1	, 0x00 },
+	{ STB0899_TSTVSELOUT	, 0x00 },
+	{ STB0899_TSTFORCEIN	, 0x00 },
+	{ STB0899_TSTRS1	, 0x00 },
+	{ STB0899_TSTRS2	, 0x00 },
+	{ STB0899_TSTRS3	, 0x00 },
+	{ STB0899_GHOSTREG	, 0x81 },
+	{ 0xffff		, 0xff },
+};
+
+
+#define PCTV452E_DVBS2_ESNO_AVE			3
+#define PCTV452E_DVBS2_ESNO_QUANT		32
+#define PCTV452E_DVBS2_AVFRAMES_COARSE		10
+#define PCTV452E_DVBS2_AVFRAMES_FINE		20
+#define PCTV452E_DVBS2_MISS_THRESHOLD		6
+#define PCTV452E_DVBS2_UWP_THRESHOLD_ACQ	1125
+#define PCTV452E_DVBS2_UWP_THRESHOLD_TRACK	758
+#define PCTV452E_DVBS2_UWP_THRESHOLD_SOF	1350
+#define PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT	1664100
+
+#define PCTV452E_DVBS2_BTR_NCO_BITS		28
+#define PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET	15
+#define PCTV452E_DVBS2_CRL_NCO_BITS		30
+#define PCTV452E_DVBS2_LDPC_MAX_ITER		70
+
+
+static struct stb0899_config stb0899_config = {
+	.init_dev	= pctv452e_init_dev,
+	.init_s2_demod   = pctv452e_init_s2_demod,
+	.init_s1_demod   = pctv452e_init_s1_demod,
+	.init_s2_fec     = pctv452e_init_s2_fec,
+	.init_tst	= pctv452e_init_tst,
+
+	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
+	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
+
+	.xtal_freq       = 27000000,	 /* Assume Hz ? */
+	.inversion       = IQ_SWAP_ON,       /* ? */
+
+	.lo_clk	  = 76500000,
+	.hi_clk	  = 99000000,
+
+	.ts_output_mode  = 0,		/* Use parallel mode */
+	.clock_polarity  = 0,		/*  */
+	.data_clk_parity = 0,		/*  */
+	.fec_mode	= 0,		/*  */
+
+	.esno_ave	    = PCTV452E_DVBS2_ESNO_AVE,
+	.esno_quant	  = PCTV452E_DVBS2_ESNO_QUANT,
+	.avframes_coarse     = PCTV452E_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine       = PCTV452E_DVBS2_AVFRAMES_FINE,
+	.miss_threshold      = PCTV452E_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq   = PCTV452E_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track = PCTV452E_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof   = PCTV452E_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout  = PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits	  = PCTV452E_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset = PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits	  = PCTV452E_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter	 = PCTV452E_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL,
+
+	/* helper for switching LED green/orange */
+	.postproc = pctv45e_postproc
+};
+
+static struct stb6100_config stb6100_config = {
+	.tuner_address = I2C_ADDR_STB6100,
+	.refclock      = 27000000
+};
+
+
+static struct i2c_algorithm pctv452e_i2c_algo = {
+	.master_xfer   = pctv452e_i2c_xfer,
+	.functionality = pctv452e_i2c_func
+};
+
+
+static struct usb_device_id pctv452e_usb_table[] = {
+	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
+	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
+	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
+
+static struct dvb_usb_device_properties pctv452e_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv     = sizeof(struct pctv452e_state),
+
+	.identify_state   = 0, // this is a warm only device
+
+	.power_ctrl       = pctv452e_power_ctrl,
+	/* Untested. */
+	/* .read_mac_address = pctv452e_read_mac_address, */
+
+	.rc.legacy = {
+		.rc_map_table     = pctv452e_rc_keys,
+		.rc_map_size      = ARRAY_SIZE(pctv452e_rc_keys),
+		.rc_query         = pctv452e_rc_query,
+		.rc_interval      = 100,
+	},
+
+	.num_adapters     = 1,
+	.adapter = {{
+		.caps	     = 0,
+		.pid_filter_count = 0,
+
+		.streaming_ctrl   = NULL,
+
+		.frontend_attach  = pctv452e_frontend_attach,
+		.tuner_attach     = pctv452e_tuner_attach,
+
+		/* parameter for the MPEG2-data transfer */
+		.stream = {
+			.type     = USB_ISOC,
+			.count    = ISO_BUF_COUNT,
+			.endpoint = 0x02,
+			.u = {
+				.isoc = {
+					.framesperurb = FRAMES_PER_ISO_BUF,
+					.framesize    = ISO_FRAME_SIZE,
+					.interval     = 1
+				}
+			}
+		},
+		.size_of_priv     = 0
+	}},
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "PCTV HDTV USB",
+		  .cold_ids = { NULL, NULL }, // this is a warm only device
+		  .warm_ids = { &pctv452e_usb_table[0], NULL }
+		},
+		{ 0 },
+	}
+};
+
+static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv		= sizeof(struct pctv452e_state),
+
+	.identify_state		= 0, // this is a warm only device
+
+	.power_ctrl		= pctv452e_power_ctrl,
+	.read_mac_address	= pctv452e_read_mac_address,
+
+	.rc.legacy = {
+		.rc_map_table   = tt_connect_s2_3600_rc_key,
+		.rc_map_size    = ARRAY_SIZE(tt_connect_s2_3600_rc_key),
+		.rc_query       = pctv452e_rc_query,
+		.rc_interval    = 500,
+	},
+
+	.num_adapters		= 1,
+	.adapter = {{
+		.caps = 0,
+		.pid_filter_count = 0,
+
+		.streaming_ctrl = NULL,
+
+		.frontend_attach = pctv452e_frontend_attach,
+		.tuner_attach = pctv452e_tuner_attach,
+
+		/* parameter for the MPEG2-data transfer */
+		.stream = {
+			.type = USB_ISOC,
+			.count = 7,
+			.endpoint = 0x02,
+			.u = {
+				.isoc = {
+					.framesperurb = 4,
+					.framesize = 940,
+					.interval = 1
+				}
+			}
+		},
+		.size_of_priv = 0
+	}},
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
+
+	.num_device_descs = 2,
+	.devices = {
+		{ .name = "Technotrend TT Connect S2-3600",
+		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
+		  .warm_ids = { &pctv452e_usb_table[1], NULL }
+		},
+		{ .name = "Technotrend TT Connect S2-3650-CI",
+		  .cold_ids = { NULL, NULL },
+		  .warm_ids = { &pctv452e_usb_table[2], NULL }
+		},
+		{ 0 },
+	}
+};
+
+
+
+static struct usb_driver pctv452e_usb_driver = {
+#if LINUX_VERSION_CODE <=  KERNEL_VERSION(2,6,15)
+	.owner      = THIS_MODULE,
+#endif
+	.name       = "pctv452e",
+	.probe      = pctv452e_usb_probe,
+	.disconnect = pctv452e_usb_disconnect,
+	.id_table   = pctv452e_usb_table,
+};
+
+static struct usb_driver tt_connects2_3600_usb_driver = {
+#if LINUX_VERSION_CODE <=  KERNEL_VERSION(2,6,15)
+	.owner      = THIS_MODULE,
+#endif
+	.name       = "dvb-usb-tt-connect-s2-3600-01.fw",
+	.probe      = pctv452e_usb_probe,
+	.disconnect = pctv452e_usb_disconnect,
+	.id_table   = pctv452e_usb_table,
+};
+
+static int __init pctv452e_usb_init(void) {
+	int err=0;
+
+	if ((err = usb_register(&pctv452e_usb_driver))) {
+		printk("%s: usb_register failed! Error number %d", __FILE__, err);
+		return err;
+	}
+	if ((err = usb_register(&tt_connects2_3600_usb_driver))) {
+		printk("%s: usb_register failed! Error number %d", __FILE__, err);
+	}
+
+	return err;
+}
+
+static void __exit pctv452e_usb_exit(void)  {
+	usb_deregister(&pctv452e_usb_driver);
+	usb_deregister(&tt_connects2_3600_usb_driver);
+}
+
+module_init(pctv452e_usb_init);
+module_exit(pctv452e_usb_exit);
+
+MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
+MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
+MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
+MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 3b0c4bd..8e6f588 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
new file mode 100644
index 0000000..48377b2
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp22.c
@@ -0,0 +1,140 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21 driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp22.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+
+#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
+
+struct lnbp22 {
+	u8                 config[4];
+	struct i2c_adapter *i2c;
+};
+
+static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) {
+	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = (char*)&lnbp22->config,
+				.len = sizeof(lnbp22->config) };
+
+	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __FUNCTION__, voltage,
+	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
+
+	lnbp22->config[3] = 0x60; // Power down
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp22->config[3] |= LNBP22_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	dprintk(1, "%s: 0x%02x)\n", __FUNCTION__, lnbp22->config[3]);
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) {
+	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = (char*)&lnbp22->config,
+				.len = sizeof(lnbp22->config) };
+
+	dprintk(1, "%s: %d\n", __FUNCTION__, (int)arg);
+	if (arg)
+		lnbp22->config[3] |= LNBP22_LLC;
+	else
+		lnbp22->config[3] &= ~LNBP22_LLC;
+
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp22_release(struct dvb_frontend *fe)
+{
+
+	dprintk(1, "%s\n", __FUNCTION__);
+	/* LNBP power off */
+	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
+{
+	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
+	if (!lnbp22)
+		return NULL;
+
+	/* default configuration */
+	lnbp22->config[0] = 0x00; /* ? */
+	lnbp22->config[1] = 0x28; /* ? */
+	lnbp22->config[2] = 0x48; /* ? */
+	lnbp22->config[3] = 0x60; /* Power down */
+	lnbp22->i2c = i2c;
+	fe->sec_priv = lnbp22;
+
+	/* detect if it is present or not */
+	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		dprintk(0, "%s LNBP22 not found\n", __FUNCTION__);
+		kfree(lnbp22);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = lnbp22_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = lnbp22_set_voltage;
+	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
+
+	return fe;
+}
+EXPORT_SYMBOL(lnbp22_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
+MODULE_AUTHOR("Dominik Kuhlen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
new file mode 100644
index 0000000..4149c62
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp22.h
@@ -0,0 +1,51 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP22_H
+#define _LNBP22_H
+
+// Enable
+#define LNBP22_EN	  0x10
+// Voltage selection
+#define LNBP22_VSEL	0x02
+// Plus 1 Volt Bit
+#define LNBP22_LLC	0x01
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP22) || (defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_DVB_LNBP22
+
+#endif // _LNBP22_H
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
index 7dd54b3..0f54d4f 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
@@ -85,6 +85,31 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
 	return 0;
 }
 
+int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC)
+{
+	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
+		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
+		       0x1d, 0x36, 0x64, 0x78};
+	u8 data[20];
+	int i;
+
+	/* In case there is a sig check failure have the orig contents available */
+	memcpy(data, encodedMAC, 20);
+
+	for (i = 0; i < 20; i++)
+		data[i] ^= xor[i];
+	for (i = 0; i < 10; i++)
+		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
+			>> ((data[2 * i + 1] >> 6) & 3);
+
+	if (check_mac_tt(data))
+		return -ENODEV;
+
+	decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0];
+	decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4];
+	return 0;
+}
+
 static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
 {
 	int ret;
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h
index e2dc6cf..fea8bfc 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 
+extern int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC);
 extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
 
 #endif
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c      2011-07-23 11:00:49.000000000 +0000
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c      2011-07-23 11:04:00.000000000 +0000
@@ -165,6 +165,7 @@ int ttpci_eeprom_parse_mac(struct i2c_ad
 }
 
 EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
+EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
diff -Naur original-new-stb0899/linux/drivers/media/dvb/frontends/Kconfig 1/linux/drivers/media/dvb/frontends/Kconfig
--- a/drivers/media/dvb/frontends/Kconfig	2007-10-22 01:40:25.000000000 +0100
+++ b/drivers/media/dvb/frontends/Kconfig	2007-10-23 19:47:41.000000000 +0100
@@ -358,6 +358,12 @@
 	help
 	  An SEC control chip.
 
+config DVB_LNBP22
+	tristate "LNBP22 SEC controller"
+	depends on DVB_CORE && I2C
+	help
+	  An SEC control chip.
+
 config DVB_ISL6421
 	tristate "ISL6421 SEC controller"
 	depends on DVB_CORE && I2C
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-06-15 15:44       ` Igor M. Liplianin
@ 2011-09-13  6:04         ` Steffen Barszus
  2011-09-27  7:55           ` Dominik Kuhlen
  0 siblings, 1 reply; 18+ messages in thread
From: Steffen Barszus @ 2011-09-13  6:04 UTC (permalink / raw)
  To: Igor M. Liplianin
  Cc: linux-media, Doychin Dokov, Konstantin Dimitrov,
	Hans Petter Selasky, Dominik Kuhlen, Michael H. Schimek,
	Mauro Chehab

On Wed, 15 Jun 2011 18:44:35 +0300
"Igor M. Liplianin" <liplianin@me.by> wrote:

> From my point of view we can count the beginning was here:
> 
> http://www.spinics.net/lists/linux-dvb/msg26431.html
> 
> The later history is difficult to restore, but possible.
>

After some searching it looks like this is the first occurrence of the
driver:
http://www.linuxtv.org/pipermail/linux-dvb/2007-October/021403.html

Further it looks like Dominik Kuhlen is not responding at that mail (as
he has been on copy on one of the last mails. 

So looks like we cant get the signed-off-by from him. 

Does that mean the patch can't be applied and needs to be rewritten
from scratch even if the author put the code under GPL2 back then ? Is
there any rule for this ?

See comment of  Oliver Freyermuth - the driver seems to work (after
altering it to make it work with current kernel), also got some postive
feedback for it for kernel 2.6.38 and current 3.2 media_tree. 

Does someone have a definitive answer on how to go ahead ? What else is
missing ?

Thanks :) 

Steffen


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-05 21:27   ` Oliver Freyermuth
@ 2011-09-23 20:03     ` Mauro Carvalho Chehab
  2011-09-23 20:22       ` Steffen Barszus
                         ` (3 more replies)
  0 siblings, 4 replies; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2011-09-23 20:03 UTC (permalink / raw)
  To: Oliver Freyermuth
  Cc: Linux Media Mailing List, Doychin Dokov, Steffen Barszus,
	Igor M. Liplianin, Dominik Kuhlen, Andre Weidemann,
	Michael H. Schimek

Em 05-09-2011 18:27, Oliver Freyermuth escreveu:
> Got it working with kernel 3.0!
> 
> For me, some more changes on the current patchset appeared to be necessary.
> In short, I had to change all a->fe to a->fe[0] (because of 3.0-kernel)
> and I had to add lnbp22 to Kconfig (it would otherwise have been
> disabled and not been built, although other modules depended on it...).
> 
> I also had to add the additional
> "EXPORT_SYMBOL(ttpci_eeprom_decode_mac);" as mentioned by Doychin Dokov.
> 
> Attached is the 'new' version of the patch with the mentioned changes.

For it to be applied, we need the SOB's of the patch authors:

+MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
+MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
+MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");

Also, the patch needs some adjustments to be applied. See bellow for my quick review:

> diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
> index c545039..6d725ad 100644
> --- a/drivers/media/dvb/dvb-usb/Kconfig
> +++ b/drivers/media/dvb/dvb-usb/Kconfig
> @@ -250,6 +250,18 @@ config DVB_USB_AF9005
>  	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
>  	  and the TerraTec Cinergy T USB XE (Rev.1)
>  
> +config DVB_USB_PCTV452E
> +	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
> +	depends on DVB_USB
> +	select TTPCI_EEPROM
> +	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
> +	select DVB_STB0899 if !DVB_FE_CUSTOMISE
> +	select DVB_STB6100 if !DVB_FE_CUSTOMISE
> +	help
> +	  Support for external USB adapter designed by Pinnacle,
> +	  shipped under the brand name 'PCTV HDTV Pro USB'.
> +	  Say Y if you own such a device and want to use it.
> +
>  config DVB_USB_AF9005_REMOTE
>  	tristate "Afatech AF9005 default remote control support"
>  	depends on DVB_USB_AF9005
> diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
> index 4bac13d..2497694 100644
> --- a/drivers/media/dvb/dvb-usb/Makefile
> +++ b/drivers/media/dvb/dvb-usb/Makefile
> @@ -73,6 +73,9 @@ obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
>  dvb-usb-af9015-objs = af9015.o
>  obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
>  
> +dvb-usb-pctv452e-objs = pctv452e.o
> +obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
> +
>  dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
>  obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
>  
> diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> index 3a8b744..1c8a241 100644
> --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> @@ -237,6 +237,9 @@
>  #define USB_PID_PCTV_200E				0x020e
>  #define USB_PID_PCTV_400E				0x020f
>  #define USB_PID_PCTV_450E				0x0222
> +#define USB_PID_PCTV_452E				0x021f
> +#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
> +#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
>  #define USB_PID_NEBULA_DIGITV				0x0201
>  #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
>  #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
> diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
> new file mode 100644
> index 0000000..1be24e5
> --- /dev/null
> +++ b/drivers/media/dvb/dvb-usb/pctv452e.c
> @@ -0,0 +1,1454 @@
> +/*
> + * PCTV 452e DVB driver
> + *
> + * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
> + *
> + * TT connect S2-3650-CI Common Interface support, MAC readout
> + * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
> + *
> + * 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.
> + */
> +
> +/* dvb usb framework */
> +#define DVB_USB_LOG_PREFIX "pctv452e"
> +#include "dvb-usb.h"

Due to a change for 3.2, you'll need to include linux/module.h somewhere.

> +
> +/* Demodulator */
> +#include "stb0899_drv.h"
> +#include "stb0899_reg.h"
> +/* Tuner */
> +#include "stb6100.h"
> +#include "stb6100_cfg.h"
> +/* FE Power */
> +#include "lnbp22.h"
> +
> +#include "dvb_ca_en50221.h"
> +#include "ttpci-eeprom.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
> +
> +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
> +
> +#define ISO_BUF_COUNT      4
> +#define FRAMES_PER_ISO_BUF 4
> +#define ISO_FRAME_SIZE     940
> +#define ISOC_INTERFACE_ALTERNATIVE 3
> +
> +#define SYNC_BYTE_OUT 0xaa
> +#define SYNC_BYTE_IN  0x55
> +
> +/* guessed: (copied from ttusb-budget) */
> +#define PCTV_CMD_RESET 0x15
> +/* command to poll IR receiver */
> +#define PCTV_CMD_IR    0x1b
> +/* command to send I2C  */
> +#define PCTV_CMD_I2C   0x31
> +
> +#define I2C_ADDR_STB0899 (0xd0 >> 1)
> +#define I2C_ADDR_STB6100 (0xc0 >> 1)
> +#define I2C_ADDR_LNBP22  (0x10 >> 1)
> +#define I2C_ADDR_24C16   (0xa0 >> 1)
> +#define I2C_ADDR_24C64   (0xa2 >> 1)
> +
> +
> +/* pctv452e sends us this amount of data for each issued usb-command */
> +#define PCTV_ANSWER_LEN 64
> +/* Wait up to 1000ms for device  */
> +#define PCTV_TIMEOUT 1000
> +
> +
> +#define PCTV_LED_GPIO   STB0899_GPIO01
> +#define PCTV_LED_GREEN  0x82
> +#define PCTV_LED_ORANGE 0x02
> +
> +#define ci_dbg(format, arg...)				\
> +do {							\
> +	if (0)						\
> +		printk (KERN_DEBUG DVB_USB_LOG_PREFIX	\
> +			": " format "\n" , ## arg);	\
> +} while (0)
> +
> +enum {
> +	TT3650_CMD_CI_TEST = 0x40,
> +	TT3650_CMD_CI_RD_CTRL,
> +	TT3650_CMD_CI_WR_CTRL,
> +	TT3650_CMD_CI_RD_ATTR,
> +	TT3650_CMD_CI_WR_ATTR,
> +	TT3650_CMD_CI_RESET,
> +	TT3650_CMD_CI_SET_VIDEO_PORT
> +};
> +
> +
> +static struct stb0899_postproc pctv45e_postproc[] = {
> +	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
> +	{ 0, 0 }
> +};
> +
> +/*
> + * stores all private variables for communication with the PCTV452e DVB-S2
> + */
> +struct pctv452e_state {
> +	struct dvb_ca_en50221 ca;
> +	struct mutex ca_mutex;
> +
> +	u8 c;	   /* transaction counter, wraps around...  */
> +	u8 initialized; /* set to 1 if 0x15 has been sent */
> +};
> +
> +static int
> +tt3650_ci_msg			(struct dvb_usb_device *d,
> +				 u8			cmd,
> +				 u8 *			data,
> +				 unsigned int		write_len,
> +				 unsigned int		read_len)
> +{
> +	struct pctv452e_state *state = (struct pctv452e_state *) d->priv;
> +	u8 buf[64];
> +	u8 id;
> +	unsigned int rlen;
> +	int ret;
> +
> +	BUG_ON (NULL == data && 0 != (write_len | read_len));
> +	BUG_ON (write_len > 64 - 4);
> +	BUG_ON (read_len > 64 - 4);
> +
> +	id = state->c++;
> +
> +	buf[0] = SYNC_BYTE_OUT;
> +	buf[1] = id;
> +	buf[2] = cmd;
> +	buf[3] = write_len;
> +
> +	memcpy (buf + 4, data, write_len);
> +
> +	rlen = (read_len > 0) ? 64 : 0;
> +	ret = dvb_usb_generic_rw (d, buf, 4 + write_len,
> +				  buf, rlen, /* delay_ms */ 0);
> +	if (0 != ret)
> +		goto failed;
> +
> +	ret = -EIO;
> +	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
> +		goto failed;
> +
> +	memcpy (data, buf + 4, read_len);
> +
> +	return 0;
> +
> + failed:
> +	err ("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
> +	     ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
> +
> +	return ret;
> +}
> +
> +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
> +				 u8			cmd,
> +				 u8 *			data,
> +				 unsigned int		write_len,
> +				 unsigned int		read_len)
> +{
> +	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	int ret;
> +
> +	mutex_lock(&state->ca_mutex);
> +	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
> +	mutex_unlock(&state->ca_mutex);
> +
> +	return ret;
> +}
> +
> +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			address)
> +{
> +	u8 buf[3];
> +	int ret;
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = (address >> 8) & 0x0F;
> +	buf[1] = address;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
> +
> +	ci_dbg ("%s %04x -> %d 0x%02x",
> +		__func__, address, ret, buf[2]);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return buf[2];
> +}
> +
> +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			address,
> +				 u8			value)
> +{
> +	u8 buf[3];
> +
> +	ci_dbg("%s %d 0x%04x 0x%02x",
> +		__func__, slot, address, value);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = (address >> 8) & 0x0F;
> +	buf[1] = address;
> +	buf[2] = value;
> +
> +	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
> +}
> +
> +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 u8			address)
> +{
> +	u8 buf[2];
> +	int ret;
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = address & 3;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
> +
> +	ci_dbg("%s 0x%02x -> %d 0x%02x",
> +		__func__, address, ret, buf[1]);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return buf[1];
> +}
> +
> +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 u8			address,
> +				 u8			value)
> +{
> +	u8 buf[2];
> +
> +	ci_dbg("%s %d 0x%02x 0x%02x",
> +		__func__, slot, address, value);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = address;
> +	buf[1] = value;
> +
> +	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
> +}
> +
> +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			enable)
> +{
> +	u8 buf[1];
> +	int ret;
> +
> +	ci_dbg("%s %d %d", __func__, slot, enable);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	enable = !!enable;
> +	buf[0] = enable;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (enable != buf[0]) {
> +		err("CI not %sabled.", enable ? "en" : "dis");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca,
> +				 int			slot)
> +{
> +	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
> +}
> +
> +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca,
> +				 int			slot)
> +{
> +	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
> +}
> +
> +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca,
> +				 int			slot)
> +{
> +	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	u8 buf[1];
> +	int ret;
> +
> +	ci_dbg ("%s %d", __func__, slot);
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	buf[0] = 0;
> +
> +	mutex_lock (&state->ca_mutex);
> +
> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
> +	if (0 != ret)
> +		goto failed;
> +
> +	msleep (500);
> +
> +	buf[0] = 1;
> +
> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
> +	if (0 != ret)
> +		goto failed;
> +
> +	msleep (500);
> +
> +	buf[0] = 0; /* FTA */
> +
> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
> +
> + failed:
> +	mutex_unlock (&state->ca_mutex);
> +
> +	return ret;
> +}
> +
> +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
> +				 int			slot,
> +				 int			open)
> +{
> +	u8 buf[1];
> +	int ret;
> +
> +	if (0 != slot)
> +		return -EINVAL;
> +
> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
> +	if (0 != ret)
> +		return ret;
> +
> +	if (1 == buf[0]) {
> +		return (DVB_CA_EN50221_POLL_CAM_PRESENT |
> +			DVB_CA_EN50221_POLL_CAM_READY);
> +	} else {
> +		return 0;
> +	}
> +}
> +
> +static void tt3650_ci_uninit(struct dvb_usb_device *d)
> +{
> +	struct pctv452e_state *state;
> +
> +	ci_dbg("%s", __func__);
> +
> +	if (NULL == d)
> +		return;
> +
> +	state = (struct pctv452e_state *)d->priv;
> +	if (NULL == state)
> +		return;
> +
> +	if (NULL == state->ca.data)
> +		return;
> +
> +	/* Error ignored. */
> +	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
> +
> +	dvb_ca_en50221_release(&state->ca);
> +
> +	memset(&state->ca, 0, sizeof(state->ca));
> +}
> +
> +static int tt3650_ci_init(struct dvb_usb_adapter *a)
> +{
> +	struct dvb_usb_device *d = a->dev;
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	int ret;
> +
> +	ci_dbg ("%s", __func__);
> +
> +	mutex_init(&state->ca_mutex);
> +
> +	state->ca.owner = THIS_MODULE;
> +	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
> +	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
> +	state->ca.read_cam_control = tt3650_ci_read_cam_control;
> +	state->ca.write_cam_control = tt3650_ci_write_cam_control;
> +	state->ca.slot_reset = tt3650_ci_slot_reset;
> +	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
> +	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
> +	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
> +	state->ca.data = d;
> +
> +	ret = dvb_ca_en50221_init (&a->dvb_adap,
> +				   &state->ca,
> +				   /* flags */ 0,
> +				   /* n_slots */ 1);
> +	if (0 != ret) {
> +		err ("Cannot initialize CI: Error %d.", ret);
> +		memset (&state->ca, 0, sizeof (state->ca));
> +		return ret;
> +	}
> +
> +	info ("CI initialized.");
> +
> +	return 0;
> +}
> +
> +  #define CMD_BUFFER_SIZE 0x28
> +static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, const u8 * snd_buf,
> +				u8 snd_len, u8 * rcv_buf, u8 rcv_len) {
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	u8 buf[64];
> +	u8 id;
> +	int ret;
> +
> +	id = state->c++;
> +
> +	ret = -EINVAL;
> +	if (snd_len > 64 - 7 || rcv_len > 64 - 7)
> +		goto failed;
> +
> +	buf[0] = SYNC_BYTE_OUT;
> +	buf[1] = id;
> +	buf[2] = PCTV_CMD_I2C;
> +	buf[3] = snd_len + 3;
> +	buf[4] = addr << 1;
> +	buf[5] = snd_len;
> +	buf[6] = rcv_len;
> +
> +	memcpy (buf + 7, snd_buf, snd_len);
> +
> +	ret = dvb_usb_generic_rw (d, buf, 7 + snd_len,
> +				  buf, /* rcv_len */ 64,
> +				  /* delay_ms */ 0);
> +	if (ret < 0)
> +		goto failed;
> +
> +	/* TT USB protocol error. */
> +	ret = -EIO;
> +	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
> +		goto failed;
> +
> +	/* I2C device didn't respond as expected. */
> +	ret = -EREMOTEIO;
> +	if (buf[5] < snd_len || buf[6] < rcv_len)
> +		goto failed;
> +
> +	memcpy (rcv_buf, buf + 7, rcv_len);
> +
> +	return rcv_len;
> +
> + failed:
> +	err ("I2C error %d; %02X %02X  %02X %02X %02X -> "
> +	     "%02X %02X  %02X %02X %02X.",
> +	     ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
> +	     buf[0], buf[1], buf[4], buf[5], buf[6]);
> +
> +	return ret;
> +}
> +
> +static int pctv452e_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) {
> +	struct dvb_usb_device *d= i2c_get_adapdata(adapter);
> +	int i;
> +
> +	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
> +		return -EAGAIN;
> +
> +	for (i = 0; i < num; i++) {
> +		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
> +		int err;
> +
> +		if (msg[i].flags & I2C_M_RD) {
> +			addr = msg[i].addr;
> +			snd_buf = NULL;
> +			snd_len = 0;
> +			rcv_buf = msg[i].buf;
> +			rcv_len = msg[i].len;
> +		} else {
> +			addr = msg[i].addr;
> +			snd_buf = msg[i].buf;
> +			snd_len = msg[i].len;
> +			rcv_buf = NULL;
> +			rcv_len = 0;
> +		}
> +
> +		err = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf, rcv_len);
> +		if (err < rcv_len)
> +			break;
> +	}
> +
> +	mutex_unlock(&d->i2c_mutex);
> +	return i;
> +}
> +
> +static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) {
> +	return I2C_FUNC_I2C;
> +}
> +
> +int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) {
> +	struct pctv452e_state *state = (struct pctv452e_state*)d->priv;
> +	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
> +	u8 rx[PCTV_ANSWER_LEN];
> +	int ret;
> +		printk("%s: %d\n", __func__, i);
> +	if (i) {
> +		if (!state->initialized) {
> +			// hmm where shoud this should go?
> +			ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
> +			if (ret != 0) {
> +				printk("%s: Warning set interface returned: %d\n", __func__, ret);
> +			}
> +
> +			// this is a one-time initialization, dont know where to put
> +			b0[1] = state->c++;
> +			// reset board
> +			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
> +
> +			b0[1] = state->c++;
> +			b0[4] = 1;
> +			// reset board (again?)
> +			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
> +
> +			state->initialized = 1;
> +		}
> +	} else {
> +		// power down ?
> +	}
> +	return 0;
> +}
> +
> +/* Remote control stuff */
> +static struct rc_map_table pctv452e_rc_keys[] = {
> +	{0x0700, KEY_MUTE},
> +	{0x0701, KEY_VENDOR},  // pinnacle logo (top middle)
> +	{0x0739, KEY_POWER},
> +	{0x0703, KEY_VOLUMEUP},
> +	{0x0709, KEY_VOLUMEDOWN},
> +	{0x0706, KEY_CHANNELUP},
> +	{0x070c, KEY_CHANNELDOWN},
> +	{0x070f, KEY_1},
> +	{0x0715, KEY_2},
> +	{0x0710, KEY_3},
> +	{0x0718, KEY_4},
> +	{0x071b, KEY_5},
> +	{0x071e, KEY_6},
> +	{0x0711, KEY_7},
> +	{0x0721, KEY_8},
> +	{0x0712, KEY_9},
> +	{0x0727, KEY_0},
> +	{0x0724, KEY_TV}, // left of '0'
> +	{0x072a, KEY_T}, // right of '0'
> +	{0x072d, KEY_REWIND},
> +	{0x0733, KEY_FORWARD},
> +	{0x0730, KEY_PLAY},
> +	{0x0736, KEY_RECORD},
> +	{0x073c, KEY_STOP},
> +	{0x073f, KEY_HELP}
> +};
> +
> +/* Remote Control Stuff fo S2-3600 (copied from TT-S1500): */
> +static struct rc_map_table tt_connect_s2_3600_rc_key[] = {
> +	{0x1501, KEY_POWER},
> +	{0x1502, KEY_SHUFFLE}, /* ? double-arrow key */
> +	{0x1503, KEY_1},
> +	{0x1504, KEY_2},
> +	{0x1505, KEY_3},
> +	{0x1506, KEY_4},
> +	{0x1507, KEY_5},
> +	{0x1508, KEY_6},
> +	{0x1509, KEY_7},
> +	{0x150a, KEY_8},
> +	{0x150b, KEY_9},
> +	{0x150c, KEY_0},
> +	{0x150d, KEY_UP},
> +	{0x150e, KEY_LEFT},
> +	{0x150f, KEY_OK},
> +	{0x1510, KEY_RIGHT},
> +	{0x1511, KEY_DOWN},
> +	{0x1512, KEY_INFO},
> +	{0x1513, KEY_EXIT},
> +	{0x1514, KEY_RED},
> +	{0x1515, KEY_GREEN},
> +	{0x1516, KEY_YELLOW},
> +	{0x1517, KEY_BLUE},
> +	{0x1518, KEY_MUTE},
> +	{0x1519, KEY_TEXT},
> +	{0x151a, KEY_MODE},  /* ? TV/Radio */
> +	{0x1521, KEY_OPTION},
> +	{0x1522, KEY_EPG},
> +	{0x1523, KEY_CHANNELUP},
> +	{0x1524, KEY_CHANNELDOWN},
> +	{0x1525, KEY_VOLUMEUP},
> +	{0x1526, KEY_VOLUMEDOWN},
> +	{0x1527, KEY_SETUP},
> +	{0x153a, KEY_RECORD},/* these keys are only in the black remote */
> +	{0x153b, KEY_PLAY},
> +	{0x153c, KEY_STOP},
> +	{0x153d, KEY_REWIND},
> +	{0x153e, KEY_PAUSE},
> +	{0x153f, KEY_FORWARD}
> +};

Keytables should be moved to drivers/media/rc/keymaps

> +
> +static int pctv452e_rc_query(struct dvb_usb_device *d, u32 *keyevent, int *keystate) {
> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
> +	u8 b[CMD_BUFFER_SIZE];
> +	u8 rx[PCTV_ANSWER_LEN];
> +	u8 keybuf[5];
> +	int ret, i;
> +	u8 id = state->c++;
> +
> +	/* prepare command header  */
> +	b[0] = SYNC_BYTE_OUT;
> +	b[1] = id;
> +	b[2] = PCTV_CMD_IR;
> +	b[3] = 0;
> +
> +	*keystate = REMOTE_NO_KEY_PRESSED;
> +
> +	/* send ir request */
> +	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
> +	if (ret != 0) return ret;
> +
> +	if (debug > 3) {
> +		printk("%s: read: %2d: %02x %02x %02x: ", __func__, ret, rx[0], rx[1], rx[2]);
> +		for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) {
> +			printk(" %02x", rx[i+3]);
> +		}
> +		printk("\n");
> +	}
> +
> +	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
> +		/* got a "press" event */
> +		if (debug > 2) {
> +	 		printk("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[6], rx[7]);
> +		}
> +		keybuf[0] = 0x01;// DVB_USB_RC_NEC_KEY_PRESSED; why is this #define'd privately?
> +		keybuf[1] = rx[7];
> +		keybuf[2] = ~keybuf[1]; // fake checksum
> +		keybuf[3] = rx[6];
> +		keybuf[4] = ~keybuf[3]; // fake checksum
> +		dvb_usb_nec_rc_key_to_event(d, keybuf, keyevent, keystate);
> +
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +pctv452e_read_mac_address	(struct dvb_usb_device *d,
> +				 u8			mac[6])
> +{
> +	const u8 mem_addr[] = { 0x1F, 0xCC };
> +	u8 encoded_mac[20];
> +	int ret;
> +
> +	ret = -EAGAIN;
> +	if (mutex_lock_interruptible (&d->i2c_mutex) < 0)
> +		goto failed;
> +
> +	ret = pctv452e_i2c_msg (d, I2C_ADDR_24C16,
> +				mem_addr + 1, /* snd_len */ 1,
> +				encoded_mac, /* rcv_len */ 20);
> +	if (-EREMOTEIO == ret) {
> +		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
> +		   byte write if /WC is low. */
> +		ret = pctv452e_i2c_msg (d, I2C_ADDR_24C64,
> +					mem_addr, 2,
> +					encoded_mac, 20);
> +	}
> +
> +	mutex_unlock (&d->i2c_mutex);
> +
> +	if (20 != ret)
> +		goto failed;
> +
> +	ret = ttpci_eeprom_decode_mac (mac, encoded_mac);
> +	if (0 != ret)
> +		goto failed;
> +
> +	return 0;
> +
> + failed:
> +	memset (mac, 0, 6);
> +
> +	return ret;
> +}
> +
> +
> +static struct stb0899_config stb0899_config;
> +static struct stb6100_config stb6100_config;
> +static struct dvb_usb_device_properties pctv452e_properties;
> +static struct dvb_usb_device_properties tt_connect_s2_3600_properties;
> +
> +int pctv452e_frontend_attach(struct dvb_usb_adapter *a) {
> +	struct usb_device_id *id;
> +
> +		printk("%s Enter\n", __func__);
> +
> +	a->fe[0] = dvb_attach(stb0899_attach, &stb0899_config, &a->dev->i2c_adap);
> +	if (!a->fe[0]) return -ENODEV;
> +	if ((dvb_attach(lnbp22_attach, a->fe[0], &a->dev->i2c_adap)) == 0) {
> +		printk("Warning: cannot attach lnbp22\n");
> +	}
> +
> +	id = a->dev->desc->warm_ids[0];
> +	if (USB_VID_TECHNOTREND == id->idVendor
> +	    && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct) {
> +		/* Error ignored. */
> +		tt3650_ci_init (a);
> +	}
> +
> +		printk("%s Leave Ok\n", __func__);
> +	return 0;
> +}
> +
> +int pctv452e_tuner_attach(struct dvb_usb_adapter *a) {
> +		printk("%s Enter\n", __func__);
> +	if (!a->fe[0]) return -ENODEV;
> +	if (dvb_attach(stb6100_attach, a->fe[0], &stb6100_config, &a->dev->i2c_adap) == 0) {
> +		printk("%s failed\n", __func__);
> +		return -ENODEV;
> +	}
> +		printk("%s Leave\n", __func__);
> +	return 0;
> +}
> +
> +static void
> +pctv452e_usb_disconnect		(struct usb_interface *	intf)
> +{
> +	struct dvb_usb_device *d = usb_get_intfdata (intf);
> +
> +	tt3650_ci_uninit (d);
> +	dvb_usb_device_exit (intf);
> +}
> +
> +static int pctv452e_usb_probe(struct usb_interface *intf,const struct usb_device_id *id) {
> +	int ret=-ENOMEM;
> +	if ((ret=dvb_usb_device_init(intf, &pctv452e_properties, THIS_MODULE, NULL, adapter_nr))==0){
> +		return ret;
> +	}
> +	return dvb_usb_device_init(intf, &tt_connect_s2_3600_properties, THIS_MODULE, NULL, adapter_nr);
> +}
> +
> +
> +
> +static const struct stb0899_s1_reg pctv452e_init_dev [] = {
> +	{ STB0899_DISCNTRL1	, 0x26 },
> +	{ STB0899_DISCNTRL2	, 0x80 },
> +	{ STB0899_DISRX_ST0	, 0x04 },
> +	{ STB0899_DISRX_ST1	, 0x20 },
> +	{ STB0899_DISPARITY	, 0x00 },
> +	{ STB0899_DISFIFO	, 0x00 },
> +	{ STB0899_DISF22	, 0x99 },
> +	{ STB0899_DISF22RX	, 0x85 }, // 0xa8
> +	{ STB0899_ACRPRESC	, 0x11 },
> +	{ STB0899_ACRDIV1	, 0x0a },
> +	{ STB0899_ACRDIV2	, 0x05 },
> +	{ STB0899_DACR1		, 0x00 },
> +	{ STB0899_DACR2		, 0x00 },
> +	{ STB0899_OUTCFG	, 0x00 },
> +	{ STB0899_MODECFG	, 0x00 }, // Inversion
> + 	{ STB0899_IRQMSK_3	, 0xf3 },
> + 	{ STB0899_IRQMSK_2	, 0xfc },
> + 	{ STB0899_IRQMSK_1	, 0xff },
> + 	{ STB0899_IRQMSK_0	, 0xff },
> +	{ STB0899_I2CCFG	, 0x88 },
> +	{ STB0899_I2CRPT	, 0x58 },
> +	{ STB0899_GPIO00CFG	, 0x82 },
> +	{ STB0899_GPIO01CFG	, 0x82 }, /* 0x02 -> LED green 0x82 -> LED orange */
> +	{ STB0899_GPIO02CFG	, 0x82 },
> +	{ STB0899_GPIO03CFG	, 0x82 },
> +	{ STB0899_GPIO04CFG	, 0x82 },
> +	{ STB0899_GPIO05CFG	, 0x82 },
> +	{ STB0899_GPIO06CFG	, 0x82 },
> +	{ STB0899_GPIO07CFG	, 0x82 },
> +	{ STB0899_GPIO08CFG	, 0x82 },
> +	{ STB0899_GPIO09CFG	, 0x82 },
> +	{ STB0899_GPIO10CFG	, 0x82 },
> +	{ STB0899_GPIO11CFG	, 0x82 },
> +	{ STB0899_GPIO12CFG	, 0x82 },
> +	{ STB0899_GPIO13CFG	, 0x82 },
> +	{ STB0899_GPIO14CFG	, 0x82 },
> +	{ STB0899_GPIO15CFG	, 0x82 },
> +	{ STB0899_GPIO16CFG	, 0x82 },
> +	{ STB0899_GPIO17CFG	, 0x82 },
> +	{ STB0899_GPIO18CFG	, 0x82 },
> +	{ STB0899_GPIO19CFG	, 0x82 },
> +	{ STB0899_GPIO20CFG	, 0x82 },
> +	{ STB0899_SDATCFG	, 0xb8 },
> +	{ STB0899_SCLTCFG	, 0xba },
> +	{ STB0899_AGCRFCFG	, 0x1c }, // 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm)
> +	{ STB0899_GPIO22	, 0x82 },
> +	{ STB0899_GPIO21	, 0x91 },
> +	{ STB0899_DIRCLKCFG	, 0x82 },
> +	{ STB0899_CLKOUT27CFG	, 0x7e },
> +	{ STB0899_STDBYCFG	, 0x82 },
> +	{ STB0899_CS0CFG	, 0x82 },
> +	{ STB0899_CS1CFG	, 0x82 },
> +	{ STB0899_DISEQCOCFG	, 0x20 },
> +	{ STB0899_NCOARSE	, 0x15 }, // 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 108MHz
> +	{ STB0899_SYNTCTRL	, 0x00 }, // 0x00 = CLK from CLKI, 0x02 = CLK from XTALI
> +	{ STB0899_FILTCTRL	, 0x00 },
> +	{ STB0899_SYSCTRL	, 0x00 },
> +	{ STB0899_STOPCLK1	, 0x20 }, // orig: 0x00 budget-ci: 0x20
> +	{ STB0899_STOPCLK2	, 0x00 },
> +	{ STB0899_INTBUFCTRL	, 0x0a },
> +	{ STB0899_AGC2I1	, 0x00 },
> +	{ STB0899_AGC2I2	, 0x00 },
> +	{ STB0899_AGCIQIN       , 0x00 },
> +	{ STB0899_TSTRES	, 0x40 }, //rjkm
> +	{0xffff, 0xff},
> +};
> +
> +static const struct stb0899_s2_reg pctv452e_init_s2_demod[]  = {
> +	{ STB0899_OFF0_DMD_STATUS	, STB0899_BASE_DMD_STATUS	, 0x00000103 },	/* DMDSTATUS	*/
> +	{ STB0899_OFF0_CRL_FREQ		, STB0899_BASE_CRL_FREQ		, 0x3ed1da56 },	/* CRLFREQ	*/
> +	{ STB0899_OFF0_BTR_FREQ		, STB0899_BASE_BTR_FREQ		, 0x00004000 },	/* BTRFREQ	*/
> +	{ STB0899_OFF0_IF_AGC_GAIN	, STB0899_BASE_IF_AGC_GAIN	, 0x00002ade },	/* IFAGCGAIN	*/
> +	{ STB0899_OFF0_BB_AGC_GAIN	, STB0899_BASE_BB_AGC_GAIN	, 0x000001bc },	/* BBAGCGAIN	*/
> +	{ STB0899_OFF0_DC_OFFSET	, STB0899_BASE_DC_OFFSET	, 0x00000200 },	/* DCOFFSET	*/
> +	{ STB0899_OFF0_DMD_CNTRL	, STB0899_BASE_DMD_CNTRL	, 0x0000000f },	/* DMDCNTRL	*/
> +
> +	{ STB0899_OFF0_IF_AGC_CNTRL	, STB0899_BASE_IF_AGC_CNTRL	, 0x03fb4a20 },	/* IFAGCCNTRL	*/
> +	{ STB0899_OFF0_BB_AGC_CNTRL	, STB0899_BASE_BB_AGC_CNTRL	, 0x00200c97 },	/* BBAGCCNTRL	*/
> +
> +	{ STB0899_OFF0_CRL_CNTRL	, STB0899_BASE_CRL_CNTRL	, 0x00000016 },	/* CRLCNTRL	*/
> +	{ STB0899_OFF0_CRL_PHS_INIT	, STB0899_BASE_CRL_PHS_INIT	, 0x00000000 },	/* CRLPHSINIT	*/
> +	{ STB0899_OFF0_CRL_FREQ_INIT	, STB0899_BASE_CRL_FREQ_INIT	, 0x00000000 },	/* CRLFREQINIT	*/
> +	{ STB0899_OFF0_CRL_LOOP_GAIN	, STB0899_BASE_CRL_LOOP_GAIN	, 0x00000000 },	/* CRLLOOPGAIN	*/
> +	{ STB0899_OFF0_CRL_NOM_FREQ	, STB0899_BASE_CRL_NOM_FREQ	, 0x3ed097b6 },	/* CRLNOMFREQ	*/
> +	{ STB0899_OFF0_CRL_SWP_RATE	, STB0899_BASE_CRL_SWP_RATE	, 0x00000000 },	/* CRLSWPRATE	*/
> +	{ STB0899_OFF0_CRL_MAX_SWP	, STB0899_BASE_CRL_MAX_SWP	, 0x00000000 },	/* CRLMAXSWP	*/
> +	{ STB0899_OFF0_CRL_LK_CNTRL	, STB0899_BASE_CRL_LK_CNTRL	, 0x0f6cdc01 },	/* CRLLKCNTRL	*/
> +	{ STB0899_OFF0_DECIM_CNTRL	, STB0899_BASE_DECIM_CNTRL	, 0x00000000 },	/* DECIMCNTRL	*/
> +	{ STB0899_OFF0_BTR_CNTRL	, STB0899_BASE_BTR_CNTRL	, 0x00003993 },	/* BTRCNTRL	*/
> +	{ STB0899_OFF0_BTR_LOOP_GAIN	, STB0899_BASE_BTR_LOOP_GAIN	, 0x000d3c6f },	/* BTRLOOPGAIN	*/
> +	{ STB0899_OFF0_BTR_PHS_INIT	, STB0899_BASE_BTR_PHS_INIT	, 0x00000000 },	/* BTRPHSINIT	*/
> +	{ STB0899_OFF0_BTR_FREQ_INIT	, STB0899_BASE_BTR_FREQ_INIT	, 0x00000000 },	/* BTRFREQINIT	*/
> +	{ STB0899_OFF0_BTR_NOM_FREQ	, STB0899_BASE_BTR_NOM_FREQ	, 0x0238e38e },	/* BTRNOMFREQ	*/
> +	{ STB0899_OFF0_BTR_LK_CNTRL	, STB0899_BASE_BTR_LK_CNTRL	, 0x00000000 },	/* BTRLKCNTRL	*/
> +	{ STB0899_OFF0_DECN_CNTRL	, STB0899_BASE_DECN_CNTRL	, 0x00000000 },	/* DECNCNTRL	*/
> +	{ STB0899_OFF0_TP_CNTRL		, STB0899_BASE_TP_CNTRL		, 0x00000000 },	/* TPCNTRL	*/
> +	{ STB0899_OFF0_TP_BUF_STATUS	, STB0899_BASE_TP_BUF_STATUS	, 0x00000000 },	/* TPBUFSTATUS	*/
> +	{ STB0899_OFF0_DC_ESTIM		, STB0899_BASE_DC_ESTIM		, 0x00000000 },	/* DCESTIM	*/
> +	{ STB0899_OFF0_FLL_CNTRL	, STB0899_BASE_FLL_CNTRL	, 0x00000000 },	/* FLLCNTRL	*/
> +	{ STB0899_OFF0_FLL_FREQ_WD	, STB0899_BASE_FLL_FREQ_WD	, 0x40070000 },	/* FLLFREQWD	*/
> +	{ STB0899_OFF0_ANTI_ALIAS_SEL	, STB0899_BASE_ANTI_ALIAS_SEL	, 0x00000001 },	/* ANTIALIASSEL */
> +	{ STB0899_OFF0_RRC_ALPHA	, STB0899_BASE_RRC_ALPHA	, 0x00000002 },	/* RRCALPHA	*/
> +	{ STB0899_OFF0_DC_ADAPT_LSHFT	, STB0899_BASE_DC_ADAPT_LSHFT	, 0x00000000 },	/* DCADAPTISHFT */
> +	{ STB0899_OFF0_IMB_OFFSET	, STB0899_BASE_IMB_OFFSET	, 0x0000fe01 },	/* IMBOFFSET	*/
> +	{ STB0899_OFF0_IMB_ESTIMATE	, STB0899_BASE_IMB_ESTIMATE	, 0x00000000 },	/* IMBESTIMATE	*/
> +	{ STB0899_OFF0_IMB_CNTRL	, STB0899_BASE_IMB_CNTRL	, 0x00000001 },	/* IMBCNTRL	*/
> +	{ STB0899_OFF0_IF_AGC_CNTRL2	, STB0899_BASE_IF_AGC_CNTRL2	, 0x00005007 },	/* IFAGCCNTRL2	*/
> +	{ STB0899_OFF0_DMD_CNTRL2	, STB0899_BASE_DMD_CNTRL2	, 0x00000002 },	/* DMDCNTRL2	*/
> +	{ STB0899_OFF0_TP_BUFFER	, STB0899_BASE_TP_BUFFER	, 0x00000000 },	/* TPBUFFER	*/
> +	{ STB0899_OFF0_TP_BUFFER1	, STB0899_BASE_TP_BUFFER1	, 0x00000000 },	/* TPBUFFER1	*/
> +	{ STB0899_OFF0_TP_BUFFER2	, STB0899_BASE_TP_BUFFER2	, 0x00000000 },	/* TPBUFFER2	*/
> +	{ STB0899_OFF0_TP_BUFFER3	, STB0899_BASE_TP_BUFFER3	, 0x00000000 },	/* TPBUFFER3	*/
> +	{ STB0899_OFF0_TP_BUFFER4	, STB0899_BASE_TP_BUFFER4	, 0x00000000 },	/* TPBUFFER4	*/
> +	{ STB0899_OFF0_TP_BUFFER5	, STB0899_BASE_TP_BUFFER5	, 0x00000000 },	/* TPBUFFER5	*/
> +	{ STB0899_OFF0_TP_BUFFER6	, STB0899_BASE_TP_BUFFER6	, 0x00000000 },	/* TPBUFFER6	*/
> +	{ STB0899_OFF0_TP_BUFFER7	, STB0899_BASE_TP_BUFFER7	, 0x00000000 },	/* TPBUFFER7	*/
> +	{ STB0899_OFF0_TP_BUFFER8	, STB0899_BASE_TP_BUFFER8	, 0x00000000 },	/* TPBUFFER8	*/
> +	{ STB0899_OFF0_TP_BUFFER9	, STB0899_BASE_TP_BUFFER9	, 0x00000000 },	/* TPBUFFER9	*/
> +	{ STB0899_OFF0_TP_BUFFER10	, STB0899_BASE_TP_BUFFER10	, 0x00000000 },	/* TPBUFFER10	*/
> +	{ STB0899_OFF0_TP_BUFFER11	, STB0899_BASE_TP_BUFFER11	, 0x00000000 },	/* TPBUFFER11	*/
> +	{ STB0899_OFF0_TP_BUFFER12	, STB0899_BASE_TP_BUFFER12	, 0x00000000 },	/* TPBUFFER12	*/
> +	{ STB0899_OFF0_TP_BUFFER13	, STB0899_BASE_TP_BUFFER13	, 0x00000000 },	/* TPBUFFER13	*/
> +	{ STB0899_OFF0_TP_BUFFER14	, STB0899_BASE_TP_BUFFER14	, 0x00000000 },	/* TPBUFFER14	*/
> +	{ STB0899_OFF0_TP_BUFFER15	, STB0899_BASE_TP_BUFFER15	, 0x00000000 },	/* TPBUFFER15	*/
> +	{ STB0899_OFF0_TP_BUFFER16	, STB0899_BASE_TP_BUFFER16	, 0x0000ff00 },	/* TPBUFFER16	*/
> +	{ STB0899_OFF0_TP_BUFFER17	, STB0899_BASE_TP_BUFFER17	, 0x00000100 },	/* TPBUFFER17	*/
> +	{ STB0899_OFF0_TP_BUFFER18	, STB0899_BASE_TP_BUFFER18	, 0x0000fe01 },	/* TPBUFFER18	*/
> +	{ STB0899_OFF0_TP_BUFFER19	, STB0899_BASE_TP_BUFFER19	, 0x000004fe },	/* TPBUFFER19	*/
> +	{ STB0899_OFF0_TP_BUFFER20	, STB0899_BASE_TP_BUFFER20	, 0x0000cfe7 },	/* TPBUFFER20	*/
> +	{ STB0899_OFF0_TP_BUFFER21	, STB0899_BASE_TP_BUFFER21	, 0x0000bec6 },	/* TPBUFFER21	*/
> +	{ STB0899_OFF0_TP_BUFFER22	, STB0899_BASE_TP_BUFFER22	, 0x0000c2bf },	/* TPBUFFER22	*/
> +	{ STB0899_OFF0_TP_BUFFER23	, STB0899_BASE_TP_BUFFER23	, 0x0000c1c1 },	/* TPBUFFER23	*/
> +	{ STB0899_OFF0_TP_BUFFER24	, STB0899_BASE_TP_BUFFER24	, 0x0000c1c1 },	/* TPBUFFER24	*/
> +	{ STB0899_OFF0_TP_BUFFER25	, STB0899_BASE_TP_BUFFER25	, 0x0000c1c1 },	/* TPBUFFER25	*/
> +	{ STB0899_OFF0_TP_BUFFER26	, STB0899_BASE_TP_BUFFER26	, 0x0000c1c1 },	/* TPBUFFER26	*/
> +	{ STB0899_OFF0_TP_BUFFER27	, STB0899_BASE_TP_BUFFER27	, 0x0000c1c0 },	/* TPBUFFER27	*/
> +	{ STB0899_OFF0_TP_BUFFER28	, STB0899_BASE_TP_BUFFER28	, 0x0000c0c0 },	/* TPBUFFER28	*/
> +	{ STB0899_OFF0_TP_BUFFER29	, STB0899_BASE_TP_BUFFER29	, 0x0000c1c1 },	/* TPBUFFER29	*/
> +	{ STB0899_OFF0_TP_BUFFER30	, STB0899_BASE_TP_BUFFER30	, 0x0000c1c1 },	/* TPBUFFER30	*/
> +	{ STB0899_OFF0_TP_BUFFER31	, STB0899_BASE_TP_BUFFER31	, 0x0000c0c1 },	/* TPBUFFER31	*/
> +	{ STB0899_OFF0_TP_BUFFER32	, STB0899_BASE_TP_BUFFER32	, 0x0000c0c1 },	/* TPBUFFER32	*/
> +	{ STB0899_OFF0_TP_BUFFER33	, STB0899_BASE_TP_BUFFER33	, 0x0000c1c1 },	/* TPBUFFER33	*/
> +	{ STB0899_OFF0_TP_BUFFER34	, STB0899_BASE_TP_BUFFER34	, 0x0000c1c1 },	/* TPBUFFER34	*/
> +	{ STB0899_OFF0_TP_BUFFER35	, STB0899_BASE_TP_BUFFER35	, 0x0000c0c1 },	/* TPBUFFER35	*/
> +	{ STB0899_OFF0_TP_BUFFER36	, STB0899_BASE_TP_BUFFER36	, 0x0000c1c1 },	/* TPBUFFER36	*/
> +	{ STB0899_OFF0_TP_BUFFER37	, STB0899_BASE_TP_BUFFER37	, 0x0000c0c1 },	/* TPBUFFER37	*/
> +	{ STB0899_OFF0_TP_BUFFER38	, STB0899_BASE_TP_BUFFER38	, 0x0000c1c1 },	/* TPBUFFER38	*/
> +	{ STB0899_OFF0_TP_BUFFER39	, STB0899_BASE_TP_BUFFER39	, 0x0000c0c0 },	/* TPBUFFER39	*/
> +	{ STB0899_OFF0_TP_BUFFER40	, STB0899_BASE_TP_BUFFER40	, 0x0000c1c0 },	/* TPBUFFER40	*/
> +	{ STB0899_OFF0_TP_BUFFER41	, STB0899_BASE_TP_BUFFER41	, 0x0000c1c1 },	/* TPBUFFER41	*/
> +	{ STB0899_OFF0_TP_BUFFER42	, STB0899_BASE_TP_BUFFER42	, 0x0000c0c0 },	/* TPBUFFER42	*/
> +	{ STB0899_OFF0_TP_BUFFER43	, STB0899_BASE_TP_BUFFER43	, 0x0000c1c0 },	/* TPBUFFER43	*/
> +	{ STB0899_OFF0_TP_BUFFER44	, STB0899_BASE_TP_BUFFER44	, 0x0000c0c1 },	/* TPBUFFER44	*/
> +	{ STB0899_OFF0_TP_BUFFER45	, STB0899_BASE_TP_BUFFER45	, 0x0000c1be },	/* TPBUFFER45	*/
> +	{ STB0899_OFF0_TP_BUFFER46	, STB0899_BASE_TP_BUFFER46	, 0x0000c1c9 },	/* TPBUFFER46	*/
> +	{ STB0899_OFF0_TP_BUFFER47	, STB0899_BASE_TP_BUFFER47	, 0x0000c0da },	/* TPBUFFER47	*/
> +	{ STB0899_OFF0_TP_BUFFER48	, STB0899_BASE_TP_BUFFER48	, 0x0000c0ba },	/* TPBUFFER48	*/
> +	{ STB0899_OFF0_TP_BUFFER49	, STB0899_BASE_TP_BUFFER49	, 0x0000c1c4 },	/* TPBUFFER49	*/
> +	{ STB0899_OFF0_TP_BUFFER50	, STB0899_BASE_TP_BUFFER50	, 0x0000c1bf },	/* TPBUFFER50	*/
> +	{ STB0899_OFF0_TP_BUFFER51	, STB0899_BASE_TP_BUFFER51	, 0x0000c0c1 },	/* TPBUFFER51	*/
> +	{ STB0899_OFF0_TP_BUFFER52	, STB0899_BASE_TP_BUFFER52	, 0x0000c1c0 },	/* TPBUFFER52	*/
> +	{ STB0899_OFF0_TP_BUFFER53	, STB0899_BASE_TP_BUFFER53	, 0x0000c0c1 },	/* TPBUFFER53	*/
> +	{ STB0899_OFF0_TP_BUFFER54	, STB0899_BASE_TP_BUFFER54	, 0x0000c1c1 },	/* TPBUFFER54	*/
> +	{ STB0899_OFF0_TP_BUFFER55	, STB0899_BASE_TP_BUFFER55	, 0x0000c1c1 },	/* TPBUFFER55	*/
> +	{ STB0899_OFF0_TP_BUFFER56	, STB0899_BASE_TP_BUFFER56	, 0x0000c1c1 },	/* TPBUFFER56	*/
> +	{ STB0899_OFF0_TP_BUFFER57	, STB0899_BASE_TP_BUFFER57	, 0x0000c1c1 },	/* TPBUFFER57	*/
> +	{ STB0899_OFF0_TP_BUFFER58	, STB0899_BASE_TP_BUFFER58	, 0x0000c1c1 },	/* TPBUFFER58	*/
> +	{ STB0899_OFF0_TP_BUFFER59	, STB0899_BASE_TP_BUFFER59	, 0x0000c1c1 },	/* TPBUFFER59	*/
> +	{ STB0899_OFF0_TP_BUFFER60	, STB0899_BASE_TP_BUFFER60	, 0x0000c1c1 },	/* TPBUFFER60	*/
> +	{ STB0899_OFF0_TP_BUFFER61	, STB0899_BASE_TP_BUFFER61	, 0x0000c1c1 },	/* TPBUFFER61	*/
> +	{ STB0899_OFF0_TP_BUFFER62	, STB0899_BASE_TP_BUFFER62	, 0x0000c1c1 },	/* TPBUFFER62	*/
> +	{ STB0899_OFF0_TP_BUFFER63	, STB0899_BASE_TP_BUFFER63	, 0x0000c1c0 },	/* TPBUFFER63	*/
> +	{ STB0899_OFF0_RESET_CNTRL	, STB0899_BASE_RESET_CNTRL	, 0x00000001 },	/* RESETCNTRL	*/
> +	{ STB0899_OFF0_ACM_ENABLE	, STB0899_BASE_ACM_ENABLE	, 0x00005654 },	/* ACMENABLE	*/
> +	{ STB0899_OFF0_DESCR_CNTRL	, STB0899_BASE_DESCR_CNTRL	, 0x00000000 },	/* DESCRCNTRL	*/
> +	{ STB0899_OFF0_CSM_CNTRL1	, STB0899_BASE_CSM_CNTRL1	, 0x00020019 },	/* CSMCNTRL1	*/
> +	{ STB0899_OFF0_CSM_CNTRL2	, STB0899_BASE_CSM_CNTRL2	, 0x004b3237 },	/* CSMCNTRL2	*/
> +	{ STB0899_OFF0_CSM_CNTRL3	, STB0899_BASE_CSM_CNTRL3	, 0x0003dd17 },	/* CSMCNTRL3	*/
> +	{ STB0899_OFF0_CSM_CNTRL4	, STB0899_BASE_CSM_CNTRL4	, 0x00008008 },	/* CSMCNTRL4	*/
> +	{ STB0899_OFF0_UWP_CNTRL1	, STB0899_BASE_UWP_CNTRL1	, 0x002a3106 },	/* UWPCNTRL1	*/
> +	{ STB0899_OFF0_UWP_CNTRL2	, STB0899_BASE_UWP_CNTRL2	, 0x0006140a },	/* UWPCNTRL2	*/
> +	{ STB0899_OFF0_UWP_STAT1	, STB0899_BASE_UWP_STAT1	, 0x00008000 },	/* UWPSTAT1	*/
> +	{ STB0899_OFF0_UWP_STAT2	, STB0899_BASE_UWP_STAT2	, 0x00000000 },	/* UWPSTAT2	*/
> +	{ STB0899_OFF0_DMD_STAT2	, STB0899_BASE_DMD_STAT2	, 0x00000000 },	/* DMDSTAT2	*/
> +	{ STB0899_OFF0_FREQ_ADJ_SCALE	, STB0899_BASE_FREQ_ADJ_SCALE	, 0x00000471 },	/* FREQADJSCALE */
> +	{ STB0899_OFF0_UWP_CNTRL3	, STB0899_BASE_UWP_CNTRL3	, 0x017b0465 },	/* UWPCNTRL3	*/
> +	{ STB0899_OFF0_SYM_CLK_SEL	, STB0899_BASE_SYM_CLK_SEL	, 0x00000002 },	/* SYMCLKSEL	*/
> +	{ STB0899_OFF0_SOF_SRCH_TO	, STB0899_BASE_SOF_SRCH_TO	, 0x00196464 },	/* SOFSRCHTO	*/
> +	{ STB0899_OFF0_ACQ_CNTRL1	, STB0899_BASE_ACQ_CNTRL1	, 0x00000603 },	/* ACQCNTRL1	*/
> +	{ STB0899_OFF0_ACQ_CNTRL2	, STB0899_BASE_ACQ_CNTRL2	, 0x02046666 },	/* ACQCNTRL2	*/
> +	{ STB0899_OFF0_ACQ_CNTRL3	, STB0899_BASE_ACQ_CNTRL3	, 0x10046583 },	/* ACQCNTRL3	*/
> +	{ STB0899_OFF0_FE_SETTLE	, STB0899_BASE_FE_SETTLE	, 0x00010404 },	/* FESETTLE	*/
> +	{ STB0899_OFF0_AC_DWELL		, STB0899_BASE_AC_DWELL		, 0x0002aa8a },	/* ACDWELL	*/
> +	{ STB0899_OFF0_ACQUIRE_TRIG	, STB0899_BASE_ACQUIRE_TRIG	, 0x00000000 },	/* ACQUIRETRIG	*/
> +	{ STB0899_OFF0_LOCK_LOST	, STB0899_BASE_LOCK_LOST	, 0x00000001 },	/* LOCKLOST	*/
> +	{ STB0899_OFF0_ACQ_STAT1	, STB0899_BASE_ACQ_STAT1	, 0x00000500 },	/* ACQSTAT1	*/
> +	{ STB0899_OFF0_ACQ_TIMEOUT	, STB0899_BASE_ACQ_TIMEOUT	, 0x0028a0a0 },	/* ACQTIMEOUT	*/
> +	{ STB0899_OFF0_ACQ_TIME		, STB0899_BASE_ACQ_TIME		, 0x00000000 },	/* ACQTIME	*/
> +	{ STB0899_OFF0_FINAL_AGC_CNTRL	, STB0899_BASE_FINAL_AGC_CNTRL	, 0x00800c17 },	/* FINALAGCCNTRL*/
> +	{ STB0899_OFF0_FINAL_AGC_GAIN	, STB0899_BASE_FINAL_AGC_GAIN	, 0x00000000 },	/* FINALAGCCGAIN*/
> +	{ STB0899_OFF0_EQUALIZER_INIT	, STB0899_BASE_EQUALIZER_INIT	, 0x00000000 },	/* EQUILIZERINIT*/
> +	{ STB0899_OFF0_EQ_CNTRL		, STB0899_BASE_EQ_CNTRL		, 0x00054802 },	/* EQCNTL	*/
> +	{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF0 */
> +	{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF1 */
> +	{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF2 */
> +	{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF3 */
> +	{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF4 */
> +	{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 },	/* EQIINITCOEFF5 */
> +	{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF6 */
> +	{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF7 */
> +	{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF8 */
> +	{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF9 */
> +	{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF10*/
> +	{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF0 */
> +	{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF1 */
> +	{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF2 */
> +	{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF3 */
> +	{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF4 */
> +	{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF5 */
> +	{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF6 */
> +	{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF7 */
> +	{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF8 */
> +	{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF9 */
> +	{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF10*/
> +	{ STB0899_OFF0_EQ_I_OUT_COEFF_0	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT0 */
> +	{ STB0899_OFF1_EQ_I_OUT_COEFF_1	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT1 */
> +	{ STB0899_OFF2_EQ_I_OUT_COEFF_2	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT2 */
> +	{ STB0899_OFF3_EQ_I_OUT_COEFF_3	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT3 */
> +	{ STB0899_OFF4_EQ_I_OUT_COEFF_4	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT4 */
> +	{ STB0899_OFF5_EQ_I_OUT_COEFF_5	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT5 */
> +	{ STB0899_OFF6_EQ_I_OUT_COEFF_6	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT6 */
> +	{ STB0899_OFF7_EQ_I_OUT_COEFF_7	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT7 */
> +	{ STB0899_OFF8_EQ_I_OUT_COEFF_8	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT8 */
> +	{ STB0899_OFF9_EQ_I_OUT_COEFF_9	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT9 */
> +	{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT10*/
> +	{ STB0899_OFF0_EQ_Q_OUT_COEFF_0	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT0 */
> +	{ STB0899_OFF1_EQ_Q_OUT_COEFF_1	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT1 */
> +	{ STB0899_OFF2_EQ_Q_OUT_COEFF_2	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT2 */
> +	{ STB0899_OFF3_EQ_Q_OUT_COEFF_3	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT3 */
> +	{ STB0899_OFF4_EQ_Q_OUT_COEFF_4	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT4 */
> +	{ STB0899_OFF5_EQ_Q_OUT_COEFF_5	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT5 */
> +	{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT6 */
> +	{ STB0899_OFF7_EQ_Q_OUT_COEFF_7	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT7 */
> +	{ STB0899_OFF8_EQ_Q_OUT_COEFF_8	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT8 */
> +	{ STB0899_OFF9_EQ_Q_OUT_COEFF_9	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT9 */
> +	{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT10*/
> +	{ 0xffff			, 0xffffffff		    , 0xffffffff },
> +};
> +
> +static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
> +	{ STB0899_DEMOD			, 0x00 },
> +	{ STB0899_RCOMPC		, 0xc9 },
> +	{ STB0899_AGC1CN		, 0x01 },
> +	{ STB0899_AGC1REF		, 0x10 },
> +	{ STB0899_RTC			, 0x23 },
> +	{ STB0899_TMGCFG		, 0x4e },
> +	{ STB0899_AGC2REF		, 0x34 },
> +	{ STB0899_TLSR			, 0x84 },
> +	{ STB0899_CFD			, 0xf7 },
> +	{ STB0899_ACLC			, 0x87 },
> +	{ STB0899_BCLC			, 0x94 },
> +	{ STB0899_EQON			, 0x41 },
> +	{ STB0899_LDT			, 0xf1 },
> +	{ STB0899_LDT2			, 0xe3 },
> +	{ STB0899_EQUALREF		, 0xb4 },
> +	{ STB0899_TMGRAMP		, 0x10 },
> +	{ STB0899_TMGTHD		, 0x30 },
> +	{ STB0899_IDCCOMP		, 0xfd },
> +	{ STB0899_QDCCOMP		, 0xff },
> +	{ STB0899_POWERI		, 0x0c },
> +	{ STB0899_POWERQ		, 0x0f },
> +	{ STB0899_RCOMP			, 0x6c },
> +	{ STB0899_AGCIQIN		, 0x80 },
> +	{ STB0899_AGC2I1		, 0x06 },
> +	{ STB0899_AGC2I2		, 0x00 },
> +	{ STB0899_TLIR			, 0x30 },
> +	{ STB0899_RTF			, 0x7f },
> +	{ STB0899_DSTATUS		, 0x00 },
> +	{ STB0899_LDI			, 0xbc },
> +	{ STB0899_CFRM			, 0xea },
> +	{ STB0899_CFRL			, 0x31 },
> +	{ STB0899_NIRM			, 0x2b },
> +	{ STB0899_NIRL			, 0x80 },
> +	{ STB0899_ISYMB			, 0x1d },
> +	{ STB0899_QSYMB			, 0xa6 },
> +	{ STB0899_SFRH			, 0x2f },
> +	{ STB0899_SFRM			, 0x68 },
> +	{ STB0899_SFRL			, 0x40 },
> +	{ STB0899_SFRUPH		, 0x2f },
> +	{ STB0899_SFRUPM		, 0x68 },
> +	{ STB0899_SFRUPL		, 0x40 },
> +	{ STB0899_EQUAI1		, 0x02 },
> +	{ STB0899_EQUAQ1		, 0xff },
> +	{ STB0899_EQUAI2		, 0x04 },
> +	{ STB0899_EQUAQ2		, 0x05 },
> +	{ STB0899_EQUAI3		, 0x02 },
> +	{ STB0899_EQUAQ3		, 0xfd },
> +	{ STB0899_EQUAI4		, 0x03 },
> +	{ STB0899_EQUAQ4		, 0x07 },
> +	{ STB0899_EQUAI5		, 0x08 },
> +	{ STB0899_EQUAQ5		, 0xf5 },
> +	{ STB0899_DSTATUS2		, 0x00 },
> +	{ STB0899_VSTATUS		, 0x00 },
> +	{ STB0899_VERROR		, 0x86 },
> +	{ STB0899_IQSWAP		, 0x2a },
> +	{ STB0899_ECNT1M		, 0x00 },
> +	{ STB0899_ECNT1L		, 0x00 },
> +	{ STB0899_ECNT2M		, 0x00 },
> +	{ STB0899_ECNT2L		, 0x00 },
> +	{ STB0899_ECNT3M		, 0x0a },
> +	{ STB0899_ECNT3L		, 0xad },
> +	{ STB0899_FECAUTO1		, 0x06 },
> +	{ STB0899_FECM			, 0x01 },
> +	{ STB0899_VTH12			, 0xb0 },
> +	{ STB0899_VTH23			, 0x7a },
> +	{ STB0899_VTH34			, 0x58 },
> +	{ STB0899_VTH56			, 0x38 },
> +	{ STB0899_VTH67			, 0x34 },
> +	{ STB0899_VTH78			, 0x24 },
> +	{ STB0899_PRVIT			, 0xff },
> +	{ STB0899_VITSYNC		, 0x19 },
> +	{ STB0899_RSULC			, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
> +	{ STB0899_TSULC			, 0x42 },
> +	{ STB0899_RSLLC			, 0x41 },
> +	{ STB0899_TSLPL			, 0x12 },
> +	{ STB0899_TSCFGH		, 0x0c },
> +	{ STB0899_TSCFGM		, 0x00 },
> +	{ STB0899_TSCFGL		, 0x00 },
> +	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
> +	{ STB0899_RSSYNCDEL		, 0x00 },
> +	{ STB0899_TSINHDELH		, 0x02 },
> +	{ STB0899_TSINHDELM		, 0x00 },
> +	{ STB0899_TSINHDELL		, 0x00 },
> +	{ STB0899_TSLLSTKM		, 0x1b },
> +	{ STB0899_TSLLSTKL		, 0xb3 },
> +	{ STB0899_TSULSTKM		, 0x00 },
> +	{ STB0899_TSULSTKL		, 0x00 },
> +	{ STB0899_PCKLENUL		, 0xbc },
> +	{ STB0899_PCKLENLL		, 0xcc },
> +	{ STB0899_RSPCKLEN		, 0xbd },
> +	{ STB0899_TSSTATUS		, 0x90 },
> +	{ STB0899_ERRCTRL1		, 0xb6 },
> +	{ STB0899_ERRCTRL2      	, 0x95 },
> +	{ STB0899_ERRCTRL3      	, 0x8d },
> +	{ STB0899_DMONMSK1		, 0x27 },
> +	{ STB0899_DMONMSK0		, 0x03 },
> +	{ STB0899_DEMAPVIT		, 0x5c },
> +	{ STB0899_PLPARM		, 0x19 },
> +	{ STB0899_PDELCTRL		, 0x48 },
> +	{ STB0899_PDELCTRL2		, 0x00 },
> +	{ STB0899_BBHCTRL1		, 0x00 },
> +	{ STB0899_BBHCTRL2		, 0x00 },
> +	{ STB0899_HYSTTHRESH		, 0x77 },
> +	{ STB0899_MATCSTM		, 0x00 },
> +	{ STB0899_MATCSTL		, 0x00 },
> +	{ STB0899_UPLCSTM		, 0x00 },
> +	{ STB0899_UPLCSTL		, 0x00 },
> +	{ STB0899_DFLCSTM		, 0x00 },
> +	{ STB0899_DFLCSTL		, 0x00 },
> +	{ STB0899_SYNCCST		, 0x00 },
> +	{ STB0899_SYNCDCSTM		, 0x00 },
> +	{ STB0899_SYNCDCSTL		, 0x00 },
> +	{ STB0899_ISI_ENTRY		, 0x00 },
> +	{ STB0899_ISI_BIT_EN		, 0x00 },
> +	{ STB0899_MATSTRM		, 0xf0 },
> +	{ STB0899_MATSTRL		, 0x02 },
> +	{ STB0899_UPLSTRM		, 0x45 },
> +	{ STB0899_UPLSTRL		, 0x60 },
> +	{ STB0899_DFLSTRM		, 0xe3 },
> +	{ STB0899_DFLSTRL		, 0x00 },
> +	{ STB0899_SYNCSTR		, 0x47 },
> +	{ STB0899_SYNCDSTRM		, 0x05 },
> +	{ STB0899_SYNCDSTRL		, 0x18 },
> +	{ STB0899_CFGPDELSTATUS1	, 0x19 },
> +	{ STB0899_CFGPDELSTATUS2	, 0x2b },
> +	{ STB0899_BBFERRORM		, 0x00 },
> +	{ STB0899_BBFERRORL		, 0x01 },
> +	{ STB0899_UPKTERRORM		, 0x00 },
> +	{ STB0899_UPKTERRORL		, 0x00 },
> +	{ 0xffff			, 0xff },
> +};
> +
> +
> +static const struct stb0899_s2_reg pctv452e_init_s2_fec[] = {
> +	{ STB0899_OFF0_BLOCK_LNGTH	, STB0899_BASE_BLOCK_LNGTH	, 0x00000008 },	/* BLOCKLNGTH	*/
> +	{ STB0899_OFF0_ROW_STR		, STB0899_BASE_ROW_STR		, 0x000000b4 },	/* ROWSTR	*/
> +	{ STB0899_OFF0_BN_END_ADDR	, STB0899_BASE_BN_END_ADDR	, 0x000004b5 },	/* BNANDADDR	*/
> +	{ STB0899_OFF0_CN_END_ADDR	, STB0899_BASE_CN_END_ADDR	, 0x00000b4b },	/* CNANDADDR	*/
> +	{ STB0899_OFF0_INFO_LENGTH	, STB0899_BASE_INFO_LENGTH	, 0x00000078 },	/* INFOLENGTH	*/
> +	{ STB0899_OFF0_BOT_ADDR		, STB0899_BASE_BOT_ADDR		, 0x000001e0 },	/* BOT_ADDR	*/
> +	{ STB0899_OFF0_BCH_BLK_LN	, STB0899_BASE_BCH_BLK_LN	, 0x0000a8c0 },	/* BCHBLKLN	*/
> +	{ STB0899_OFF0_BCH_T		, STB0899_BASE_BCH_T		, 0x0000000c },	/* BCHT		*/
> +	{ STB0899_OFF0_CNFG_MODE	, STB0899_BASE_CNFG_MODE	, 0x00000001 },	/* CNFGMODE	*/
> +	{ STB0899_OFF0_LDPC_STAT	, STB0899_BASE_LDPC_STAT	, 0x0000000d },	/* LDPCSTAT	*/
> +	{ STB0899_OFF0_ITER_SCALE	, STB0899_BASE_ITER_SCALE	, 0x00000040 },	/* ITERSCALE	*/
> +	{ STB0899_OFF0_INPUT_MODE	, STB0899_BASE_INPUT_MODE	, 0x00000000 },	/* INPUTMODE	*/
> +	{ STB0899_OFF0_LDPCDECRST	, STB0899_BASE_LDPCDECRST	, 0x00000000 },	/* LDPCDECRST	*/
> +	{ STB0899_OFF0_CLK_PER_BYTE_RW	, STB0899_BASE_CLK_PER_BYTE_RW	, 0x00000008 },	/* CLKPERBYTE	*/
> +	{ STB0899_OFF0_BCH_ERRORS	, STB0899_BASE_BCH_ERRORS	, 0x00000000 },	/* BCHERRORS	*/
> +	{ STB0899_OFF0_LDPC_ERRORS	, STB0899_BASE_LDPC_ERRORS	, 0x00000000 },	/* LDPCERRORS	*/
> +	{ STB0899_OFF0_BCH_MODE		, STB0899_BASE_BCH_MODE		, 0x00000000 },	/* BCHMODE	*/
> +	{ STB0899_OFF0_ERR_ACC_PER	, STB0899_BASE_ERR_ACC_PER	, 0x00000008 },	/* ERRACCPER	*/
> +	{ STB0899_OFF0_BCH_ERR_ACC	, STB0899_BASE_BCH_ERR_ACC	, 0x00000000 },	/* BCHERRACC	*/
> +	{ STB0899_OFF0_FEC_TP_SEL	, STB0899_BASE_FEC_TP_SEL	, 0x00000000 },	/* FECTPSEL	*/
> +	{ 0xffff			, 0xffffffff			, 0xffffffff },
> +};
> +
> +static const struct stb0899_s1_reg pctv452e_init_tst[] = {
> +	{ STB0899_TSTCK		, 0x00 },
> +	{ STB0899_TSTRES	, 0x00 },
> +	{ STB0899_TSTOUT	, 0x00 },
> +	{ STB0899_TSTIN		, 0x00 },
> +	{ STB0899_TSTSYS	, 0x00 },
> +	{ STB0899_TSTCHIP	, 0x00 },
> +	{ STB0899_TSTFREE	, 0x00 },
> +	{ STB0899_TSTI2C	, 0x00 },
> +	{ STB0899_BITSPEEDM	, 0x00 },
> +	{ STB0899_BITSPEEDL	, 0x00 },
> +	{ STB0899_TBUSBIT	, 0x00 },
> +	{ STB0899_TSTDIS	, 0x00 },
> +	{ STB0899_TSTDISRX	, 0x00 },
> +	{ STB0899_TSTJETON	, 0x00 },
> +	{ STB0899_TSTDCADJ	, 0x00 },
> +	{ STB0899_TSTAGC1	, 0x00 },
> +	{ STB0899_TSTAGC1N	, 0x00 },
> +	{ STB0899_TSTPOLYPH	, 0x00 },
> +	{ STB0899_TSTR		, 0x00 },
> +	{ STB0899_TSTAGC2	, 0x00 },
> +	{ STB0899_TSTCTL1	, 0x00 },
> +	{ STB0899_TSTCTL2	, 0x00 },
> +	{ STB0899_TSTCTL3	, 0x00 },
> +	{ STB0899_TSTDEMAP	, 0x00 },
> +	{ STB0899_TSTDEMAP2	, 0x00 },
> +	{ STB0899_TSTDEMMON	, 0x00 },
> +	{ STB0899_TSTRATE	, 0x00 },
> +	{ STB0899_TSTSELOUT	, 0x00 },
> +	{ STB0899_TSYNC		, 0x00 },
> +	{ STB0899_TSTERR	, 0x00 },
> +	{ STB0899_TSTRAM1	, 0x00 },
> +	{ STB0899_TSTVSELOUT	, 0x00 },
> +	{ STB0899_TSTFORCEIN	, 0x00 },
> +	{ STB0899_TSTRS1	, 0x00 },
> +	{ STB0899_TSTRS2	, 0x00 },
> +	{ STB0899_TSTRS3	, 0x00 },
> +	{ STB0899_GHOSTREG	, 0x81 },
> +	{ 0xffff		, 0xff },
> +};
> +
> +
> +#define PCTV452E_DVBS2_ESNO_AVE			3
> +#define PCTV452E_DVBS2_ESNO_QUANT		32
> +#define PCTV452E_DVBS2_AVFRAMES_COARSE		10
> +#define PCTV452E_DVBS2_AVFRAMES_FINE		20
> +#define PCTV452E_DVBS2_MISS_THRESHOLD		6
> +#define PCTV452E_DVBS2_UWP_THRESHOLD_ACQ	1125
> +#define PCTV452E_DVBS2_UWP_THRESHOLD_TRACK	758
> +#define PCTV452E_DVBS2_UWP_THRESHOLD_SOF	1350
> +#define PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT	1664100
> +
> +#define PCTV452E_DVBS2_BTR_NCO_BITS		28
> +#define PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET	15
> +#define PCTV452E_DVBS2_CRL_NCO_BITS		30
> +#define PCTV452E_DVBS2_LDPC_MAX_ITER		70
> +
> +
> +static struct stb0899_config stb0899_config = {
> +	.init_dev	= pctv452e_init_dev,
> +	.init_s2_demod   = pctv452e_init_s2_demod,
> +	.init_s1_demod   = pctv452e_init_s1_demod,
> +	.init_s2_fec     = pctv452e_init_s2_fec,
> +	.init_tst	= pctv452e_init_tst,
> +
> +	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
> +	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
> +
> +	.xtal_freq       = 27000000,	 /* Assume Hz ? */
> +	.inversion       = IQ_SWAP_ON,       /* ? */
> +
> +	.lo_clk	  = 76500000,
> +	.hi_clk	  = 99000000,
> +
> +	.ts_output_mode  = 0,		/* Use parallel mode */
> +	.clock_polarity  = 0,		/*  */
> +	.data_clk_parity = 0,		/*  */
> +	.fec_mode	= 0,		/*  */
> +
> +	.esno_ave	    = PCTV452E_DVBS2_ESNO_AVE,
> +	.esno_quant	  = PCTV452E_DVBS2_ESNO_QUANT,
> +	.avframes_coarse     = PCTV452E_DVBS2_AVFRAMES_COARSE,
> +	.avframes_fine       = PCTV452E_DVBS2_AVFRAMES_FINE,
> +	.miss_threshold      = PCTV452E_DVBS2_MISS_THRESHOLD,
> +	.uwp_threshold_acq   = PCTV452E_DVBS2_UWP_THRESHOLD_ACQ,
> +	.uwp_threshold_track = PCTV452E_DVBS2_UWP_THRESHOLD_TRACK,
> +	.uwp_threshold_sof   = PCTV452E_DVBS2_UWP_THRESHOLD_SOF,
> +	.sof_search_timeout  = PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT,
> +
> +	.btr_nco_bits	  = PCTV452E_DVBS2_BTR_NCO_BITS,
> +	.btr_gain_shift_offset = PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET,
> +	.crl_nco_bits	  = PCTV452E_DVBS2_CRL_NCO_BITS,
> +	.ldpc_max_iter	 = PCTV452E_DVBS2_LDPC_MAX_ITER,
> +
> +	.tuner_get_frequency	= stb6100_get_frequency,
> +	.tuner_set_frequency	= stb6100_set_frequency,
> +	.tuner_set_bandwidth	= stb6100_set_bandwidth,
> +	.tuner_get_bandwidth	= stb6100_get_bandwidth,
> +	.tuner_set_rfsiggain	= NULL,
> +
> +	/* helper for switching LED green/orange */
> +	.postproc = pctv45e_postproc
> +};
> +
> +static struct stb6100_config stb6100_config = {
> +	.tuner_address = I2C_ADDR_STB6100,
> +	.refclock      = 27000000
> +};
> +
> +
> +static struct i2c_algorithm pctv452e_i2c_algo = {
> +	.master_xfer   = pctv452e_i2c_xfer,
> +	.functionality = pctv452e_i2c_func
> +};
> +
> +
> +static struct usb_device_id pctv452e_usb_table[] = {
> +	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
> +	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
> +	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
> +
> +static struct dvb_usb_device_properties pctv452e_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +
> +	.size_of_priv     = sizeof(struct pctv452e_state),
> +
> +	.identify_state   = 0, // this is a warm only device
> +
> +	.power_ctrl       = pctv452e_power_ctrl,
> +	/* Untested. */
> +	/* .read_mac_address = pctv452e_read_mac_address, */
> +
> +	.rc.legacy = {
> +		.rc_map_table     = pctv452e_rc_keys,
> +		.rc_map_size      = ARRAY_SIZE(pctv452e_rc_keys),
> +		.rc_query         = pctv452e_rc_query,
> +		.rc_interval      = 100,
> +	},
> +
> +	.num_adapters     = 1,
> +	.adapter = {{
> +		.caps	     = 0,
> +		.pid_filter_count = 0,
> +
> +		.streaming_ctrl   = NULL,
> +
> +		.frontend_attach  = pctv452e_frontend_attach,
> +		.tuner_attach     = pctv452e_tuner_attach,
> +
> +		/* parameter for the MPEG2-data transfer */
> +		.stream = {
> +			.type     = USB_ISOC,
> +			.count    = ISO_BUF_COUNT,
> +			.endpoint = 0x02,
> +			.u = {
> +				.isoc = {
> +					.framesperurb = FRAMES_PER_ISO_BUF,
> +					.framesize    = ISO_FRAME_SIZE,
> +					.interval     = 1
> +				}
> +			}
> +		},
> +		.size_of_priv     = 0
> +	}},
> +
> +	.i2c_algo = &pctv452e_i2c_algo,
> +
> +	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
> +
> +	.num_device_descs = 1,
> +	.devices = {
> +		{ .name = "PCTV HDTV USB",
> +		  .cold_ids = { NULL, NULL }, // this is a warm only device
> +		  .warm_ids = { &pctv452e_usb_table[0], NULL }
> +		},
> +		{ 0 },
> +	}
> +};
> +
> +static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +
> +	.size_of_priv		= sizeof(struct pctv452e_state),
> +
> +	.identify_state		= 0, // this is a warm only device
> +
> +	.power_ctrl		= pctv452e_power_ctrl,
> +	.read_mac_address	= pctv452e_read_mac_address,
> +
> +	.rc.legacy = {
> +		.rc_map_table   = tt_connect_s2_3600_rc_key,
> +		.rc_map_size    = ARRAY_SIZE(tt_connect_s2_3600_rc_key),
> +		.rc_query       = pctv452e_rc_query,
> +		.rc_interval    = 500,
> +	},

Please port it to the non-legacy RC support. The legacy one is there only because
I didn't have all DVB hardware here to remove support for them. Newer drivers shouldn't
use it.

> +
> +	.num_adapters		= 1,
> +	.adapter = {{
> +		.caps = 0,
> +		.pid_filter_count = 0,
> +
> +		.streaming_ctrl = NULL,
> +
> +		.frontend_attach = pctv452e_frontend_attach,
> +		.tuner_attach = pctv452e_tuner_attach,
> +
> +		/* parameter for the MPEG2-data transfer */
> +		.stream = {
> +			.type = USB_ISOC,
> +			.count = 7,
> +			.endpoint = 0x02,
> +			.u = {
> +				.isoc = {
> +					.framesperurb = 4,
> +					.framesize = 940,
> +					.interval = 1
> +				}
> +			}
> +		},
> +		.size_of_priv = 0
> +	}},
> +
> +	.i2c_algo = &pctv452e_i2c_algo,
> +
> +	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
> +
> +	.num_device_descs = 2,
> +	.devices = {
> +		{ .name = "Technotrend TT Connect S2-3600",
> +		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
> +		  .warm_ids = { &pctv452e_usb_table[1], NULL }
> +		},
> +		{ .name = "Technotrend TT Connect S2-3650-CI",
> +		  .cold_ids = { NULL, NULL },
> +		  .warm_ids = { &pctv452e_usb_table[2], NULL }
> +		},
> +		{ 0 },
> +	}
> +};
> +
> +
> +
> +static struct usb_driver pctv452e_usb_driver = {
> +#if LINUX_VERSION_CODE <=  KERNEL_VERSION(2,6,15)
> +	.owner      = THIS_MODULE,
> +#endif
> +	.name       = "pctv452e",
> +	.probe      = pctv452e_usb_probe,
> +	.disconnect = pctv452e_usb_disconnect,
> +	.id_table   = pctv452e_usb_table,
> +};
> +
> +static struct usb_driver tt_connects2_3600_usb_driver = {
> +#if LINUX_VERSION_CODE <=  KERNEL_VERSION(2,6,15)
> +	.owner      = THIS_MODULE,
> +#endif

Those ifdefs should be removed when submitting a driver upstream.

> +	.name       = "dvb-usb-tt-connect-s2-3600-01.fw",
> +	.probe      = pctv452e_usb_probe,
> +	.disconnect = pctv452e_usb_disconnect,
> +	.id_table   = pctv452e_usb_table,
> +};
> +
> +static int __init pctv452e_usb_init(void) {
> +	int err=0;
> +
> +	if ((err = usb_register(&pctv452e_usb_driver))) {
> +		printk("%s: usb_register failed! Error number %d", __FILE__, err);
> +		return err;
> +	}
> +	if ((err = usb_register(&tt_connects2_3600_usb_driver))) {
> +		printk("%s: usb_register failed! Error number %d", __FILE__, err);
> +	}
> +
> +	return err;
> +}
> +
> +static void __exit pctv452e_usb_exit(void)  {
> +	usb_deregister(&pctv452e_usb_driver);
> +	usb_deregister(&tt_connects2_3600_usb_driver);
> +}
> +
> +module_init(pctv452e_usb_init);
> +module_exit(pctv452e_usb_exit);
> +
> +MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
> +MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
> +MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
> +MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
> index 3b0c4bd..8e6f588 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -49,6 +49,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
>  obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
>  obj-$(CONFIG_DVB_CX24123) += cx24123.o
>  obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
> +obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
>  obj-$(CONFIG_DVB_ISL6405) += isl6405.o
>  obj-$(CONFIG_DVB_ISL6421) += isl6421.o
>  obj-$(CONFIG_DVB_TDA10086) += tda10086.o
> diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
> new file mode 100644
> index 0000000..48377b2
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/lnbp22.c
> @@ -0,0 +1,140 @@
> +/*
> + * lnbp22.h - driver for lnb supply and control ic lnbp22
> + *
> + * Copyright (C) 2006 Dominik Kuhlen
> + * Based on lnbp21 driver
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
> + *
> + *
> + * the project's page is at http://www.linuxtv.org
> + */
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +
> +#include "dvb_frontend.h"
> +#include "lnbp22.h"
> +
> +static int debug = 0;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
> +
> +
> +#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
> +
> +struct lnbp22 {
> +	u8                 config[4];
> +	struct i2c_adapter *i2c;
> +};
> +
> +static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) {
> +	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
> +	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
> +				.buf = (char*)&lnbp22->config,
> +				.len = sizeof(lnbp22->config) };
> +
> +	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __FUNCTION__, voltage,
> +	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
> +
> +	lnbp22->config[3] = 0x60; // Power down
> +	switch(voltage) {
> +	case SEC_VOLTAGE_OFF:
> +		break;
> +	case SEC_VOLTAGE_13:
> +		lnbp22->config[3] |= LNBP22_EN;
> +		break;
> +	case SEC_VOLTAGE_18:
> +		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
> +		break;
> +	default:
> +		return -EINVAL;
> +	};
> +
> +	dprintk(1, "%s: 0x%02x)\n", __FUNCTION__, lnbp22->config[3]);
> +	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
> +}
> +
> +static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) {
> +	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
> +	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
> +				.buf = (char*)&lnbp22->config,
> +				.len = sizeof(lnbp22->config) };
> +
> +	dprintk(1, "%s: %d\n", __FUNCTION__, (int)arg);
> +	if (arg)
> +		lnbp22->config[3] |= LNBP22_LLC;
> +	else
> +		lnbp22->config[3] &= ~LNBP22_LLC;
> +
> +	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
> +}
> +
> +static void lnbp22_release(struct dvb_frontend *fe)
> +{
> +
> +	dprintk(1, "%s\n", __FUNCTION__);
> +	/* LNBP power off */
> +	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
> +
> +	/* free data */
> +	kfree(fe->sec_priv);
> +	fe->sec_priv = NULL;
> +}
> +
> +struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
> +{
> +	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
> +	if (!lnbp22)
> +		return NULL;
> +
> +	/* default configuration */
> +	lnbp22->config[0] = 0x00; /* ? */
> +	lnbp22->config[1] = 0x28; /* ? */
> +	lnbp22->config[2] = 0x48; /* ? */
> +	lnbp22->config[3] = 0x60; /* Power down */
> +	lnbp22->i2c = i2c;
> +	fe->sec_priv = lnbp22;
> +
> +	/* detect if it is present or not */
> +	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
> +		dprintk(0, "%s LNBP22 not found\n", __FUNCTION__);
> +		kfree(lnbp22);
> +		fe->sec_priv = NULL;
> +		return NULL;
> +	}
> +
> +	/* install release callback */
> +	fe->ops.release_sec = lnbp22_release;
> +
> +	/* override frontend ops */
> +	fe->ops.set_voltage = lnbp22_set_voltage;
> +	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
> +
> +	return fe;
> +}
> +EXPORT_SYMBOL(lnbp22_attach);
> +
> +MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
> +MODULE_AUTHOR("Dominik Kuhlen");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
> new file mode 100644
> index 0000000..4149c62
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/lnbp22.h
> @@ -0,0 +1,51 @@
> +/*
> + * lnbp22.h - driver for lnb supply and control ic lnbp22
> + *
> + * Copyright (C) 2006 Dominik Kuhlen
> + * Based on lnbp21.h
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
> + *
> + *
> + * the project's page is at http://www.linuxtv.org
> + */
> +
> +#ifndef _LNBP22_H
> +#define _LNBP22_H
> +
> +// Enable
> +#define LNBP22_EN	  0x10
> +// Voltage selection
> +#define LNBP22_VSEL	0x02
> +// Plus 1 Volt Bit
> +#define LNBP22_LLC	0x01
> +
> +#include <linux/dvb/frontend.h>
> +
> +#if defined(CONFIG_DVB_LNBP22) || (defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
> +/* override_set and override_clear control which system register bits (above) to always set & clear */
> +extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c);
> +#else
> +static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +#endif // CONFIG_DVB_LNBP22
> +
> +#endif // _LNBP22_H
> diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
> index 7dd54b3..0f54d4f 100644
> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
> @@ -85,6 +85,31 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
>  	return 0;
>  }
>  
> +int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC)
> +{
> +	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
> +		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
> +		       0x1d, 0x36, 0x64, 0x78};
> +	u8 data[20];
> +	int i;
> +
> +	/* In case there is a sig check failure have the orig contents available */
> +	memcpy(data, encodedMAC, 20);
> +
> +	for (i = 0; i < 20; i++)
> +		data[i] ^= xor[i];
> +	for (i = 0; i < 10; i++)
> +		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
> +			>> ((data[2 * i + 1] >> 6) & 3);
> +
> +	if (check_mac_tt(data))
> +		return -ENODEV;
> +
> +	decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0];
> +	decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4];
> +	return 0;
> +}
> +
>  static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
>  {
>  	int ret;
> diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h
> index e2dc6cf..fea8bfc 100644
> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h
> @@ -28,6 +28,7 @@
>  #include <linux/types.h>
>  #include <linux/i2c.h>
>  
> +extern int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC);
>  extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
>  
>  #endif
> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c      2011-07-23 11:00:49.000000000 +0000
> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c      2011-07-23 11:04:00.000000000 +0000
> @@ -165,6 +165,7 @@ int ttpci_eeprom_parse_mac(struct i2c_ad
>  }
>  
>  EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
> +EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
>  
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
> diff -Naur original-new-stb0899/linux/drivers/media/dvb/frontends/Kconfig 1/linux/drivers/media/dvb/frontends/Kconfig
> --- a/drivers/media/dvb/frontends/Kconfig	2007-10-22 01:40:25.000000000 +0100
> +++ b/drivers/media/dvb/frontends/Kconfig	2007-10-23 19:47:41.000000000 +0100
> @@ -358,6 +358,12 @@
>  	help
>  	  An SEC control chip.
>  
> +config DVB_LNBP22
> +	tristate "LNBP22 SEC controller"
> +	depends on DVB_CORE && I2C
> +	help
> +	  An SEC control chip.
> +
>  config DVB_ISL6421
>  	tristate "ISL6421 SEC controller"
>  	depends on DVB_CORE && I2C
> -- 
> 1.7.1.1

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-23 20:03     ` Mauro Carvalho Chehab
@ 2011-09-23 20:22       ` Steffen Barszus
  2011-09-23 20:26       ` Steffen Barszus
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 18+ messages in thread
From: Steffen Barszus @ 2011-09-23 20:22 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Oliver Freyermuth, Linux Media Mailing List, Doychin Dokov,
	Igor M. Liplianin, Dominik Kuhlen, Andre Weidemann,
	Michael H. Schimek

On Fri, 23 Sep 2011 17:03:04 -0300
Mauro Carvalho Chehab <mchehab@redhat.com> wrote:

> Em 05-09-2011 18:27, Oliver Freyermuth escreveu:
> > Got it working with kernel 3.0!
> > 
> > For me, some more changes on the current patchset appeared to be
> > necessary. In short, I had to change all a->fe to a->fe[0] (because
> > of 3.0-kernel) and I had to add lnbp22 to Kconfig (it would
> > otherwise have been disabled and not been built, although other
> > modules depended on it...).
> > 
> > I also had to add the additional
> > "EXPORT_SYMBOL(ttpci_eeprom_decode_mac);" as mentioned by Doychin
> > Dokov.
> > 
> > Attached is the 'new' version of the patch with the mentioned
> > changes.
> 
> For it to be applied, we need the SOB's of the patch authors:
> 
> +MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
> +MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
> +MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");

I tried to ping Dominik Kuhlen at least a couple of times - without a
reply. Is this a must or nice to have ? Is there a workaround or is
this driver at dead end then ? I can only confirm that the driver is
working with the mentioned changes. 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-23 20:03     ` Mauro Carvalho Chehab
  2011-09-23 20:22       ` Steffen Barszus
@ 2011-09-23 20:26       ` Steffen Barszus
  2011-09-23 20:48       ` Igor M. Liplianin
  2011-09-23 20:58       ` Oliver Freyermuth
  3 siblings, 0 replies; 18+ messages in thread
From: Steffen Barszus @ 2011-09-23 20:26 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Oliver Freyermuth, Linux Media Mailing List, Doychin Dokov,
	Igor M. Liplianin, Dominik Kuhlen, Andre Weidemann,
	Michael H. Schimek

On Fri, 23 Sep 2011 17:03:04 -0300
Mauro Carvalho Chehab <mchehab@redhat.com> wrote:

> > 
> > Attached is the 'new' version of the patch with the mentioned
> > changes.  
> 
> For it to be applied, we need the SOB's of the patch authors:
> 
> +MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
> +MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
> +MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
> 
> Also, the patch needs some adjustments to be applied. See bellow for
> my quick review:

Another note - for the move of remote to rc-core (as suggested by
you) there is another patch waiting in your Inbox Mauro. 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-23 20:03     ` Mauro Carvalho Chehab
  2011-09-23 20:22       ` Steffen Barszus
  2011-09-23 20:26       ` Steffen Barszus
@ 2011-09-23 20:48       ` Igor M. Liplianin
  2011-09-23 20:58       ` Oliver Freyermuth
  3 siblings, 0 replies; 18+ messages in thread
From: Igor M. Liplianin @ 2011-09-23 20:48 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Oliver Freyermuth, Linux Media Mailing List, Doychin Dokov,
	Steffen Barszus, Dominik Kuhlen, Andre Weidemann,
	Michael H. Schimek

[-- Attachment #1: Type: Text/Plain, Size: 75 bytes --]

Here is my version.
Made with git format-patch for branch staging/for_v3.2

[-- Attachment #2: 0001-Add-support-for-pctv452e.patch --]
[-- Type: text/x-patch, Size: 43620 bytes --]

From cc44ac937f36ed51335eb11a7e28cf047a979a1c Mon Sep 17 00:00:00 2001
From: Igor M. Liplianin <liplianin@me.by>
Date: Fri, 23 Sep 2011 23:31:25 +0300
Subject: [PATCH] Add support for pctv452e
To: <mchehab@infradead.org>, <linux-media@vger.kernel.org>

Signed-off-by: Igor M. Liplianin <liplianin@me.by>
---
 drivers/media/dvb/dvb-usb/Kconfig       |   13 +
 drivers/media/dvb/dvb-usb/Makefile      |    4 +
 drivers/media/dvb/dvb-usb/dvb-usb-ids.h |    3 +
 drivers/media/dvb/dvb-usb/pctv452e.c    | 1182 +++++++++++++++++++++++++++++++
 drivers/media/dvb/frontends/Kconfig     |   10 +
 drivers/media/dvb/frontends/Makefile    |    1 +
 drivers/media/dvb/frontends/lnbp22.c    |  148 ++++
 drivers/media/dvb/frontends/lnbp22.h    |   57 ++
 drivers/media/dvb/ttpci/ttpci-eeprom.c  |   29 +
 drivers/media/dvb/ttpci/ttpci-eeprom.h  |    1 +
 10 files changed, 1448 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/dvb/dvb-usb/pctv452e.c
 create mode 100644 drivers/media/dvb/frontends/lnbp22.c
 create mode 100644 drivers/media/dvb/frontends/lnbp22.h

diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 2c773827..5825716 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -258,6 +258,19 @@ config DVB_USB_AF9005_REMOTE
 	  Say Y here to support the default remote control decoding for the
 	  Afatech AF9005 based receiver.
 
+config DVB_USB_PCTV452E
+	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
+	depends on DVB_USB
+	select TTPCI_EEPROM
+	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	help
+	  Support for external USB adapter designed by Pinnacle,
+	  shipped under the brand name 'PCTV HDTV Pro USB'.
+	  Also supports TT Connect S2-3600/3650 cards.
+	  Say Y if you own such a device and want to use it.
+
 config DVB_USB_DW2102
 	tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
 	depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 06f75f6..7d0710b 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -64,6 +64,9 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
 dvb-usb-anysee-objs = anysee.o
 obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
 
+dvb-usb-pctv452e-objs = pctv452e.o
+obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
+
 dvb-usb-dw2102-objs = dw2102.o
 obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
 
@@ -104,4 +107,5 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
 ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 ccflags-y += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 7433261..2ad33ba 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -241,6 +241,9 @@
 #define USB_PID_PCTV_200E				0x020e
 #define USB_PID_PCTV_400E				0x020f
 #define USB_PID_PCTV_450E				0x0222
+#define USB_PID_PCTV_452E				0x021f
+#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
+#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
 #define USB_PID_NEBULA_DIGITV				0x0201
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
new file mode 100644
index 0000000..6151b3e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/pctv452e.c
@@ -0,0 +1,1182 @@
+/*
+ * PCTV 452e DVB driver
+ *
+ * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
+ *
+ * TT connect S2-3650-CI Common Interface support, MAC readout
+ * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
+ *
+ * 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.
+ */
+
+/* dvb usb framework */
+#define DVB_USB_LOG_PREFIX "pctv452e"
+#include "dvb-usb.h"
+
+/* Demodulator */
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+/* Tuner */
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+/* FE Power */
+#include "lnbp22.h"
+
+#include "dvb_ca_en50221.h"
+#include "ttpci-eeprom.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define ISO_BUF_COUNT      4
+#define FRAMES_PER_ISO_BUF 4
+#define ISO_FRAME_SIZE     940
+#define ISOC_INTERFACE_ALTERNATIVE 3
+
+#define SYNC_BYTE_OUT 0xaa
+#define SYNC_BYTE_IN  0x55
+
+/* guessed: (copied from ttusb-budget) */
+#define PCTV_CMD_RESET 0x15
+/* command to poll IR receiver */
+#define PCTV_CMD_IR    0x1b
+/* command to send I2C  */
+#define PCTV_CMD_I2C   0x31
+
+#define I2C_ADDR_STB0899 (0xd0 >> 1)
+#define I2C_ADDR_STB6100 (0xc0 >> 1)
+#define I2C_ADDR_LNBP22  (0x10 >> 1)
+#define I2C_ADDR_24C16   (0xa0 >> 1)
+#define I2C_ADDR_24C64   (0xa2 >> 1)
+
+
+/* pctv452e sends us this amount of data for each issued usb-command */
+#define PCTV_ANSWER_LEN 64
+/* Wait up to 1000ms for device  */
+#define PCTV_TIMEOUT 1000
+
+
+#define PCTV_LED_GPIO   STB0899_GPIO01
+#define PCTV_LED_GREEN  0x82
+#define PCTV_LED_ORANGE 0x02
+
+#define ci_dbg(format, arg...)				\
+do {							\
+	if (0)						\
+		printk(KERN_DEBUG DVB_USB_LOG_PREFIX	\
+			": " format "\n" , ## arg);	\
+} while (0)
+
+enum {
+	TT3650_CMD_CI_TEST = 0x40,
+	TT3650_CMD_CI_RD_CTRL,
+	TT3650_CMD_CI_WR_CTRL,
+	TT3650_CMD_CI_RD_ATTR,
+	TT3650_CMD_CI_WR_ATTR,
+	TT3650_CMD_CI_RESET,
+	TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
+
+static struct stb0899_postproc pctv45e_postproc[] = {
+	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
+	{ 0, 0 }
+};
+
+/*
+ * stores all private variables for communication with the PCTV452e DVB-S2
+ */
+struct pctv452e_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+
+	u8 c;	   /* transaction counter, wraps around...  */
+	u8 initialized; /* set to 1 if 0x15 has been sent */
+};
+
+static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
+			 unsigned int write_len, unsigned int read_len)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[64];
+	u8 id;
+	unsigned int rlen;
+	int ret;
+
+	BUG_ON(NULL == data && 0 != (write_len | read_len));
+	BUG_ON(write_len > 64 - 4);
+	BUG_ON(read_len > 64 - 4);
+
+	id = state->c++;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = cmd;
+	buf[3] = write_len;
+
+	memcpy(buf + 4, data, write_len);
+
+	rlen = (read_len > 0) ? 64 : 0;
+	ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
+				  buf, rlen, /* delay_ms */ 0);
+	if (0 != ret)
+		goto failed;
+
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	memcpy(data, buf + 4, read_len);
+
+	return 0;
+
+failed:
+	err("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
+	     ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
+
+	return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
+				u8 cmd, u8 *data, unsigned int write_len,
+				unsigned int read_len)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	mutex_lock(&state->ca_mutex);
+	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int slot, int address)
+{
+	u8 buf[3];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+	ci_dbg("%s %04x -> %d 0x%02x",
+		__func__, address, ret, buf[2]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int slot, int address, u8 value)
+{
+	u8 buf[3];
+
+	ci_dbg("%s %d 0x%04x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+	buf[2] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address)
+{
+	u8 buf[2];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address & 3;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+	ci_dbg("%s 0x%02x -> %d 0x%02x",
+		__func__, address, ret, buf[1]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address,
+				 u8			value)
+{
+	u8 buf[2];
+
+	ci_dbg("%s %d 0x%02x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address;
+	buf[1] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			enable)
+{
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%s %d %d", __func__, slot, enable);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	enable = !!enable;
+	buf[0] = enable;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+	if (ret < 0)
+		return ret;
+
+	if (enable != buf[0]) {
+		err("CI not %sabled.", enable ? "en" : "dis");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%s %d", __func__, slot);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = 0;
+
+	mutex_lock(&state->ca_mutex);
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 1;
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 0; /* FTA */
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+ failed:
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			open)
+{
+	u8 buf[1];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+	if (0 != ret)
+		return ret;
+
+	if (1 == buf[0])
+		return DVB_CA_EN50221_POLL_CAM_PRESENT |
+			DVB_CA_EN50221_POLL_CAM_READY;
+
+	return 0;
+
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+	struct pctv452e_state *state;
+
+	ci_dbg("%s", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = (struct pctv452e_state *)d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	/* Error ignored. */
+	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	ci_dbg("%s", __func__);
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner = THIS_MODULE;
+	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+	state->ca.read_cam_control = tt3650_ci_read_cam_control;
+	state->ca.write_cam_control = tt3650_ci_write_cam_control;
+	state->ca.slot_reset = tt3650_ci_slot_reset;
+	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+	state->ca.data = d;
+
+	ret = dvb_ca_en50221_init(&a->dvb_adap,
+				   &state->ca,
+				   /* flags */ 0,
+				   /* n_slots */ 1);
+	if (0 != ret) {
+		err("Cannot initialize CI: Error %d.", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	info("CI initialized.");
+
+	return 0;
+}
+
+#define CMD_BUFFER_SIZE 0x28
+static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
+				const u8 *snd_buf, u8 snd_len,
+				u8 *rcv_buf, u8 rcv_len)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[64];
+	u8 id;
+	int ret;
+
+	id = state->c++;
+
+	ret = -EINVAL;
+	if (snd_len > 64 - 7 || rcv_len > 64 - 7)
+		goto failed;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = PCTV_CMD_I2C;
+	buf[3] = snd_len + 3;
+	buf[4] = addr << 1;
+	buf[5] = snd_len;
+	buf[6] = rcv_len;
+
+	memcpy(buf + 7, snd_buf, snd_len);
+
+	ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
+				  buf, /* rcv_len */ 64,
+				  /* delay_ms */ 0);
+	if (ret < 0)
+		goto failed;
+
+	/* TT USB protocol error. */
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	/* I2C device didn't respond as expected. */
+	ret = -EREMOTEIO;
+	if (buf[5] < snd_len || buf[6] < rcv_len)
+		goto failed;
+
+	memcpy(rcv_buf, buf + 7, rcv_len);
+
+	return rcv_len;
+
+failed:
+	err("I2C error %d; %02X %02X  %02X %02X %02X -> "
+	     "%02X %02X  %02X %02X %02X.",
+	     ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
+	     buf[0], buf[1], buf[4], buf[5], buf[6]);
+
+	return ret;
+}
+
+static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+				int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adapter);
+	int i;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
+		int ret;
+
+		if (msg[i].flags & I2C_M_RD) {
+			addr = msg[i].addr;
+			snd_buf = NULL;
+			snd_len = 0;
+			rcv_buf = msg[i].buf;
+			rcv_len = msg[i].len;
+		} else {
+			addr = msg[i].addr;
+			snd_buf = msg[i].buf;
+			snd_len = msg[i].len;
+			rcv_buf = NULL;
+			rcv_len = 0;
+		}
+
+		ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
+					rcv_len);
+		if (ret < rcv_len)
+			break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
+	u8 rx[PCTV_ANSWER_LEN];
+	int ret;
+
+	info("%s: %d\n", __func__, i);
+
+	if (!i)
+		return 0;
+
+	if (state->initialized)
+		return 0;
+
+	/* hmm where shoud this should go? */
+	ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
+	if (ret != 0)
+		info("%s: Warning set interface returned: %d\n",
+			__func__, ret);
+
+	/* this is a one-time initialization, dont know where to put */
+	b0[1] = state->c++;
+	/* reset board */
+	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+	if (ret)
+		return ret;
+
+	b0[1] = state->c++;
+	b0[4] = 1;
+	/* reset board (again?) */
+	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+	if (ret)
+		return ret;
+
+	state->initialized = 1;
+
+	return 0;
+}
+
+/* Remote control stuff */
+static struct rc_map_table rc_map_pctv452e_table[] = {
+	{0x0700, KEY_MUTE},
+	{0x0701, KEY_VENDOR},  /* pinnacle logo (top middle) */
+	{0x0739, KEY_POWER},
+	{0x0703, KEY_VOLUMEUP},
+	{0x0709, KEY_VOLUMEDOWN},
+	{0x0706, KEY_CHANNELUP},
+	{0x070c, KEY_CHANNELDOWN},
+	{0x070f, KEY_1},
+	{0x0715, KEY_2},
+	{0x0710, KEY_3},
+	{0x0718, KEY_4},
+	{0x071b, KEY_5},
+	{0x071e, KEY_6},
+	{0x0711, KEY_7},
+	{0x0721, KEY_8},
+	{0x0712, KEY_9},
+	{0x0727, KEY_0},
+	{0x0724, KEY_TV}, /* left of '0' */
+	{0x072a, KEY_T}, /* right of '0' */
+	{0x072d, KEY_REWIND},
+	{0x0733, KEY_FORWARD},
+	{0x0730, KEY_PLAY},
+	{0x0736, KEY_RECORD},
+	{0x073c, KEY_STOP},
+	{0x073f, KEY_HELP}
+};
+
+/* Remote Control Stuff fo S2-3600 (copied from TT-S1500): */
+static struct rc_map_table rc_map_s2_3600_table[] = {
+	{0x1501, KEY_POWER},
+	{0x1502, KEY_SHUFFLE}, /* ? double-arrow key */
+	{0x1503, KEY_1},
+	{0x1504, KEY_2},
+	{0x1505, KEY_3},
+	{0x1506, KEY_4},
+	{0x1507, KEY_5},
+	{0x1508, KEY_6},
+	{0x1509, KEY_7},
+	{0x150a, KEY_8},
+	{0x150b, KEY_9},
+	{0x150c, KEY_0},
+	{0x150d, KEY_UP},
+	{0x150e, KEY_LEFT},
+	{0x150f, KEY_OK},
+	{0x1510, KEY_RIGHT},
+	{0x1511, KEY_DOWN},
+	{0x1512, KEY_INFO},
+	{0x1513, KEY_EXIT},
+	{0x1514, KEY_RED},
+	{0x1515, KEY_GREEN},
+	{0x1516, KEY_YELLOW},
+	{0x1517, KEY_BLUE},
+	{0x1518, KEY_MUTE},
+	{0x1519, KEY_TEXT},
+	{0x151a, KEY_MODE},  /* ? TV/Radio */
+	{0x1521, KEY_OPTION},
+	{0x1522, KEY_EPG},
+	{0x1523, KEY_CHANNELUP},
+	{0x1524, KEY_CHANNELDOWN},
+	{0x1525, KEY_VOLUMEUP},
+	{0x1526, KEY_VOLUMEDOWN},
+	{0x1527, KEY_SETUP},
+	{0x153a, KEY_RECORD},/* these keys are only in the black remote */
+	{0x153b, KEY_PLAY},
+	{0x153c, KEY_STOP},
+	{0x153d, KEY_REWIND},
+	{0x153e, KEY_PAUSE},
+	{0x153f, KEY_FORWARD}
+};
+
+static int pctv452e_rc_query(struct dvb_usb_device *d, u32 *keyevent,
+				int *keystate)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 b[CMD_BUFFER_SIZE];
+	u8 rx[PCTV_ANSWER_LEN];
+	u8 keybuf[5];
+	int ret, i;
+	u8 id = state->c++;
+
+	/* prepare command header  */
+	b[0] = SYNC_BYTE_OUT;
+	b[1] = id;
+	b[2] = PCTV_CMD_IR;
+	b[3] = 0;
+
+	*keystate = REMOTE_NO_KEY_PRESSED;
+
+	/* send ir request */
+	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
+	if (ret != 0)
+		return ret;
+
+	if (debug > 3) {
+		info("%s: read: %2d: %02x %02x %02x: ", __func__,
+				ret, rx[0], rx[1], rx[2]);
+		for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
+			info(" %02x", rx[i+3]);
+
+		info("\n");
+	}
+
+	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
+		/* got a "press" event */
+		if (debug > 2)
+			info("%s: cmd=0x%02x sys=0x%02x\n",
+				__func__, rx[6], rx[7]);
+		/* DVB_USB_RC_NEC_KEY_PRESSED; why is this define'd privately?*/
+		keybuf[0] = 0x01;
+		keybuf[1] = rx[7];
+		keybuf[2] = ~keybuf[1]; /* fake checksum */
+		keybuf[3] = rx[6];
+		keybuf[4] = ~keybuf[3]; /* fake checksum */
+		dvb_usb_nec_rc_key_to_event(d, keybuf, keyevent, keystate);
+
+	}
+
+	return 0;
+}
+
+static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	const u8 mem_addr[] = { 0x1f, 0xcc };
+	u8 encoded_mac[20];
+	int ret;
+
+	ret = -EAGAIN;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		goto failed;
+
+	ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
+				mem_addr + 1, /* snd_len */ 1,
+				encoded_mac, /* rcv_len */ 20);
+	if (-EREMOTEIO == ret)
+		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
+		   byte write if /WC is low. */
+		ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
+					mem_addr, 2,
+					encoded_mac, 20);
+
+	mutex_unlock(&d->i2c_mutex);
+
+	if (20 != ret)
+		goto failed;
+
+	ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
+	if (0 != ret)
+		goto failed;
+
+	return 0;
+
+failed:
+	memset(mac, 0, 6);
+
+	return ret;
+}
+
+static const struct stb0899_s1_reg pctv452e_init_dev[] = {
+	{ STB0899_DISCNTRL1,	0x26 },
+	{ STB0899_DISCNTRL2,	0x80 },
+	{ STB0899_DISRX_ST0,	0x04 },
+	{ STB0899_DISRX_ST1,	0x20 },
+	{ STB0899_DISPARITY,	0x00 },
+	{ STB0899_DISFIFO,	0x00 },
+	{ STB0899_DISF22,	0x99 },
+	{ STB0899_DISF22RX,	0x85 }, /* 0xa8 */
+	{ STB0899_ACRPRESC,	0x11 },
+	{ STB0899_ACRDIV1,	0x0a },
+	{ STB0899_ACRDIV2,	0x05 },
+	{ STB0899_DACR1	,	0x00 },
+	{ STB0899_DACR2	,	0x00 },
+	{ STB0899_OUTCFG,	0x00 },
+	{ STB0899_MODECFG,	0x00 }, /* Inversion */
+	{ STB0899_IRQMSK_3,	0xf3 },
+	{ STB0899_IRQMSK_2,	0xfc },
+	{ STB0899_IRQMSK_1,	0xff },
+	{ STB0899_IRQMSK_0,	0xff },
+	{ STB0899_I2CCFG,	0x88 },
+	{ STB0899_I2CRPT,	0x58 },
+	{ STB0899_GPIO00CFG,	0x82 },
+	{ STB0899_GPIO01CFG,	0x82 }, /* LED: 0x02 green, 0x82 orange */
+	{ STB0899_GPIO02CFG,	0x82 },
+	{ STB0899_GPIO03CFG,	0x82 },
+	{ STB0899_GPIO04CFG,	0x82 },
+	{ STB0899_GPIO05CFG,	0x82 },
+	{ STB0899_GPIO06CFG,	0x82 },
+	{ STB0899_GPIO07CFG,	0x82 },
+	{ STB0899_GPIO08CFG,	0x82 },
+	{ STB0899_GPIO09CFG,	0x82 },
+	{ STB0899_GPIO10CFG,	0x82 },
+	{ STB0899_GPIO11CFG,	0x82 },
+	{ STB0899_GPIO12CFG,	0x82 },
+	{ STB0899_GPIO13CFG,	0x82 },
+	{ STB0899_GPIO14CFG,	0x82 },
+	{ STB0899_GPIO15CFG,	0x82 },
+	{ STB0899_GPIO16CFG,	0x82 },
+	{ STB0899_GPIO17CFG,	0x82 },
+	{ STB0899_GPIO18CFG,	0x82 },
+	{ STB0899_GPIO19CFG,	0x82 },
+	{ STB0899_GPIO20CFG,	0x82 },
+	{ STB0899_SDATCFG,	0xb8 },
+	{ STB0899_SCLTCFG,	0xba },
+	{ STB0899_AGCRFCFG,	0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
+	{ STB0899_GPIO22,	0x82 },
+	{ STB0899_GPIO21,	0x91 },
+	{ STB0899_DIRCLKCFG,	0x82 },
+	{ STB0899_CLKOUT27CFG,	0x7e },
+	{ STB0899_STDBYCFG,	0x82 },
+	{ STB0899_CS0CFG,	0x82 },
+	{ STB0899_CS1CFG,	0x82 },
+	{ STB0899_DISEQCOCFG,	0x20 },
+	{ STB0899_NCOARSE,	0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
+	{ STB0899_SYNTCTRL,	0x00 }, /* 0x00 CLKI, 0x02 XTALI */
+	{ STB0899_FILTCTRL,	0x00 },
+	{ STB0899_SYSCTRL,	0x00 },
+	{ STB0899_STOPCLK1,	0x20 }, /* orig: 0x00 budget-ci: 0x20 */
+	{ STB0899_STOPCLK2,	0x00 },
+	{ STB0899_INTBUFCTRL,	0x0a },
+	{ STB0899_AGC2I1,	0x00 },
+	{ STB0899_AGC2I2,	0x00 },
+	{ STB0899_AGCIQIN,	0x00 },
+	{ STB0899_TSTRES,	0x40 }, /* rjkm */
+	{ 0xffff,		0xff },
+};
+
+static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
+	{ STB0899_DEMOD,	0x00 },
+	{ STB0899_RCOMPC,	0xc9 },
+	{ STB0899_AGC1CN,	0x01 },
+	{ STB0899_AGC1REF,	0x10 },
+	{ STB0899_RTC,		0x23 },
+	{ STB0899_TMGCFG,	0x4e },
+	{ STB0899_AGC2REF,	0x34 },
+	{ STB0899_TLSR,		0x84 },
+	{ STB0899_CFD,		0xf7 },
+	{ STB0899_ACLC,		0x87 },
+	{ STB0899_BCLC,		0x94 },
+	{ STB0899_EQON,		0x41 },
+	{ STB0899_LDT,		0xf1 },
+	{ STB0899_LDT2,		0xe3 },
+	{ STB0899_EQUALREF,	0xb4 },
+	{ STB0899_TMGRAMP,	0x10 },
+	{ STB0899_TMGTHD,	0x30 },
+	{ STB0899_IDCCOMP,	0xfd },
+	{ STB0899_QDCCOMP,	0xff },
+	{ STB0899_POWERI,	0x0c },
+	{ STB0899_POWERQ,	0x0f },
+	{ STB0899_RCOMP,	0x6c },
+	{ STB0899_AGCIQIN,	0x80 },
+	{ STB0899_AGC2I1,	0x06 },
+	{ STB0899_AGC2I2,	0x00 },
+	{ STB0899_TLIR,		0x30 },
+	{ STB0899_RTF,		0x7f },
+	{ STB0899_DSTATUS,	0x00 },
+	{ STB0899_LDI,		0xbc },
+	{ STB0899_CFRM,		0xea },
+	{ STB0899_CFRL,		0x31 },
+	{ STB0899_NIRM,		0x2b },
+	{ STB0899_NIRL,		0x80 },
+	{ STB0899_ISYMB,	0x1d },
+	{ STB0899_QSYMB,	0xa6 },
+	{ STB0899_SFRH,		0x2f },
+	{ STB0899_SFRM,		0x68 },
+	{ STB0899_SFRL,		0x40 },
+	{ STB0899_SFRUPH,	0x2f },
+	{ STB0899_SFRUPM,	0x68 },
+	{ STB0899_SFRUPL,	0x40 },
+	{ STB0899_EQUAI1,	0x02 },
+	{ STB0899_EQUAQ1,	0xff },
+	{ STB0899_EQUAI2,	0x04 },
+	{ STB0899_EQUAQ2,	0x05 },
+	{ STB0899_EQUAI3,	0x02 },
+	{ STB0899_EQUAQ3,	0xfd },
+	{ STB0899_EQUAI4,	0x03 },
+	{ STB0899_EQUAQ4,	0x07 },
+	{ STB0899_EQUAI5,	0x08 },
+	{ STB0899_EQUAQ5,	0xf5 },
+	{ STB0899_DSTATUS2,	0x00 },
+	{ STB0899_VSTATUS,	0x00 },
+	{ STB0899_VERROR,	0x86 },
+	{ STB0899_IQSWAP,	0x2a },
+	{ STB0899_ECNT1M,	0x00 },
+	{ STB0899_ECNT1L,	0x00 },
+	{ STB0899_ECNT2M,	0x00 },
+	{ STB0899_ECNT2L,	0x00 },
+	{ STB0899_ECNT3M,	0x0a },
+	{ STB0899_ECNT3L,	0xad },
+	{ STB0899_FECAUTO1,	0x06 },
+	{ STB0899_FECM,		0x01 },
+	{ STB0899_VTH12,	0xb0 },
+	{ STB0899_VTH23,	0x7a },
+	{ STB0899_VTH34,	0x58 },
+	{ STB0899_VTH56,	0x38 },
+	{ STB0899_VTH67,	0x34 },
+	{ STB0899_VTH78,	0x24 },
+	{ STB0899_PRVIT,	0xff },
+	{ STB0899_VITSYNC,	0x19 },
+	{ STB0899_RSULC,	0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC,	0x42 },
+	{ STB0899_RSLLC,	0x41 },
+	{ STB0899_TSLPL,	0x12 },
+	{ STB0899_TSCFGH,	0x0c },
+	{ STB0899_TSCFGM,	0x00 },
+	{ STB0899_TSCFGL,	0x00 },
+	{ STB0899_TSOUT,	0x69 }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL,	0x00 },
+	{ STB0899_TSINHDELH,	0x02 },
+	{ STB0899_TSINHDELM,	0x00 },
+	{ STB0899_TSINHDELL,	0x00 },
+	{ STB0899_TSLLSTKM,	0x1b },
+	{ STB0899_TSLLSTKL,	0xb3 },
+	{ STB0899_TSULSTKM,	0x00 },
+	{ STB0899_TSULSTKL,	0x00 },
+	{ STB0899_PCKLENUL,	0xbc },
+	{ STB0899_PCKLENLL,	0xcc },
+	{ STB0899_RSPCKLEN,	0xbd },
+	{ STB0899_TSSTATUS,	0x90 },
+	{ STB0899_ERRCTRL1,	0xb6 },
+	{ STB0899_ERRCTRL2,	0x95 },
+	{ STB0899_ERRCTRL3,	0x8d },
+	{ STB0899_DMONMSK1,	0x27 },
+	{ STB0899_DMONMSK0,	0x03 },
+	{ STB0899_DEMAPVIT,	0x5c },
+	{ STB0899_PLPARM,	0x19 },
+	{ STB0899_PDELCTRL,	0x48 },
+	{ STB0899_PDELCTRL2,	0x00 },
+	{ STB0899_BBHCTRL1,	0x00 },
+	{ STB0899_BBHCTRL2,	0x00 },
+	{ STB0899_HYSTTHRESH,	0x77 },
+	{ STB0899_MATCSTM,	0x00 },
+	{ STB0899_MATCSTL,	0x00 },
+	{ STB0899_UPLCSTM,	0x00 },
+	{ STB0899_UPLCSTL,	0x00 },
+	{ STB0899_DFLCSTM,	0x00 },
+	{ STB0899_DFLCSTL,	0x00 },
+	{ STB0899_SYNCCST,	0x00 },
+	{ STB0899_SYNCDCSTM,	0x00 },
+	{ STB0899_SYNCDCSTL,	0x00 },
+	{ STB0899_ISI_ENTRY,	0x00 },
+	{ STB0899_ISI_BIT_EN,	0x00 },
+	{ STB0899_MATSTRM,	0xf0 },
+	{ STB0899_MATSTRL,	0x02 },
+	{ STB0899_UPLSTRM,	0x45 },
+	{ STB0899_UPLSTRL,	0x60 },
+	{ STB0899_DFLSTRM,	0xe3 },
+	{ STB0899_DFLSTRL,	0x00 },
+	{ STB0899_SYNCSTR,	0x47 },
+	{ STB0899_SYNCDSTRM,	0x05 },
+	{ STB0899_SYNCDSTRL,	0x18 },
+	{ STB0899_CFGPDELSTATUS1, 0x19 },
+	{ STB0899_CFGPDELSTATUS2, 0x2b },
+	{ STB0899_BBFERRORM,	0x00 },
+	{ STB0899_BBFERRORL,	0x01 },
+	{ STB0899_UPKTERRORM,	0x00 },
+	{ STB0899_UPKTERRORL,	0x00 },
+	{ 0xffff,		0xff },
+};
+
+static struct stb0899_config stb0899_config = {
+	.init_dev	= pctv452e_init_dev,
+	.init_s2_demod	= stb0899_s2_init_2,
+	.init_s1_demod	= pctv452e_init_s1_demod,
+	.init_s2_fec	= stb0899_s2_init_4,
+	.init_tst	= stb0899_s1_init_5,
+
+	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
+	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
+
+	.xtal_freq       = 27000000,	 /* Assume Hz ? */
+	.inversion       = IQ_SWAP_ON,       /* ? */
+
+	.lo_clk	  = 76500000,
+	.hi_clk	  = 99000000,
+
+	.ts_output_mode  = 0,	/* Use parallel mode */
+	.clock_polarity  = 0,
+	.data_clk_parity = 0,
+	.fec_mode	= 0,
+
+	.esno_ave	    = STB0899_DVBS2_ESNO_AVE,
+	.esno_quant	  = STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse     = STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine       = STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold      = STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq   = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof   = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout  = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits	  = STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits	  = STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter	 = STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL,
+
+	/* helper for switching LED green/orange */
+	.postproc = pctv45e_postproc
+};
+
+static struct stb6100_config stb6100_config = {
+	.tuner_address = I2C_ADDR_STB6100,
+	.refclock      = 27000000
+};
+
+
+static struct i2c_algorithm pctv452e_i2c_algo = {
+	.master_xfer   = pctv452e_i2c_xfer,
+	.functionality = pctv452e_i2c_func
+};
+
+static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
+{
+	struct usb_device_id *id;
+
+	a->fe = dvb_attach(stb0899_attach, &stb0899_config, &a->dev->i2c_adap);
+	if (!a->fe)
+		return -ENODEV;
+	if ((dvb_attach(lnbp22_attach, a->fe, &a->dev->i2c_adap)) == 0)
+		err("Cannot attach lnbp22\n");
+
+	id = a->dev->desc->warm_ids[0];
+	if (USB_VID_TECHNOTREND == id->idVendor
+	    && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
+		/* Error ignored. */
+		tt3650_ci_init(a);
+
+	return 0;
+}
+
+static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
+{
+	if (!a->fe)
+		return -ENODEV;
+	if (dvb_attach(stb6100_attach, a->fe, &stb6100_config,
+					&a->dev->i2c_adap) == 0) {
+		err("%s failed\n", __func__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct usb_device_id pctv452e_usb_table[] = {
+	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
+	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
+	{USB_DEVICE(USB_VID_TECHNOTREND,
+				USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
+
+static struct dvb_usb_device_properties pctv452e_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv     = sizeof(struct pctv452e_state),
+
+	.identify_state   = 0, /* this is a warm only device */
+
+	.power_ctrl       = pctv452e_power_ctrl,
+	/* Untested. */
+	/* .read_mac_address = pctv452e_read_mac_address, */
+
+	.rc.legacy = {
+		.rc_map_table	= rc_map_pctv452e_table,
+		.rc_map_size	= ARRAY_SIZE(rc_map_pctv452e_table),
+		.rc_query	= pctv452e_rc_query,
+		.rc_interval	= 100,
+	},
+
+	.num_adapters     = 1,
+	.adapter = {{
+		.caps	     = 0,
+		.pid_filter_count = 0,
+
+		.streaming_ctrl   = NULL,
+
+		.frontend_attach  = pctv452e_frontend_attach,
+		.tuner_attach     = pctv452e_tuner_attach,
+
+		/* parameter for the MPEG2-data transfer */
+		.stream = {
+			.type     = USB_ISOC,
+			.count    = ISO_BUF_COUNT,
+			.endpoint = 0x02,
+			.u = {
+				.isoc = {
+					.framesperurb = FRAMES_PER_ISO_BUF,
+					.framesize    = ISO_FRAME_SIZE,
+					.interval     = 1
+				}
+			}
+		},
+		.size_of_priv     = 0
+	} },
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "PCTV HDTV USB",
+		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
+		  .warm_ids = { &pctv452e_usb_table[0], NULL }
+		},
+		{ 0 },
+	}
+};
+
+static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv		= sizeof(struct pctv452e_state),
+
+	.identify_state		= 0, /* this is a warm only device */
+
+	.power_ctrl		= pctv452e_power_ctrl,
+	.read_mac_address	= pctv452e_read_mac_address,
+
+	.rc.legacy = {
+		.rc_map_table	= rc_map_s2_3600_table,
+		.rc_map_size	= ARRAY_SIZE(rc_map_s2_3600_table),
+		.rc_query	= pctv452e_rc_query,
+		.rc_interval	= 500,
+	},
+
+	.num_adapters		= 1,
+	.adapter = {{
+		.caps = 0,
+		.pid_filter_count = 0,
+
+		.streaming_ctrl = NULL,
+
+		.frontend_attach = pctv452e_frontend_attach,
+		.tuner_attach = pctv452e_tuner_attach,
+
+		/* parameter for the MPEG2-data transfer */
+		.stream = {
+			.type = USB_ISOC,
+			.count = 7,
+			.endpoint = 0x02,
+			.u = {
+				.isoc = {
+					.framesperurb = 4,
+					.framesize = 940,
+					.interval = 1
+				}
+			}
+		},
+		.size_of_priv = 0
+	} },
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
+
+	.num_device_descs = 2,
+	.devices = {
+		{ .name = "Technotrend TT Connect S2-3600",
+		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
+		  .warm_ids = { &pctv452e_usb_table[1], NULL }
+		},
+		{ .name = "Technotrend TT Connect S2-3650-CI",
+		  .cold_ids = { NULL, NULL },
+		  .warm_ids = { &pctv452e_usb_table[2], NULL }
+		},
+		{ 0 },
+	}
+};
+
+static void pctv452e_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+	tt3650_ci_uninit(d);
+	dvb_usb_device_exit(intf);
+}
+
+static int pctv452e_usb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
+					THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
+					THIS_MODULE, NULL, adapter_nr))
+		return 0;
+
+	return -ENODEV;
+}
+
+static struct usb_driver pctv452e_usb_driver = {
+	.name       = "pctv452e",
+	.probe      = pctv452e_usb_probe,
+	.disconnect = pctv452e_usb_disconnect,
+	.id_table   = pctv452e_usb_table,
+};
+
+static struct usb_driver tt_connects2_3600_usb_driver = {
+	.name       = "dvb-usb-tt-connect-s2-3600-01.fw",
+	.probe      = pctv452e_usb_probe,
+	.disconnect = pctv452e_usb_disconnect,
+	.id_table   = pctv452e_usb_table,
+};
+
+static int __init pctv452e_usb_init(void)
+{
+	int ret = usb_register(&pctv452e_usb_driver);
+
+	if (ret) {
+		err("%s: usb_register failed! Error %d", __FILE__, ret);
+		return ret;
+	}
+	ret = usb_register(&tt_connects2_3600_usb_driver);
+	if (ret)
+		err("%s: usb_register failed! Error %d", __FILE__, ret);
+
+	return ret;
+}
+
+static void __exit pctv452e_usb_exit(void)
+{
+	usb_deregister(&pctv452e_usb_driver);
+	usb_deregister(&tt_connects2_3600_usb_driver);
+}
+
+module_init(pctv452e_usb_init);
+module_exit(pctv452e_usb_exit);
+
+MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
+MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
+MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
+MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 28fbb5c..4a2d2e6 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -607,6 +607,16 @@ config DVB_LNBP21
 	help
 	  An SEC control chips.
 
+config DVB_LNBP22
+	tristate "LNBP22 SEC controllers"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  LNB power supply and control voltage
+	  regulator chip with step-up converter
+	  and I2C interface.
+	  Say Y when you want to support this chip.
+
 config DVB_ISL6405
 	tristate "ISL6405 SEC controller"
 	depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 36c8d81..f639f67 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
new file mode 100644
index 0000000..84ad039
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp22.c
@@ -0,0 +1,148 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21 driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp22.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+
+#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
+
+struct lnbp22 {
+	u8		    config[4];
+	struct i2c_adapter *i2c;
+};
+
+static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv;
+	struct i2c_msg msg = {
+		.addr = 0x08,
+		.flags = 0,
+		.buf = (char *)&lnbp22->config,
+		.len = sizeof(lnbp22->config),
+	};
+
+	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __func__, voltage,
+	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
+
+	lnbp22->config[3] = 0x60; /* Power down */
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp22->config[3] |= LNBP22_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]);
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+	struct i2c_msg msg = {
+		.addr = 0x08,
+		.flags = 0,
+		.buf = (char *)&lnbp22->config,
+		.len = sizeof(lnbp22->config),
+	};
+
+	dprintk(1, "%s: %d\n", __func__, (int)arg);
+	if (arg)
+		lnbp22->config[3] |= LNBP22_LLC;
+	else
+		lnbp22->config[3] &= ~LNBP22_LLC;
+
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp22_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s\n", __func__);
+	/* LNBP power off */
+	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c)
+{
+	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
+	if (!lnbp22)
+		return NULL;
+
+	/* default configuration */
+	lnbp22->config[0] = 0x00; /* ? */
+	lnbp22->config[1] = 0x28; /* ? */
+	lnbp22->config[2] = 0x48; /* ? */
+	lnbp22->config[3] = 0x60; /* Power down */
+	lnbp22->i2c = i2c;
+	fe->sec_priv = lnbp22;
+
+	/* detect if it is present or not */
+	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		dprintk(0, "%s LNBP22 not found\n", __func__);
+		kfree(lnbp22);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = lnbp22_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = lnbp22_set_voltage;
+	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
+
+	return fe;
+}
+EXPORT_SYMBOL(lnbp22_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
+MODULE_AUTHOR("Dominik Kuhlen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
new file mode 100644
index 0000000..63e2dec
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp22.h
@@ -0,0 +1,57 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP22_H
+#define _LNBP22_H
+
+/* Enable */
+#define LNBP22_EN	  0x10
+/* Voltage selection */
+#define LNBP22_VSEL	0x02
+/* Plus 1 Volt Bit */
+#define LNBP22_LLC	0x01
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP22) || \
+		(defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
+/*
+ * override_set and override_clear control which system register bits (above)
+ * to always set & clear
+ */
+extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LNBP22 */
+
+#endif /* _LNBP22_H */
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
index 7dd54b3..32d4315 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
@@ -85,6 +85,35 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
 	return 0;
 }
 
+int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC)
+{
+	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
+		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
+		       0x1d, 0x36, 0x64, 0x78};
+	u8 data[20];
+	int i;
+
+	memcpy(data, encodedMAC, 20);
+
+	for (i = 0; i < 20; i++)
+		data[i] ^= xor[i];
+	for (i = 0; i < 10; i++)
+		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
+			>> ((data[2 * i + 1] >> 6) & 3);
+
+	if (check_mac_tt(data))
+		return -ENODEV;
+
+	decodedMAC[0] = data[2];
+	decodedMAC[1] = data[1];
+	decodedMAC[2] = data[0];
+	decodedMAC[3] = data[6];
+	decodedMAC[4] = data[5];
+	decodedMAC[5] = data[4];
+	return 0;
+}
+EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
+
 static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
 {
 	int ret;
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h
index e2dc6cf..dcc33d5 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 
+extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC);
 extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
 
 #endif
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-23 20:03     ` Mauro Carvalho Chehab
                         ` (2 preceding siblings ...)
  2011-09-23 20:48       ` Igor M. Liplianin
@ 2011-09-23 20:58       ` Oliver Freyermuth
  2011-09-23 21:11         ` Igor M. Liplianin
  3 siblings, 1 reply; 18+ messages in thread
From: Oliver Freyermuth @ 2011-09-23 20:58 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Linux Media Mailing List, Doychin Dokov, Steffen Barszus,
	Igor M. Liplianin, Dominik Kuhlen, Andre Weidemann,
	Michael H. Schimek

Thanks for the review!

As this is the first time I touched module- / kernel-code and I am not 
really familiar with the structures of the rc-system, I do not really 
feel up to porting to non-legacy rc-support (Igors version also appears 
to use rc-legacy), and up to now, it was only combining patches and 
fixing small glitches for me.
However, feel free to use me as a tester (I have the hardware available, 
after all) or flood me with links to guidelines or further instructions.

Thanks again,
     Oliver Freyermuth

Am 23.09.2011 22:03, schrieb Mauro Carvalho Chehab:
> Em 05-09-2011 18:27, Oliver Freyermuth escreveu:
>> Got it working with kernel 3.0!
>>
>> For me, some more changes on the current patchset appeared to be necessary.
>> In short, I had to change all a->fe to a->fe[0] (because of 3.0-kernel)
>> and I had to add lnbp22 to Kconfig (it would otherwise have been
>> disabled and not been built, although other modules depended on it...).
>>
>> I also had to add the additional
>> "EXPORT_SYMBOL(ttpci_eeprom_decode_mac);" as mentioned by Doychin Dokov.
>>
>> Attached is the 'new' version of the patch with the mentioned changes.
> For it to be applied, we need the SOB's of the patch authors:
>
> +MODULE_AUTHOR("Dominik Kuhlen<dkuhlen@gmx.net>");
> +MODULE_AUTHOR("Andre Weidemann<Andre.Weidemann@web.de>");
> +MODULE_AUTHOR("Michael H. Schimek<mschimek@gmx.at>");
>
> Also, the patch needs some adjustments to be applied. See bellow for my quick review:
>
>> diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
>> index c545039..6d725ad 100644
>> --- a/drivers/media/dvb/dvb-usb/Kconfig
>> +++ b/drivers/media/dvb/dvb-usb/Kconfig
>> @@ -250,6 +250,18 @@ config DVB_USB_AF9005
>>   	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
>>   	  and the TerraTec Cinergy T USB XE (Rev.1)
>>
>> +config DVB_USB_PCTV452E
>> +	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
>> +	depends on DVB_USB
>> +	select TTPCI_EEPROM
>> +	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
>> +	select DVB_STB0899 if !DVB_FE_CUSTOMISE
>> +	select DVB_STB6100 if !DVB_FE_CUSTOMISE
>> +	help
>> +	  Support for external USB adapter designed by Pinnacle,
>> +	  shipped under the brand name 'PCTV HDTV Pro USB'.
>> +	  Say Y if you own such a device and want to use it.
>> +
>>   config DVB_USB_AF9005_REMOTE
>>   	tristate "Afatech AF9005 default remote control support"
>>   	depends on DVB_USB_AF9005
>> diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
>> index 4bac13d..2497694 100644
>> --- a/drivers/media/dvb/dvb-usb/Makefile
>> +++ b/drivers/media/dvb/dvb-usb/Makefile
>> @@ -73,6 +73,9 @@ obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
>>   dvb-usb-af9015-objs = af9015.o
>>   obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
>>
>> +dvb-usb-pctv452e-objs = pctv452e.o
>> +obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
>> +
>>   dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
>>   obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
>>
>> diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
>> index 3a8b744..1c8a241 100644
>> --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
>> +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
>> @@ -237,6 +237,9 @@
>>   #define USB_PID_PCTV_200E				0x020e
>>   #define USB_PID_PCTV_400E				0x020f
>>   #define USB_PID_PCTV_450E				0x0222
>> +#define USB_PID_PCTV_452E				0x021f
>> +#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
>> +#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
>>   #define USB_PID_NEBULA_DIGITV				0x0201
>>   #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
>>   #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
>> diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
>> new file mode 100644
>> index 0000000..1be24e5
>> --- /dev/null
>> +++ b/drivers/media/dvb/dvb-usb/pctv452e.c
>> @@ -0,0 +1,1454 @@
>> +/*
>> + * PCTV 452e DVB driver
>> + *
>> + * Copyright (c) 2006-2008 Dominik Kuhlen<dkuhlen@gmx.net>
>> + *
>> + * TT connect S2-3650-CI Common Interface support, MAC readout
>> + * Copyright (C) 2008 Michael H. Schimek<mschimek@gmx.at>
>> + *
>> + * 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.
>> + */
>> +
>> +/* dvb usb framework */
>> +#define DVB_USB_LOG_PREFIX "pctv452e"
>> +#include "dvb-usb.h"
> Due to a change for 3.2, you'll need to include linux/module.h somewhere.
>
>> +
>> +/* Demodulator */
>> +#include "stb0899_drv.h"
>> +#include "stb0899_reg.h"
>> +/* Tuner */
>> +#include "stb6100.h"
>> +#include "stb6100_cfg.h"
>> +/* FE Power */
>> +#include "lnbp22.h"
>> +
>> +#include "dvb_ca_en50221.h"
>> +#include "ttpci-eeprom.h"
>> +
>> +static int debug;
>> +module_param(debug, int, 0644);
>> +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
>> +
>> +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
>> +
>> +#define ISO_BUF_COUNT      4
>> +#define FRAMES_PER_ISO_BUF 4
>> +#define ISO_FRAME_SIZE     940
>> +#define ISOC_INTERFACE_ALTERNATIVE 3
>> +
>> +#define SYNC_BYTE_OUT 0xaa
>> +#define SYNC_BYTE_IN  0x55
>> +
>> +/* guessed: (copied from ttusb-budget) */
>> +#define PCTV_CMD_RESET 0x15
>> +/* command to poll IR receiver */
>> +#define PCTV_CMD_IR    0x1b
>> +/* command to send I2C  */
>> +#define PCTV_CMD_I2C   0x31
>> +
>> +#define I2C_ADDR_STB0899 (0xd0>>  1)
>> +#define I2C_ADDR_STB6100 (0xc0>>  1)
>> +#define I2C_ADDR_LNBP22  (0x10>>  1)
>> +#define I2C_ADDR_24C16   (0xa0>>  1)
>> +#define I2C_ADDR_24C64   (0xa2>>  1)
>> +
>> +
>> +/* pctv452e sends us this amount of data for each issued usb-command */
>> +#define PCTV_ANSWER_LEN 64
>> +/* Wait up to 1000ms for device  */
>> +#define PCTV_TIMEOUT 1000
>> +
>> +
>> +#define PCTV_LED_GPIO   STB0899_GPIO01
>> +#define PCTV_LED_GREEN  0x82
>> +#define PCTV_LED_ORANGE 0x02
>> +
>> +#define ci_dbg(format, arg...)				\
>> +do {							\
>> +	if (0)						\
>> +		printk (KERN_DEBUG DVB_USB_LOG_PREFIX	\
>> +			": " format "\n" , ## arg);	\
>> +} while (0)
>> +
>> +enum {
>> +	TT3650_CMD_CI_TEST = 0x40,
>> +	TT3650_CMD_CI_RD_CTRL,
>> +	TT3650_CMD_CI_WR_CTRL,
>> +	TT3650_CMD_CI_RD_ATTR,
>> +	TT3650_CMD_CI_WR_ATTR,
>> +	TT3650_CMD_CI_RESET,
>> +	TT3650_CMD_CI_SET_VIDEO_PORT
>> +};
>> +
>> +
>> +static struct stb0899_postproc pctv45e_postproc[] = {
>> +	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
>> +	{ 0, 0 }
>> +};
>> +
>> +/*
>> + * stores all private variables for communication with the PCTV452e DVB-S2
>> + */
>> +struct pctv452e_state {
>> +	struct dvb_ca_en50221 ca;
>> +	struct mutex ca_mutex;
>> +
>> +	u8 c;	   /* transaction counter, wraps around...  */
>> +	u8 initialized; /* set to 1 if 0x15 has been sent */
>> +};
>> +
>> +static int
>> +tt3650_ci_msg			(struct dvb_usb_device *d,
>> +				 u8			cmd,
>> +				 u8 *			data,
>> +				 unsigned int		write_len,
>> +				 unsigned int		read_len)
>> +{
>> +	struct pctv452e_state *state = (struct pctv452e_state *) d->priv;
>> +	u8 buf[64];
>> +	u8 id;
>> +	unsigned int rlen;
>> +	int ret;
>> +
>> +	BUG_ON (NULL == data&&  0 != (write_len | read_len));
>> +	BUG_ON (write_len>  64 - 4);
>> +	BUG_ON (read_len>  64 - 4);
>> +
>> +	id = state->c++;
>> +
>> +	buf[0] = SYNC_BYTE_OUT;
>> +	buf[1] = id;
>> +	buf[2] = cmd;
>> +	buf[3] = write_len;
>> +
>> +	memcpy (buf + 4, data, write_len);
>> +
>> +	rlen = (read_len>  0) ? 64 : 0;
>> +	ret = dvb_usb_generic_rw (d, buf, 4 + write_len,
>> +				  buf, rlen, /* delay_ms */ 0);
>> +	if (0 != ret)
>> +		goto failed;
>> +
>> +	ret = -EIO;
>> +	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
>> +		goto failed;
>> +
>> +	memcpy (data, buf + 4, read_len);
>> +
>> +	return 0;
>> +
>> + failed:
>> +	err ("CI error %d; %02X %02X %02X ->  %02X %02X %02X.",
>> +	     ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
>> +
>> +	return ret;
>> +}
>> +
>> +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
>> +				 u8			cmd,
>> +				 u8 *			data,
>> +				 unsigned int		write_len,
>> +				 unsigned int		read_len)
>> +{
>> +	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
>> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
>> +	int ret;
>> +
>> +	mutex_lock(&state->ca_mutex);
>> +	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
>> +	mutex_unlock(&state->ca_mutex);
>> +
>> +	return ret;
>> +}
>> +
>> +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
>> +				 int			slot,
>> +				 int			address)
>> +{
>> +	u8 buf[3];
>> +	int ret;
>> +
>> +	if (0 != slot)
>> +		return -EINVAL;
>> +
>> +	buf[0] = (address>>  8)&  0x0F;
>> +	buf[1] = address;
>> +
>> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
>> +
>> +	ci_dbg ("%s %04x ->  %d 0x%02x",
>> +		__func__, address, ret, buf[2]);
>> +
>> +	if (ret<  0)
>> +		return ret;
>> +
>> +	return buf[2];
>> +}
>> +
>> +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
>> +				 int			slot,
>> +				 int			address,
>> +				 u8			value)
>> +{
>> +	u8 buf[3];
>> +
>> +	ci_dbg("%s %d 0x%04x 0x%02x",
>> +		__func__, slot, address, value);
>> +
>> +	if (0 != slot)
>> +		return -EINVAL;
>> +
>> +	buf[0] = (address>>  8)&  0x0F;
>> +	buf[1] = address;
>> +	buf[2] = value;
>> +
>> +	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
>> +}
>> +
>> +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
>> +				 int			slot,
>> +				 u8			address)
>> +{
>> +	u8 buf[2];
>> +	int ret;
>> +
>> +	if (0 != slot)
>> +		return -EINVAL;
>> +
>> +	buf[0] = address&  3;
>> +
>> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
>> +
>> +	ci_dbg("%s 0x%02x ->  %d 0x%02x",
>> +		__func__, address, ret, buf[1]);
>> +
>> +	if (ret<  0)
>> +		return ret;
>> +
>> +	return buf[1];
>> +}
>> +
>> +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
>> +				 int			slot,
>> +				 u8			address,
>> +				 u8			value)
>> +{
>> +	u8 buf[2];
>> +
>> +	ci_dbg("%s %d 0x%02x 0x%02x",
>> +		__func__, slot, address, value);
>> +
>> +	if (0 != slot)
>> +		return -EINVAL;
>> +
>> +	buf[0] = address;
>> +	buf[1] = value;
>> +
>> +	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
>> +}
>> +
>> +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
>> +				 int			slot,
>> +				 int			enable)
>> +{
>> +	u8 buf[1];
>> +	int ret;
>> +
>> +	ci_dbg("%s %d %d", __func__, slot, enable);
>> +
>> +	if (0 != slot)
>> +		return -EINVAL;
>> +
>> +	enable = !!enable;
>> +	buf[0] = enable;
>> +
>> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
>> +	if (ret<  0)
>> +		return ret;
>> +
>> +	if (enable != buf[0]) {
>> +		err("CI not %sabled.", enable ? "en" : "dis");
>> +		return -EIO;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca,
>> +				 int			slot)
>> +{
>> +	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
>> +}
>> +
>> +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca,
>> +				 int			slot)
>> +{
>> +	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
>> +}
>> +
>> +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca,
>> +				 int			slot)
>> +{
>> +	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
>> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
>> +	u8 buf[1];
>> +	int ret;
>> +
>> +	ci_dbg ("%s %d", __func__, slot);
>> +
>> +	if (0 != slot)
>> +		return -EINVAL;
>> +
>> +	buf[0] = 0;
>> +
>> +	mutex_lock (&state->ca_mutex);
>> +
>> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
>> +	if (0 != ret)
>> +		goto failed;
>> +
>> +	msleep (500);
>> +
>> +	buf[0] = 1;
>> +
>> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
>> +	if (0 != ret)
>> +		goto failed;
>> +
>> +	msleep (500);
>> +
>> +	buf[0] = 0; /* FTA */
>> +
>> +	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
>> +
>> + failed:
>> +	mutex_unlock (&state->ca_mutex);
>> +
>> +	return ret;
>> +}
>> +
>> +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
>> +				 int			slot,
>> +				 int			open)
>> +{
>> +	u8 buf[1];
>> +	int ret;
>> +
>> +	if (0 != slot)
>> +		return -EINVAL;
>> +
>> +	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
>> +	if (0 != ret)
>> +		return ret;
>> +
>> +	if (1 == buf[0]) {
>> +		return (DVB_CA_EN50221_POLL_CAM_PRESENT |
>> +			DVB_CA_EN50221_POLL_CAM_READY);
>> +	} else {
>> +		return 0;
>> +	}
>> +}
>> +
>> +static void tt3650_ci_uninit(struct dvb_usb_device *d)
>> +{
>> +	struct pctv452e_state *state;
>> +
>> +	ci_dbg("%s", __func__);
>> +
>> +	if (NULL == d)
>> +		return;
>> +
>> +	state = (struct pctv452e_state *)d->priv;
>> +	if (NULL == state)
>> +		return;
>> +
>> +	if (NULL == state->ca.data)
>> +		return;
>> +
>> +	/* Error ignored. */
>> +	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
>> +
>> +	dvb_ca_en50221_release(&state->ca);
>> +
>> +	memset(&state->ca, 0, sizeof(state->ca));
>> +}
>> +
>> +static int tt3650_ci_init(struct dvb_usb_adapter *a)
>> +{
>> +	struct dvb_usb_device *d = a->dev;
>> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
>> +	int ret;
>> +
>> +	ci_dbg ("%s", __func__);
>> +
>> +	mutex_init(&state->ca_mutex);
>> +
>> +	state->ca.owner = THIS_MODULE;
>> +	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
>> +	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
>> +	state->ca.read_cam_control = tt3650_ci_read_cam_control;
>> +	state->ca.write_cam_control = tt3650_ci_write_cam_control;
>> +	state->ca.slot_reset = tt3650_ci_slot_reset;
>> +	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
>> +	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
>> +	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
>> +	state->ca.data = d;
>> +
>> +	ret = dvb_ca_en50221_init (&a->dvb_adap,
>> +				&state->ca,
>> +				   /* flags */ 0,
>> +				   /* n_slots */ 1);
>> +	if (0 != ret) {
>> +		err ("Cannot initialize CI: Error %d.", ret);
>> +		memset (&state->ca, 0, sizeof (state->ca));
>> +		return ret;
>> +	}
>> +
>> +	info ("CI initialized.");
>> +
>> +	return 0;
>> +}
>> +
>> +  #define CMD_BUFFER_SIZE 0x28
>> +static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, const u8 * snd_buf,
>> +				u8 snd_len, u8 * rcv_buf, u8 rcv_len) {
>> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
>> +	u8 buf[64];
>> +	u8 id;
>> +	int ret;
>> +
>> +	id = state->c++;
>> +
>> +	ret = -EINVAL;
>> +	if (snd_len>  64 - 7 || rcv_len>  64 - 7)
>> +		goto failed;
>> +
>> +	buf[0] = SYNC_BYTE_OUT;
>> +	buf[1] = id;
>> +	buf[2] = PCTV_CMD_I2C;
>> +	buf[3] = snd_len + 3;
>> +	buf[4] = addr<<  1;
>> +	buf[5] = snd_len;
>> +	buf[6] = rcv_len;
>> +
>> +	memcpy (buf + 7, snd_buf, snd_len);
>> +
>> +	ret = dvb_usb_generic_rw (d, buf, 7 + snd_len,
>> +				  buf, /* rcv_len */ 64,
>> +				  /* delay_ms */ 0);
>> +	if (ret<  0)
>> +		goto failed;
>> +
>> +	/* TT USB protocol error. */
>> +	ret = -EIO;
>> +	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
>> +		goto failed;
>> +
>> +	/* I2C device didn't respond as expected. */
>> +	ret = -EREMOTEIO;
>> +	if (buf[5]<  snd_len || buf[6]<  rcv_len)
>> +		goto failed;
>> +
>> +	memcpy (rcv_buf, buf + 7, rcv_len);
>> +
>> +	return rcv_len;
>> +
>> + failed:
>> +	err ("I2C error %d; %02X %02X  %02X %02X %02X ->  "
>> +	     "%02X %02X  %02X %02X %02X.",
>> +	     ret, SYNC_BYTE_OUT, id, addr<<  1, snd_len, rcv_len,
>> +	     buf[0], buf[1], buf[4], buf[5], buf[6]);
>> +
>> +	return ret;
>> +}
>> +
>> +static int pctv452e_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) {
>> +	struct dvb_usb_device *d= i2c_get_adapdata(adapter);
>> +	int i;
>> +
>> +	if (mutex_lock_interruptible(&d->i2c_mutex)<  0)
>> +		return -EAGAIN;
>> +
>> +	for (i = 0; i<  num; i++) {
>> +		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
>> +		int err;
>> +
>> +		if (msg[i].flags&  I2C_M_RD) {
>> +			addr = msg[i].addr;
>> +			snd_buf = NULL;
>> +			snd_len = 0;
>> +			rcv_buf = msg[i].buf;
>> +			rcv_len = msg[i].len;
>> +		} else {
>> +			addr = msg[i].addr;
>> +			snd_buf = msg[i].buf;
>> +			snd_len = msg[i].len;
>> +			rcv_buf = NULL;
>> +			rcv_len = 0;
>> +		}
>> +
>> +		err = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf, rcv_len);
>> +		if (err<  rcv_len)
>> +			break;
>> +	}
>> +
>> +	mutex_unlock(&d->i2c_mutex);
>> +	return i;
>> +}
>> +
>> +static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) {
>> +	return I2C_FUNC_I2C;
>> +}
>> +
>> +int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) {
>> +	struct pctv452e_state *state = (struct pctv452e_state*)d->priv;
>> +	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
>> +	u8 rx[PCTV_ANSWER_LEN];
>> +	int ret;
>> +		printk("%s: %d\n", __func__, i);
>> +	if (i) {
>> +		if (!state->initialized) {
>> +			// hmm where shoud this should go?
>> +			ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
>> +			if (ret != 0) {
>> +				printk("%s: Warning set interface returned: %d\n", __func__, ret);
>> +			}
>> +
>> +			// this is a one-time initialization, dont know where to put
>> +			b0[1] = state->c++;
>> +			// reset board
>> +			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
>> +
>> +			b0[1] = state->c++;
>> +			b0[4] = 1;
>> +			// reset board (again?)
>> +			if ((ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0))) return ret;
>> +
>> +			state->initialized = 1;
>> +		}
>> +	} else {
>> +		// power down ?
>> +	}
>> +	return 0;
>> +}
>> +
>> +/* Remote control stuff */
>> +static struct rc_map_table pctv452e_rc_keys[] = {
>> +	{0x0700, KEY_MUTE},
>> +	{0x0701, KEY_VENDOR},  // pinnacle logo (top middle)
>> +	{0x0739, KEY_POWER},
>> +	{0x0703, KEY_VOLUMEUP},
>> +	{0x0709, KEY_VOLUMEDOWN},
>> +	{0x0706, KEY_CHANNELUP},
>> +	{0x070c, KEY_CHANNELDOWN},
>> +	{0x070f, KEY_1},
>> +	{0x0715, KEY_2},
>> +	{0x0710, KEY_3},
>> +	{0x0718, KEY_4},
>> +	{0x071b, KEY_5},
>> +	{0x071e, KEY_6},
>> +	{0x0711, KEY_7},
>> +	{0x0721, KEY_8},
>> +	{0x0712, KEY_9},
>> +	{0x0727, KEY_0},
>> +	{0x0724, KEY_TV}, // left of '0'
>> +	{0x072a, KEY_T}, // right of '0'
>> +	{0x072d, KEY_REWIND},
>> +	{0x0733, KEY_FORWARD},
>> +	{0x0730, KEY_PLAY},
>> +	{0x0736, KEY_RECORD},
>> +	{0x073c, KEY_STOP},
>> +	{0x073f, KEY_HELP}
>> +};
>> +
>> +/* Remote Control Stuff fo S2-3600 (copied from TT-S1500): */
>> +static struct rc_map_table tt_connect_s2_3600_rc_key[] = {
>> +	{0x1501, KEY_POWER},
>> +	{0x1502, KEY_SHUFFLE}, /* ? double-arrow key */
>> +	{0x1503, KEY_1},
>> +	{0x1504, KEY_2},
>> +	{0x1505, KEY_3},
>> +	{0x1506, KEY_4},
>> +	{0x1507, KEY_5},
>> +	{0x1508, KEY_6},
>> +	{0x1509, KEY_7},
>> +	{0x150a, KEY_8},
>> +	{0x150b, KEY_9},
>> +	{0x150c, KEY_0},
>> +	{0x150d, KEY_UP},
>> +	{0x150e, KEY_LEFT},
>> +	{0x150f, KEY_OK},
>> +	{0x1510, KEY_RIGHT},
>> +	{0x1511, KEY_DOWN},
>> +	{0x1512, KEY_INFO},
>> +	{0x1513, KEY_EXIT},
>> +	{0x1514, KEY_RED},
>> +	{0x1515, KEY_GREEN},
>> +	{0x1516, KEY_YELLOW},
>> +	{0x1517, KEY_BLUE},
>> +	{0x1518, KEY_MUTE},
>> +	{0x1519, KEY_TEXT},
>> +	{0x151a, KEY_MODE},  /* ? TV/Radio */
>> +	{0x1521, KEY_OPTION},
>> +	{0x1522, KEY_EPG},
>> +	{0x1523, KEY_CHANNELUP},
>> +	{0x1524, KEY_CHANNELDOWN},
>> +	{0x1525, KEY_VOLUMEUP},
>> +	{0x1526, KEY_VOLUMEDOWN},
>> +	{0x1527, KEY_SETUP},
>> +	{0x153a, KEY_RECORD},/* these keys are only in the black remote */
>> +	{0x153b, KEY_PLAY},
>> +	{0x153c, KEY_STOP},
>> +	{0x153d, KEY_REWIND},
>> +	{0x153e, KEY_PAUSE},
>> +	{0x153f, KEY_FORWARD}
>> +};
> Keytables should be moved to drivers/media/rc/keymaps
>
>> +
>> +static int pctv452e_rc_query(struct dvb_usb_device *d, u32 *keyevent, int *keystate) {
>> +	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
>> +	u8 b[CMD_BUFFER_SIZE];
>> +	u8 rx[PCTV_ANSWER_LEN];
>> +	u8 keybuf[5];
>> +	int ret, i;
>> +	u8 id = state->c++;
>> +
>> +	/* prepare command header  */
>> +	b[0] = SYNC_BYTE_OUT;
>> +	b[1] = id;
>> +	b[2] = PCTV_CMD_IR;
>> +	b[3] = 0;
>> +
>> +	*keystate = REMOTE_NO_KEY_PRESSED;
>> +
>> +	/* send ir request */
>> +	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
>> +	if (ret != 0) return ret;
>> +
>> +	if (debug>  3) {
>> +		printk("%s: read: %2d: %02x %02x %02x: ", __func__, ret, rx[0], rx[1], rx[2]);
>> +		for (i = 0; (i<  rx[3])&&  ((i+3)<  PCTV_ANSWER_LEN); i++) {
>> +			printk(" %02x", rx[i+3]);
>> +		}
>> +		printk("\n");
>> +	}
>> +
>> +	if ((rx[3] == 9)&&   (rx[12]&  0x01)) {
>> +		/* got a "press" event */
>> +		if (debug>  2) {
>> +	 		printk("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[6], rx[7]);
>> +		}
>> +		keybuf[0] = 0x01;// DVB_USB_RC_NEC_KEY_PRESSED; why is this #define'd privately?
>> +		keybuf[1] = rx[7];
>> +		keybuf[2] = ~keybuf[1]; // fake checksum
>> +		keybuf[3] = rx[6];
>> +		keybuf[4] = ~keybuf[3]; // fake checksum
>> +		dvb_usb_nec_rc_key_to_event(d, keybuf, keyevent, keystate);
>> +
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int
>> +pctv452e_read_mac_address	(struct dvb_usb_device *d,
>> +				 u8			mac[6])
>> +{
>> +	const u8 mem_addr[] = { 0x1F, 0xCC };
>> +	u8 encoded_mac[20];
>> +	int ret;
>> +
>> +	ret = -EAGAIN;
>> +	if (mutex_lock_interruptible (&d->i2c_mutex)<  0)
>> +		goto failed;
>> +
>> +	ret = pctv452e_i2c_msg (d, I2C_ADDR_24C16,
>> +				mem_addr + 1, /* snd_len */ 1,
>> +				encoded_mac, /* rcv_len */ 20);
>> +	if (-EREMOTEIO == ret) {
>> +		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
>> +		   byte write if /WC is low. */
>> +		ret = pctv452e_i2c_msg (d, I2C_ADDR_24C64,
>> +					mem_addr, 2,
>> +					encoded_mac, 20);
>> +	}
>> +
>> +	mutex_unlock (&d->i2c_mutex);
>> +
>> +	if (20 != ret)
>> +		goto failed;
>> +
>> +	ret = ttpci_eeprom_decode_mac (mac, encoded_mac);
>> +	if (0 != ret)
>> +		goto failed;
>> +
>> +	return 0;
>> +
>> + failed:
>> +	memset (mac, 0, 6);
>> +
>> +	return ret;
>> +}
>> +
>> +
>> +static struct stb0899_config stb0899_config;
>> +static struct stb6100_config stb6100_config;
>> +static struct dvb_usb_device_properties pctv452e_properties;
>> +static struct dvb_usb_device_properties tt_connect_s2_3600_properties;
>> +
>> +int pctv452e_frontend_attach(struct dvb_usb_adapter *a) {
>> +	struct usb_device_id *id;
>> +
>> +		printk("%s Enter\n", __func__);
>> +
>> +	a->fe[0] = dvb_attach(stb0899_attach,&stb0899_config,&a->dev->i2c_adap);
>> +	if (!a->fe[0]) return -ENODEV;
>> +	if ((dvb_attach(lnbp22_attach, a->fe[0],&a->dev->i2c_adap)) == 0) {
>> +		printk("Warning: cannot attach lnbp22\n");
>> +	}
>> +
>> +	id = a->dev->desc->warm_ids[0];
>> +	if (USB_VID_TECHNOTREND == id->idVendor
>> +	&&  USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct) {
>> +		/* Error ignored. */
>> +		tt3650_ci_init (a);
>> +	}
>> +
>> +		printk("%s Leave Ok\n", __func__);
>> +	return 0;
>> +}
>> +
>> +int pctv452e_tuner_attach(struct dvb_usb_adapter *a) {
>> +		printk("%s Enter\n", __func__);
>> +	if (!a->fe[0]) return -ENODEV;
>> +	if (dvb_attach(stb6100_attach, a->fe[0],&stb6100_config,&a->dev->i2c_adap) == 0) {
>> +		printk("%s failed\n", __func__);
>> +		return -ENODEV;
>> +	}
>> +		printk("%s Leave\n", __func__);
>> +	return 0;
>> +}
>> +
>> +static void
>> +pctv452e_usb_disconnect		(struct usb_interface *	intf)
>> +{
>> +	struct dvb_usb_device *d = usb_get_intfdata (intf);
>> +
>> +	tt3650_ci_uninit (d);
>> +	dvb_usb_device_exit (intf);
>> +}
>> +
>> +static int pctv452e_usb_probe(struct usb_interface *intf,const struct usb_device_id *id) {
>> +	int ret=-ENOMEM;
>> +	if ((ret=dvb_usb_device_init(intf,&pctv452e_properties, THIS_MODULE, NULL, adapter_nr))==0){
>> +		return ret;
>> +	}
>> +	return dvb_usb_device_init(intf,&tt_connect_s2_3600_properties, THIS_MODULE, NULL, adapter_nr);
>> +}
>> +
>> +
>> +
>> +static const struct stb0899_s1_reg pctv452e_init_dev [] = {
>> +	{ STB0899_DISCNTRL1	, 0x26 },
>> +	{ STB0899_DISCNTRL2	, 0x80 },
>> +	{ STB0899_DISRX_ST0	, 0x04 },
>> +	{ STB0899_DISRX_ST1	, 0x20 },
>> +	{ STB0899_DISPARITY	, 0x00 },
>> +	{ STB0899_DISFIFO	, 0x00 },
>> +	{ STB0899_DISF22	, 0x99 },
>> +	{ STB0899_DISF22RX	, 0x85 }, // 0xa8
>> +	{ STB0899_ACRPRESC	, 0x11 },
>> +	{ STB0899_ACRDIV1	, 0x0a },
>> +	{ STB0899_ACRDIV2	, 0x05 },
>> +	{ STB0899_DACR1		, 0x00 },
>> +	{ STB0899_DACR2		, 0x00 },
>> +	{ STB0899_OUTCFG	, 0x00 },
>> +	{ STB0899_MODECFG	, 0x00 }, // Inversion
>> + 	{ STB0899_IRQMSK_3	, 0xf3 },
>> + 	{ STB0899_IRQMSK_2	, 0xfc },
>> + 	{ STB0899_IRQMSK_1	, 0xff },
>> + 	{ STB0899_IRQMSK_0	, 0xff },
>> +	{ STB0899_I2CCFG	, 0x88 },
>> +	{ STB0899_I2CRPT	, 0x58 },
>> +	{ STB0899_GPIO00CFG	, 0x82 },
>> +	{ STB0899_GPIO01CFG	, 0x82 }, /* 0x02 ->  LED green 0x82 ->  LED orange */
>> +	{ STB0899_GPIO02CFG	, 0x82 },
>> +	{ STB0899_GPIO03CFG	, 0x82 },
>> +	{ STB0899_GPIO04CFG	, 0x82 },
>> +	{ STB0899_GPIO05CFG	, 0x82 },
>> +	{ STB0899_GPIO06CFG	, 0x82 },
>> +	{ STB0899_GPIO07CFG	, 0x82 },
>> +	{ STB0899_GPIO08CFG	, 0x82 },
>> +	{ STB0899_GPIO09CFG	, 0x82 },
>> +	{ STB0899_GPIO10CFG	, 0x82 },
>> +	{ STB0899_GPIO11CFG	, 0x82 },
>> +	{ STB0899_GPIO12CFG	, 0x82 },
>> +	{ STB0899_GPIO13CFG	, 0x82 },
>> +	{ STB0899_GPIO14CFG	, 0x82 },
>> +	{ STB0899_GPIO15CFG	, 0x82 },
>> +	{ STB0899_GPIO16CFG	, 0x82 },
>> +	{ STB0899_GPIO17CFG	, 0x82 },
>> +	{ STB0899_GPIO18CFG	, 0x82 },
>> +	{ STB0899_GPIO19CFG	, 0x82 },
>> +	{ STB0899_GPIO20CFG	, 0x82 },
>> +	{ STB0899_SDATCFG	, 0xb8 },
>> +	{ STB0899_SCLTCFG	, 0xba },
>> +	{ STB0899_AGCRFCFG	, 0x1c }, // 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm)
>> +	{ STB0899_GPIO22	, 0x82 },
>> +	{ STB0899_GPIO21	, 0x91 },
>> +	{ STB0899_DIRCLKCFG	, 0x82 },
>> +	{ STB0899_CLKOUT27CFG	, 0x7e },
>> +	{ STB0899_STDBYCFG	, 0x82 },
>> +	{ STB0899_CS0CFG	, 0x82 },
>> +	{ STB0899_CS1CFG	, 0x82 },
>> +	{ STB0899_DISEQCOCFG	, 0x20 },
>> +	{ STB0899_NCOARSE	, 0x15 }, // 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 108MHz
>> +	{ STB0899_SYNTCTRL	, 0x00 }, // 0x00 = CLK from CLKI, 0x02 = CLK from XTALI
>> +	{ STB0899_FILTCTRL	, 0x00 },
>> +	{ STB0899_SYSCTRL	, 0x00 },
>> +	{ STB0899_STOPCLK1	, 0x20 }, // orig: 0x00 budget-ci: 0x20
>> +	{ STB0899_STOPCLK2	, 0x00 },
>> +	{ STB0899_INTBUFCTRL	, 0x0a },
>> +	{ STB0899_AGC2I1	, 0x00 },
>> +	{ STB0899_AGC2I2	, 0x00 },
>> +	{ STB0899_AGCIQIN       , 0x00 },
>> +	{ STB0899_TSTRES	, 0x40 }, //rjkm
>> +	{0xffff, 0xff},
>> +};
>> +
>> +static const struct stb0899_s2_reg pctv452e_init_s2_demod[]  = {
>> +	{ STB0899_OFF0_DMD_STATUS	, STB0899_BASE_DMD_STATUS	, 0x00000103 },	/* DMDSTATUS	*/
>> +	{ STB0899_OFF0_CRL_FREQ		, STB0899_BASE_CRL_FREQ		, 0x3ed1da56 },	/* CRLFREQ	*/
>> +	{ STB0899_OFF0_BTR_FREQ		, STB0899_BASE_BTR_FREQ		, 0x00004000 },	/* BTRFREQ	*/
>> +	{ STB0899_OFF0_IF_AGC_GAIN	, STB0899_BASE_IF_AGC_GAIN	, 0x00002ade },	/* IFAGCGAIN	*/
>> +	{ STB0899_OFF0_BB_AGC_GAIN	, STB0899_BASE_BB_AGC_GAIN	, 0x000001bc },	/* BBAGCGAIN	*/
>> +	{ STB0899_OFF0_DC_OFFSET	, STB0899_BASE_DC_OFFSET	, 0x00000200 },	/* DCOFFSET	*/
>> +	{ STB0899_OFF0_DMD_CNTRL	, STB0899_BASE_DMD_CNTRL	, 0x0000000f },	/* DMDCNTRL	*/
>> +
>> +	{ STB0899_OFF0_IF_AGC_CNTRL	, STB0899_BASE_IF_AGC_CNTRL	, 0x03fb4a20 },	/* IFAGCCNTRL	*/
>> +	{ STB0899_OFF0_BB_AGC_CNTRL	, STB0899_BASE_BB_AGC_CNTRL	, 0x00200c97 },	/* BBAGCCNTRL	*/
>> +
>> +	{ STB0899_OFF0_CRL_CNTRL	, STB0899_BASE_CRL_CNTRL	, 0x00000016 },	/* CRLCNTRL	*/
>> +	{ STB0899_OFF0_CRL_PHS_INIT	, STB0899_BASE_CRL_PHS_INIT	, 0x00000000 },	/* CRLPHSINIT	*/
>> +	{ STB0899_OFF0_CRL_FREQ_INIT	, STB0899_BASE_CRL_FREQ_INIT	, 0x00000000 },	/* CRLFREQINIT	*/
>> +	{ STB0899_OFF0_CRL_LOOP_GAIN	, STB0899_BASE_CRL_LOOP_GAIN	, 0x00000000 },	/* CRLLOOPGAIN	*/
>> +	{ STB0899_OFF0_CRL_NOM_FREQ	, STB0899_BASE_CRL_NOM_FREQ	, 0x3ed097b6 },	/* CRLNOMFREQ	*/
>> +	{ STB0899_OFF0_CRL_SWP_RATE	, STB0899_BASE_CRL_SWP_RATE	, 0x00000000 },	/* CRLSWPRATE	*/
>> +	{ STB0899_OFF0_CRL_MAX_SWP	, STB0899_BASE_CRL_MAX_SWP	, 0x00000000 },	/* CRLMAXSWP	*/
>> +	{ STB0899_OFF0_CRL_LK_CNTRL	, STB0899_BASE_CRL_LK_CNTRL	, 0x0f6cdc01 },	/* CRLLKCNTRL	*/
>> +	{ STB0899_OFF0_DECIM_CNTRL	, STB0899_BASE_DECIM_CNTRL	, 0x00000000 },	/* DECIMCNTRL	*/
>> +	{ STB0899_OFF0_BTR_CNTRL	, STB0899_BASE_BTR_CNTRL	, 0x00003993 },	/* BTRCNTRL	*/
>> +	{ STB0899_OFF0_BTR_LOOP_GAIN	, STB0899_BASE_BTR_LOOP_GAIN	, 0x000d3c6f },	/* BTRLOOPGAIN	*/
>> +	{ STB0899_OFF0_BTR_PHS_INIT	, STB0899_BASE_BTR_PHS_INIT	, 0x00000000 },	/* BTRPHSINIT	*/
>> +	{ STB0899_OFF0_BTR_FREQ_INIT	, STB0899_BASE_BTR_FREQ_INIT	, 0x00000000 },	/* BTRFREQINIT	*/
>> +	{ STB0899_OFF0_BTR_NOM_FREQ	, STB0899_BASE_BTR_NOM_FREQ	, 0x0238e38e },	/* BTRNOMFREQ	*/
>> +	{ STB0899_OFF0_BTR_LK_CNTRL	, STB0899_BASE_BTR_LK_CNTRL	, 0x00000000 },	/* BTRLKCNTRL	*/
>> +	{ STB0899_OFF0_DECN_CNTRL	, STB0899_BASE_DECN_CNTRL	, 0x00000000 },	/* DECNCNTRL	*/
>> +	{ STB0899_OFF0_TP_CNTRL		, STB0899_BASE_TP_CNTRL		, 0x00000000 },	/* TPCNTRL	*/
>> +	{ STB0899_OFF0_TP_BUF_STATUS	, STB0899_BASE_TP_BUF_STATUS	, 0x00000000 },	/* TPBUFSTATUS	*/
>> +	{ STB0899_OFF0_DC_ESTIM		, STB0899_BASE_DC_ESTIM		, 0x00000000 },	/* DCESTIM	*/
>> +	{ STB0899_OFF0_FLL_CNTRL	, STB0899_BASE_FLL_CNTRL	, 0x00000000 },	/* FLLCNTRL	*/
>> +	{ STB0899_OFF0_FLL_FREQ_WD	, STB0899_BASE_FLL_FREQ_WD	, 0x40070000 },	/* FLLFREQWD	*/
>> +	{ STB0899_OFF0_ANTI_ALIAS_SEL	, STB0899_BASE_ANTI_ALIAS_SEL	, 0x00000001 },	/* ANTIALIASSEL */
>> +	{ STB0899_OFF0_RRC_ALPHA	, STB0899_BASE_RRC_ALPHA	, 0x00000002 },	/* RRCALPHA	*/
>> +	{ STB0899_OFF0_DC_ADAPT_LSHFT	, STB0899_BASE_DC_ADAPT_LSHFT	, 0x00000000 },	/* DCADAPTISHFT */
>> +	{ STB0899_OFF0_IMB_OFFSET	, STB0899_BASE_IMB_OFFSET	, 0x0000fe01 },	/* IMBOFFSET	*/
>> +	{ STB0899_OFF0_IMB_ESTIMATE	, STB0899_BASE_IMB_ESTIMATE	, 0x00000000 },	/* IMBESTIMATE	*/
>> +	{ STB0899_OFF0_IMB_CNTRL	, STB0899_BASE_IMB_CNTRL	, 0x00000001 },	/* IMBCNTRL	*/
>> +	{ STB0899_OFF0_IF_AGC_CNTRL2	, STB0899_BASE_IF_AGC_CNTRL2	, 0x00005007 },	/* IFAGCCNTRL2	*/
>> +	{ STB0899_OFF0_DMD_CNTRL2	, STB0899_BASE_DMD_CNTRL2	, 0x00000002 },	/* DMDCNTRL2	*/
>> +	{ STB0899_OFF0_TP_BUFFER	, STB0899_BASE_TP_BUFFER	, 0x00000000 },	/* TPBUFFER	*/
>> +	{ STB0899_OFF0_TP_BUFFER1	, STB0899_BASE_TP_BUFFER1	, 0x00000000 },	/* TPBUFFER1	*/
>> +	{ STB0899_OFF0_TP_BUFFER2	, STB0899_BASE_TP_BUFFER2	, 0x00000000 },	/* TPBUFFER2	*/
>> +	{ STB0899_OFF0_TP_BUFFER3	, STB0899_BASE_TP_BUFFER3	, 0x00000000 },	/* TPBUFFER3	*/
>> +	{ STB0899_OFF0_TP_BUFFER4	, STB0899_BASE_TP_BUFFER4	, 0x00000000 },	/* TPBUFFER4	*/
>> +	{ STB0899_OFF0_TP_BUFFER5	, STB0899_BASE_TP_BUFFER5	, 0x00000000 },	/* TPBUFFER5	*/
>> +	{ STB0899_OFF0_TP_BUFFER6	, STB0899_BASE_TP_BUFFER6	, 0x00000000 },	/* TPBUFFER6	*/
>> +	{ STB0899_OFF0_TP_BUFFER7	, STB0899_BASE_TP_BUFFER7	, 0x00000000 },	/* TPBUFFER7	*/
>> +	{ STB0899_OFF0_TP_BUFFER8	, STB0899_BASE_TP_BUFFER8	, 0x00000000 },	/* TPBUFFER8	*/
>> +	{ STB0899_OFF0_TP_BUFFER9	, STB0899_BASE_TP_BUFFER9	, 0x00000000 },	/* TPBUFFER9	*/
>> +	{ STB0899_OFF0_TP_BUFFER10	, STB0899_BASE_TP_BUFFER10	, 0x00000000 },	/* TPBUFFER10	*/
>> +	{ STB0899_OFF0_TP_BUFFER11	, STB0899_BASE_TP_BUFFER11	, 0x00000000 },	/* TPBUFFER11	*/
>> +	{ STB0899_OFF0_TP_BUFFER12	, STB0899_BASE_TP_BUFFER12	, 0x00000000 },	/* TPBUFFER12	*/
>> +	{ STB0899_OFF0_TP_BUFFER13	, STB0899_BASE_TP_BUFFER13	, 0x00000000 },	/* TPBUFFER13	*/
>> +	{ STB0899_OFF0_TP_BUFFER14	, STB0899_BASE_TP_BUFFER14	, 0x00000000 },	/* TPBUFFER14	*/
>> +	{ STB0899_OFF0_TP_BUFFER15	, STB0899_BASE_TP_BUFFER15	, 0x00000000 },	/* TPBUFFER15	*/
>> +	{ STB0899_OFF0_TP_BUFFER16	, STB0899_BASE_TP_BUFFER16	, 0x0000ff00 },	/* TPBUFFER16	*/
>> +	{ STB0899_OFF0_TP_BUFFER17	, STB0899_BASE_TP_BUFFER17	, 0x00000100 },	/* TPBUFFER17	*/
>> +	{ STB0899_OFF0_TP_BUFFER18	, STB0899_BASE_TP_BUFFER18	, 0x0000fe01 },	/* TPBUFFER18	*/
>> +	{ STB0899_OFF0_TP_BUFFER19	, STB0899_BASE_TP_BUFFER19	, 0x000004fe },	/* TPBUFFER19	*/
>> +	{ STB0899_OFF0_TP_BUFFER20	, STB0899_BASE_TP_BUFFER20	, 0x0000cfe7 },	/* TPBUFFER20	*/
>> +	{ STB0899_OFF0_TP_BUFFER21	, STB0899_BASE_TP_BUFFER21	, 0x0000bec6 },	/* TPBUFFER21	*/
>> +	{ STB0899_OFF0_TP_BUFFER22	, STB0899_BASE_TP_BUFFER22	, 0x0000c2bf },	/* TPBUFFER22	*/
>> +	{ STB0899_OFF0_TP_BUFFER23	, STB0899_BASE_TP_BUFFER23	, 0x0000c1c1 },	/* TPBUFFER23	*/
>> +	{ STB0899_OFF0_TP_BUFFER24	, STB0899_BASE_TP_BUFFER24	, 0x0000c1c1 },	/* TPBUFFER24	*/
>> +	{ STB0899_OFF0_TP_BUFFER25	, STB0899_BASE_TP_BUFFER25	, 0x0000c1c1 },	/* TPBUFFER25	*/
>> +	{ STB0899_OFF0_TP_BUFFER26	, STB0899_BASE_TP_BUFFER26	, 0x0000c1c1 },	/* TPBUFFER26	*/
>> +	{ STB0899_OFF0_TP_BUFFER27	, STB0899_BASE_TP_BUFFER27	, 0x0000c1c0 },	/* TPBUFFER27	*/
>> +	{ STB0899_OFF0_TP_BUFFER28	, STB0899_BASE_TP_BUFFER28	, 0x0000c0c0 },	/* TPBUFFER28	*/
>> +	{ STB0899_OFF0_TP_BUFFER29	, STB0899_BASE_TP_BUFFER29	, 0x0000c1c1 },	/* TPBUFFER29	*/
>> +	{ STB0899_OFF0_TP_BUFFER30	, STB0899_BASE_TP_BUFFER30	, 0x0000c1c1 },	/* TPBUFFER30	*/
>> +	{ STB0899_OFF0_TP_BUFFER31	, STB0899_BASE_TP_BUFFER31	, 0x0000c0c1 },	/* TPBUFFER31	*/
>> +	{ STB0899_OFF0_TP_BUFFER32	, STB0899_BASE_TP_BUFFER32	, 0x0000c0c1 },	/* TPBUFFER32	*/
>> +	{ STB0899_OFF0_TP_BUFFER33	, STB0899_BASE_TP_BUFFER33	, 0x0000c1c1 },	/* TPBUFFER33	*/
>> +	{ STB0899_OFF0_TP_BUFFER34	, STB0899_BASE_TP_BUFFER34	, 0x0000c1c1 },	/* TPBUFFER34	*/
>> +	{ STB0899_OFF0_TP_BUFFER35	, STB0899_BASE_TP_BUFFER35	, 0x0000c0c1 },	/* TPBUFFER35	*/
>> +	{ STB0899_OFF0_TP_BUFFER36	, STB0899_BASE_TP_BUFFER36	, 0x0000c1c1 },	/* TPBUFFER36	*/
>> +	{ STB0899_OFF0_TP_BUFFER37	, STB0899_BASE_TP_BUFFER37	, 0x0000c0c1 },	/* TPBUFFER37	*/
>> +	{ STB0899_OFF0_TP_BUFFER38	, STB0899_BASE_TP_BUFFER38	, 0x0000c1c1 },	/* TPBUFFER38	*/
>> +	{ STB0899_OFF0_TP_BUFFER39	, STB0899_BASE_TP_BUFFER39	, 0x0000c0c0 },	/* TPBUFFER39	*/
>> +	{ STB0899_OFF0_TP_BUFFER40	, STB0899_BASE_TP_BUFFER40	, 0x0000c1c0 },	/* TPBUFFER40	*/
>> +	{ STB0899_OFF0_TP_BUFFER41	, STB0899_BASE_TP_BUFFER41	, 0x0000c1c1 },	/* TPBUFFER41	*/
>> +	{ STB0899_OFF0_TP_BUFFER42	, STB0899_BASE_TP_BUFFER42	, 0x0000c0c0 },	/* TPBUFFER42	*/
>> +	{ STB0899_OFF0_TP_BUFFER43	, STB0899_BASE_TP_BUFFER43	, 0x0000c1c0 },	/* TPBUFFER43	*/
>> +	{ STB0899_OFF0_TP_BUFFER44	, STB0899_BASE_TP_BUFFER44	, 0x0000c0c1 },	/* TPBUFFER44	*/
>> +	{ STB0899_OFF0_TP_BUFFER45	, STB0899_BASE_TP_BUFFER45	, 0x0000c1be },	/* TPBUFFER45	*/
>> +	{ STB0899_OFF0_TP_BUFFER46	, STB0899_BASE_TP_BUFFER46	, 0x0000c1c9 },	/* TPBUFFER46	*/
>> +	{ STB0899_OFF0_TP_BUFFER47	, STB0899_BASE_TP_BUFFER47	, 0x0000c0da },	/* TPBUFFER47	*/
>> +	{ STB0899_OFF0_TP_BUFFER48	, STB0899_BASE_TP_BUFFER48	, 0x0000c0ba },	/* TPBUFFER48	*/
>> +	{ STB0899_OFF0_TP_BUFFER49	, STB0899_BASE_TP_BUFFER49	, 0x0000c1c4 },	/* TPBUFFER49	*/
>> +	{ STB0899_OFF0_TP_BUFFER50	, STB0899_BASE_TP_BUFFER50	, 0x0000c1bf },	/* TPBUFFER50	*/
>> +	{ STB0899_OFF0_TP_BUFFER51	, STB0899_BASE_TP_BUFFER51	, 0x0000c0c1 },	/* TPBUFFER51	*/
>> +	{ STB0899_OFF0_TP_BUFFER52	, STB0899_BASE_TP_BUFFER52	, 0x0000c1c0 },	/* TPBUFFER52	*/
>> +	{ STB0899_OFF0_TP_BUFFER53	, STB0899_BASE_TP_BUFFER53	, 0x0000c0c1 },	/* TPBUFFER53	*/
>> +	{ STB0899_OFF0_TP_BUFFER54	, STB0899_BASE_TP_BUFFER54	, 0x0000c1c1 },	/* TPBUFFER54	*/
>> +	{ STB0899_OFF0_TP_BUFFER55	, STB0899_BASE_TP_BUFFER55	, 0x0000c1c1 },	/* TPBUFFER55	*/
>> +	{ STB0899_OFF0_TP_BUFFER56	, STB0899_BASE_TP_BUFFER56	, 0x0000c1c1 },	/* TPBUFFER56	*/
>> +	{ STB0899_OFF0_TP_BUFFER57	, STB0899_BASE_TP_BUFFER57	, 0x0000c1c1 },	/* TPBUFFER57	*/
>> +	{ STB0899_OFF0_TP_BUFFER58	, STB0899_BASE_TP_BUFFER58	, 0x0000c1c1 },	/* TPBUFFER58	*/
>> +	{ STB0899_OFF0_TP_BUFFER59	, STB0899_BASE_TP_BUFFER59	, 0x0000c1c1 },	/* TPBUFFER59	*/
>> +	{ STB0899_OFF0_TP_BUFFER60	, STB0899_BASE_TP_BUFFER60	, 0x0000c1c1 },	/* TPBUFFER60	*/
>> +	{ STB0899_OFF0_TP_BUFFER61	, STB0899_BASE_TP_BUFFER61	, 0x0000c1c1 },	/* TPBUFFER61	*/
>> +	{ STB0899_OFF0_TP_BUFFER62	, STB0899_BASE_TP_BUFFER62	, 0x0000c1c1 },	/* TPBUFFER62	*/
>> +	{ STB0899_OFF0_TP_BUFFER63	, STB0899_BASE_TP_BUFFER63	, 0x0000c1c0 },	/* TPBUFFER63	*/
>> +	{ STB0899_OFF0_RESET_CNTRL	, STB0899_BASE_RESET_CNTRL	, 0x00000001 },	/* RESETCNTRL	*/
>> +	{ STB0899_OFF0_ACM_ENABLE	, STB0899_BASE_ACM_ENABLE	, 0x00005654 },	/* ACMENABLE	*/
>> +	{ STB0899_OFF0_DESCR_CNTRL	, STB0899_BASE_DESCR_CNTRL	, 0x00000000 },	/* DESCRCNTRL	*/
>> +	{ STB0899_OFF0_CSM_CNTRL1	, STB0899_BASE_CSM_CNTRL1	, 0x00020019 },	/* CSMCNTRL1	*/
>> +	{ STB0899_OFF0_CSM_CNTRL2	, STB0899_BASE_CSM_CNTRL2	, 0x004b3237 },	/* CSMCNTRL2	*/
>> +	{ STB0899_OFF0_CSM_CNTRL3	, STB0899_BASE_CSM_CNTRL3	, 0x0003dd17 },	/* CSMCNTRL3	*/
>> +	{ STB0899_OFF0_CSM_CNTRL4	, STB0899_BASE_CSM_CNTRL4	, 0x00008008 },	/* CSMCNTRL4	*/
>> +	{ STB0899_OFF0_UWP_CNTRL1	, STB0899_BASE_UWP_CNTRL1	, 0x002a3106 },	/* UWPCNTRL1	*/
>> +	{ STB0899_OFF0_UWP_CNTRL2	, STB0899_BASE_UWP_CNTRL2	, 0x0006140a },	/* UWPCNTRL2	*/
>> +	{ STB0899_OFF0_UWP_STAT1	, STB0899_BASE_UWP_STAT1	, 0x00008000 },	/* UWPSTAT1	*/
>> +	{ STB0899_OFF0_UWP_STAT2	, STB0899_BASE_UWP_STAT2	, 0x00000000 },	/* UWPSTAT2	*/
>> +	{ STB0899_OFF0_DMD_STAT2	, STB0899_BASE_DMD_STAT2	, 0x00000000 },	/* DMDSTAT2	*/
>> +	{ STB0899_OFF0_FREQ_ADJ_SCALE	, STB0899_BASE_FREQ_ADJ_SCALE	, 0x00000471 },	/* FREQADJSCALE */
>> +	{ STB0899_OFF0_UWP_CNTRL3	, STB0899_BASE_UWP_CNTRL3	, 0x017b0465 },	/* UWPCNTRL3	*/
>> +	{ STB0899_OFF0_SYM_CLK_SEL	, STB0899_BASE_SYM_CLK_SEL	, 0x00000002 },	/* SYMCLKSEL	*/
>> +	{ STB0899_OFF0_SOF_SRCH_TO	, STB0899_BASE_SOF_SRCH_TO	, 0x00196464 },	/* SOFSRCHTO	*/
>> +	{ STB0899_OFF0_ACQ_CNTRL1	, STB0899_BASE_ACQ_CNTRL1	, 0x00000603 },	/* ACQCNTRL1	*/
>> +	{ STB0899_OFF0_ACQ_CNTRL2	, STB0899_BASE_ACQ_CNTRL2	, 0x02046666 },	/* ACQCNTRL2	*/
>> +	{ STB0899_OFF0_ACQ_CNTRL3	, STB0899_BASE_ACQ_CNTRL3	, 0x10046583 },	/* ACQCNTRL3	*/
>> +	{ STB0899_OFF0_FE_SETTLE	, STB0899_BASE_FE_SETTLE	, 0x00010404 },	/* FESETTLE	*/
>> +	{ STB0899_OFF0_AC_DWELL		, STB0899_BASE_AC_DWELL		, 0x0002aa8a },	/* ACDWELL	*/
>> +	{ STB0899_OFF0_ACQUIRE_TRIG	, STB0899_BASE_ACQUIRE_TRIG	, 0x00000000 },	/* ACQUIRETRIG	*/
>> +	{ STB0899_OFF0_LOCK_LOST	, STB0899_BASE_LOCK_LOST	, 0x00000001 },	/* LOCKLOST	*/
>> +	{ STB0899_OFF0_ACQ_STAT1	, STB0899_BASE_ACQ_STAT1	, 0x00000500 },	/* ACQSTAT1	*/
>> +	{ STB0899_OFF0_ACQ_TIMEOUT	, STB0899_BASE_ACQ_TIMEOUT	, 0x0028a0a0 },	/* ACQTIMEOUT	*/
>> +	{ STB0899_OFF0_ACQ_TIME		, STB0899_BASE_ACQ_TIME		, 0x00000000 },	/* ACQTIME	*/
>> +	{ STB0899_OFF0_FINAL_AGC_CNTRL	, STB0899_BASE_FINAL_AGC_CNTRL	, 0x00800c17 },	/* FINALAGCCNTRL*/
>> +	{ STB0899_OFF0_FINAL_AGC_GAIN	, STB0899_BASE_FINAL_AGC_GAIN	, 0x00000000 },	/* FINALAGCCGAIN*/
>> +	{ STB0899_OFF0_EQUALIZER_INIT	, STB0899_BASE_EQUALIZER_INIT	, 0x00000000 },	/* EQUILIZERINIT*/
>> +	{ STB0899_OFF0_EQ_CNTRL		, STB0899_BASE_EQ_CNTRL		, 0x00054802 },	/* EQCNTL	*/
>> +	{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF0 */
>> +	{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF1 */
>> +	{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF2 */
>> +	{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF3 */
>> +	{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF4 */
>> +	{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 },	/* EQIINITCOEFF5 */
>> +	{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF6 */
>> +	{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF7 */
>> +	{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF8 */
>> +	{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF9 */
>> +	{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 },	/* EQIINITCOEFF10*/
>> +	{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF0 */
>> +	{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF1 */
>> +	{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF2 */
>> +	{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF3 */
>> +	{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF4 */
>> +	{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF5 */
>> +	{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF6 */
>> +	{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF7 */
>> +	{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF8 */
>> +	{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF9 */
>> +	{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 },	/* EQQINITCOEFF10*/
>> +	{ STB0899_OFF0_EQ_I_OUT_COEFF_0	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT0 */
>> +	{ STB0899_OFF1_EQ_I_OUT_COEFF_1	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT1 */
>> +	{ STB0899_OFF2_EQ_I_OUT_COEFF_2	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT2 */
>> +	{ STB0899_OFF3_EQ_I_OUT_COEFF_3	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT3 */
>> +	{ STB0899_OFF4_EQ_I_OUT_COEFF_4	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT4 */
>> +	{ STB0899_OFF5_EQ_I_OUT_COEFF_5	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT5 */
>> +	{ STB0899_OFF6_EQ_I_OUT_COEFF_6	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT6 */
>> +	{ STB0899_OFF7_EQ_I_OUT_COEFF_7	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT7 */
>> +	{ STB0899_OFF8_EQ_I_OUT_COEFF_8	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT8 */
>> +	{ STB0899_OFF9_EQ_I_OUT_COEFF_9	, STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT9 */
>> +	{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N	, 0x00000000 }, /* EQICOEFFSOUT10*/
>> +	{ STB0899_OFF0_EQ_Q_OUT_COEFF_0	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT0 */
>> +	{ STB0899_OFF1_EQ_Q_OUT_COEFF_1	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT1 */
>> +	{ STB0899_OFF2_EQ_Q_OUT_COEFF_2	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT2 */
>> +	{ STB0899_OFF3_EQ_Q_OUT_COEFF_3	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT3 */
>> +	{ STB0899_OFF4_EQ_Q_OUT_COEFF_4	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT4 */
>> +	{ STB0899_OFF5_EQ_Q_OUT_COEFF_5	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT5 */
>> +	{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT6 */
>> +	{ STB0899_OFF7_EQ_Q_OUT_COEFF_7	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT7 */
>> +	{ STB0899_OFF8_EQ_Q_OUT_COEFF_8	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT8 */
>> +	{ STB0899_OFF9_EQ_Q_OUT_COEFF_9	, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT9 */
>> +	{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N	, 0x00000000 },	/* EQQCOEFFSOUT10*/
>> +	{ 0xffff			, 0xffffffff		    , 0xffffffff },
>> +};
>> +
>> +static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
>> +	{ STB0899_DEMOD			, 0x00 },
>> +	{ STB0899_RCOMPC		, 0xc9 },
>> +	{ STB0899_AGC1CN		, 0x01 },
>> +	{ STB0899_AGC1REF		, 0x10 },
>> +	{ STB0899_RTC			, 0x23 },
>> +	{ STB0899_TMGCFG		, 0x4e },
>> +	{ STB0899_AGC2REF		, 0x34 },
>> +	{ STB0899_TLSR			, 0x84 },
>> +	{ STB0899_CFD			, 0xf7 },
>> +	{ STB0899_ACLC			, 0x87 },
>> +	{ STB0899_BCLC			, 0x94 },
>> +	{ STB0899_EQON			, 0x41 },
>> +	{ STB0899_LDT			, 0xf1 },
>> +	{ STB0899_LDT2			, 0xe3 },
>> +	{ STB0899_EQUALREF		, 0xb4 },
>> +	{ STB0899_TMGRAMP		, 0x10 },
>> +	{ STB0899_TMGTHD		, 0x30 },
>> +	{ STB0899_IDCCOMP		, 0xfd },
>> +	{ STB0899_QDCCOMP		, 0xff },
>> +	{ STB0899_POWERI		, 0x0c },
>> +	{ STB0899_POWERQ		, 0x0f },
>> +	{ STB0899_RCOMP			, 0x6c },
>> +	{ STB0899_AGCIQIN		, 0x80 },
>> +	{ STB0899_AGC2I1		, 0x06 },
>> +	{ STB0899_AGC2I2		, 0x00 },
>> +	{ STB0899_TLIR			, 0x30 },
>> +	{ STB0899_RTF			, 0x7f },
>> +	{ STB0899_DSTATUS		, 0x00 },
>> +	{ STB0899_LDI			, 0xbc },
>> +	{ STB0899_CFRM			, 0xea },
>> +	{ STB0899_CFRL			, 0x31 },
>> +	{ STB0899_NIRM			, 0x2b },
>> +	{ STB0899_NIRL			, 0x80 },
>> +	{ STB0899_ISYMB			, 0x1d },
>> +	{ STB0899_QSYMB			, 0xa6 },
>> +	{ STB0899_SFRH			, 0x2f },
>> +	{ STB0899_SFRM			, 0x68 },
>> +	{ STB0899_SFRL			, 0x40 },
>> +	{ STB0899_SFRUPH		, 0x2f },
>> +	{ STB0899_SFRUPM		, 0x68 },
>> +	{ STB0899_SFRUPL		, 0x40 },
>> +	{ STB0899_EQUAI1		, 0x02 },
>> +	{ STB0899_EQUAQ1		, 0xff },
>> +	{ STB0899_EQUAI2		, 0x04 },
>> +	{ STB0899_EQUAQ2		, 0x05 },
>> +	{ STB0899_EQUAI3		, 0x02 },
>> +	{ STB0899_EQUAQ3		, 0xfd },
>> +	{ STB0899_EQUAI4		, 0x03 },
>> +	{ STB0899_EQUAQ4		, 0x07 },
>> +	{ STB0899_EQUAI5		, 0x08 },
>> +	{ STB0899_EQUAQ5		, 0xf5 },
>> +	{ STB0899_DSTATUS2		, 0x00 },
>> +	{ STB0899_VSTATUS		, 0x00 },
>> +	{ STB0899_VERROR		, 0x86 },
>> +	{ STB0899_IQSWAP		, 0x2a },
>> +	{ STB0899_ECNT1M		, 0x00 },
>> +	{ STB0899_ECNT1L		, 0x00 },
>> +	{ STB0899_ECNT2M		, 0x00 },
>> +	{ STB0899_ECNT2L		, 0x00 },
>> +	{ STB0899_ECNT3M		, 0x0a },
>> +	{ STB0899_ECNT3L		, 0xad },
>> +	{ STB0899_FECAUTO1		, 0x06 },
>> +	{ STB0899_FECM			, 0x01 },
>> +	{ STB0899_VTH12			, 0xb0 },
>> +	{ STB0899_VTH23			, 0x7a },
>> +	{ STB0899_VTH34			, 0x58 },
>> +	{ STB0899_VTH56			, 0x38 },
>> +	{ STB0899_VTH67			, 0x34 },
>> +	{ STB0899_VTH78			, 0x24 },
>> +	{ STB0899_PRVIT			, 0xff },
>> +	{ STB0899_VITSYNC		, 0x19 },
>> +	{ STB0899_RSULC			, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
>> +	{ STB0899_TSULC			, 0x42 },
>> +	{ STB0899_RSLLC			, 0x41 },
>> +	{ STB0899_TSLPL			, 0x12 },
>> +	{ STB0899_TSCFGH		, 0x0c },
>> +	{ STB0899_TSCFGM		, 0x00 },
>> +	{ STB0899_TSCFGL		, 0x00 },
>> +	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
>> +	{ STB0899_RSSYNCDEL		, 0x00 },
>> +	{ STB0899_TSINHDELH		, 0x02 },
>> +	{ STB0899_TSINHDELM		, 0x00 },
>> +	{ STB0899_TSINHDELL		, 0x00 },
>> +	{ STB0899_TSLLSTKM		, 0x1b },
>> +	{ STB0899_TSLLSTKL		, 0xb3 },
>> +	{ STB0899_TSULSTKM		, 0x00 },
>> +	{ STB0899_TSULSTKL		, 0x00 },
>> +	{ STB0899_PCKLENUL		, 0xbc },
>> +	{ STB0899_PCKLENLL		, 0xcc },
>> +	{ STB0899_RSPCKLEN		, 0xbd },
>> +	{ STB0899_TSSTATUS		, 0x90 },
>> +	{ STB0899_ERRCTRL1		, 0xb6 },
>> +	{ STB0899_ERRCTRL2      	, 0x95 },
>> +	{ STB0899_ERRCTRL3      	, 0x8d },
>> +	{ STB0899_DMONMSK1		, 0x27 },
>> +	{ STB0899_DMONMSK0		, 0x03 },
>> +	{ STB0899_DEMAPVIT		, 0x5c },
>> +	{ STB0899_PLPARM		, 0x19 },
>> +	{ STB0899_PDELCTRL		, 0x48 },
>> +	{ STB0899_PDELCTRL2		, 0x00 },
>> +	{ STB0899_BBHCTRL1		, 0x00 },
>> +	{ STB0899_BBHCTRL2		, 0x00 },
>> +	{ STB0899_HYSTTHRESH		, 0x77 },
>> +	{ STB0899_MATCSTM		, 0x00 },
>> +	{ STB0899_MATCSTL		, 0x00 },
>> +	{ STB0899_UPLCSTM		, 0x00 },
>> +	{ STB0899_UPLCSTL		, 0x00 },
>> +	{ STB0899_DFLCSTM		, 0x00 },
>> +	{ STB0899_DFLCSTL		, 0x00 },
>> +	{ STB0899_SYNCCST		, 0x00 },
>> +	{ STB0899_SYNCDCSTM		, 0x00 },
>> +	{ STB0899_SYNCDCSTL		, 0x00 },
>> +	{ STB0899_ISI_ENTRY		, 0x00 },
>> +	{ STB0899_ISI_BIT_EN		, 0x00 },
>> +	{ STB0899_MATSTRM		, 0xf0 },
>> +	{ STB0899_MATSTRL		, 0x02 },
>> +	{ STB0899_UPLSTRM		, 0x45 },
>> +	{ STB0899_UPLSTRL		, 0x60 },
>> +	{ STB0899_DFLSTRM		, 0xe3 },
>> +	{ STB0899_DFLSTRL		, 0x00 },
>> +	{ STB0899_SYNCSTR		, 0x47 },
>> +	{ STB0899_SYNCDSTRM		, 0x05 },
>> +	{ STB0899_SYNCDSTRL		, 0x18 },
>> +	{ STB0899_CFGPDELSTATUS1	, 0x19 },
>> +	{ STB0899_CFGPDELSTATUS2	, 0x2b },
>> +	{ STB0899_BBFERRORM		, 0x00 },
>> +	{ STB0899_BBFERRORL		, 0x01 },
>> +	{ STB0899_UPKTERRORM		, 0x00 },
>> +	{ STB0899_UPKTERRORL		, 0x00 },
>> +	{ 0xffff			, 0xff },
>> +};
>> +
>> +
>> +static const struct stb0899_s2_reg pctv452e_init_s2_fec[] = {
>> +	{ STB0899_OFF0_BLOCK_LNGTH	, STB0899_BASE_BLOCK_LNGTH	, 0x00000008 },	/* BLOCKLNGTH	*/
>> +	{ STB0899_OFF0_ROW_STR		, STB0899_BASE_ROW_STR		, 0x000000b4 },	/* ROWSTR	*/
>> +	{ STB0899_OFF0_BN_END_ADDR	, STB0899_BASE_BN_END_ADDR	, 0x000004b5 },	/* BNANDADDR	*/
>> +	{ STB0899_OFF0_CN_END_ADDR	, STB0899_BASE_CN_END_ADDR	, 0x00000b4b },	/* CNANDADDR	*/
>> +	{ STB0899_OFF0_INFO_LENGTH	, STB0899_BASE_INFO_LENGTH	, 0x00000078 },	/* INFOLENGTH	*/
>> +	{ STB0899_OFF0_BOT_ADDR		, STB0899_BASE_BOT_ADDR		, 0x000001e0 },	/* BOT_ADDR	*/
>> +	{ STB0899_OFF0_BCH_BLK_LN	, STB0899_BASE_BCH_BLK_LN	, 0x0000a8c0 },	/* BCHBLKLN	*/
>> +	{ STB0899_OFF0_BCH_T		, STB0899_BASE_BCH_T		, 0x0000000c },	/* BCHT		*/
>> +	{ STB0899_OFF0_CNFG_MODE	, STB0899_BASE_CNFG_MODE	, 0x00000001 },	/* CNFGMODE	*/
>> +	{ STB0899_OFF0_LDPC_STAT	, STB0899_BASE_LDPC_STAT	, 0x0000000d },	/* LDPCSTAT	*/
>> +	{ STB0899_OFF0_ITER_SCALE	, STB0899_BASE_ITER_SCALE	, 0x00000040 },	/* ITERSCALE	*/
>> +	{ STB0899_OFF0_INPUT_MODE	, STB0899_BASE_INPUT_MODE	, 0x00000000 },	/* INPUTMODE	*/
>> +	{ STB0899_OFF0_LDPCDECRST	, STB0899_BASE_LDPCDECRST	, 0x00000000 },	/* LDPCDECRST	*/
>> +	{ STB0899_OFF0_CLK_PER_BYTE_RW	, STB0899_BASE_CLK_PER_BYTE_RW	, 0x00000008 },	/* CLKPERBYTE	*/
>> +	{ STB0899_OFF0_BCH_ERRORS	, STB0899_BASE_BCH_ERRORS	, 0x00000000 },	/* BCHERRORS	*/
>> +	{ STB0899_OFF0_LDPC_ERRORS	, STB0899_BASE_LDPC_ERRORS	, 0x00000000 },	/* LDPCERRORS	*/
>> +	{ STB0899_OFF0_BCH_MODE		, STB0899_BASE_BCH_MODE		, 0x00000000 },	/* BCHMODE	*/
>> +	{ STB0899_OFF0_ERR_ACC_PER	, STB0899_BASE_ERR_ACC_PER	, 0x00000008 },	/* ERRACCPER	*/
>> +	{ STB0899_OFF0_BCH_ERR_ACC	, STB0899_BASE_BCH_ERR_ACC	, 0x00000000 },	/* BCHERRACC	*/
>> +	{ STB0899_OFF0_FEC_TP_SEL	, STB0899_BASE_FEC_TP_SEL	, 0x00000000 },	/* FECTPSEL	*/
>> +	{ 0xffff			, 0xffffffff			, 0xffffffff },
>> +};
>> +
>> +static const struct stb0899_s1_reg pctv452e_init_tst[] = {
>> +	{ STB0899_TSTCK		, 0x00 },
>> +	{ STB0899_TSTRES	, 0x00 },
>> +	{ STB0899_TSTOUT	, 0x00 },
>> +	{ STB0899_TSTIN		, 0x00 },
>> +	{ STB0899_TSTSYS	, 0x00 },
>> +	{ STB0899_TSTCHIP	, 0x00 },
>> +	{ STB0899_TSTFREE	, 0x00 },
>> +	{ STB0899_TSTI2C	, 0x00 },
>> +	{ STB0899_BITSPEEDM	, 0x00 },
>> +	{ STB0899_BITSPEEDL	, 0x00 },
>> +	{ STB0899_TBUSBIT	, 0x00 },
>> +	{ STB0899_TSTDIS	, 0x00 },
>> +	{ STB0899_TSTDISRX	, 0x00 },
>> +	{ STB0899_TSTJETON	, 0x00 },
>> +	{ STB0899_TSTDCADJ	, 0x00 },
>> +	{ STB0899_TSTAGC1	, 0x00 },
>> +	{ STB0899_TSTAGC1N	, 0x00 },
>> +	{ STB0899_TSTPOLYPH	, 0x00 },
>> +	{ STB0899_TSTR		, 0x00 },
>> +	{ STB0899_TSTAGC2	, 0x00 },
>> +	{ STB0899_TSTCTL1	, 0x00 },
>> +	{ STB0899_TSTCTL2	, 0x00 },
>> +	{ STB0899_TSTCTL3	, 0x00 },
>> +	{ STB0899_TSTDEMAP	, 0x00 },
>> +	{ STB0899_TSTDEMAP2	, 0x00 },
>> +	{ STB0899_TSTDEMMON	, 0x00 },
>> +	{ STB0899_TSTRATE	, 0x00 },
>> +	{ STB0899_TSTSELOUT	, 0x00 },
>> +	{ STB0899_TSYNC		, 0x00 },
>> +	{ STB0899_TSTERR	, 0x00 },
>> +	{ STB0899_TSTRAM1	, 0x00 },
>> +	{ STB0899_TSTVSELOUT	, 0x00 },
>> +	{ STB0899_TSTFORCEIN	, 0x00 },
>> +	{ STB0899_TSTRS1	, 0x00 },
>> +	{ STB0899_TSTRS2	, 0x00 },
>> +	{ STB0899_TSTRS3	, 0x00 },
>> +	{ STB0899_GHOSTREG	, 0x81 },
>> +	{ 0xffff		, 0xff },
>> +};
>> +
>> +
>> +#define PCTV452E_DVBS2_ESNO_AVE			3
>> +#define PCTV452E_DVBS2_ESNO_QUANT		32
>> +#define PCTV452E_DVBS2_AVFRAMES_COARSE		10
>> +#define PCTV452E_DVBS2_AVFRAMES_FINE		20
>> +#define PCTV452E_DVBS2_MISS_THRESHOLD		6
>> +#define PCTV452E_DVBS2_UWP_THRESHOLD_ACQ	1125
>> +#define PCTV452E_DVBS2_UWP_THRESHOLD_TRACK	758
>> +#define PCTV452E_DVBS2_UWP_THRESHOLD_SOF	1350
>> +#define PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT	1664100
>> +
>> +#define PCTV452E_DVBS2_BTR_NCO_BITS		28
>> +#define PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET	15
>> +#define PCTV452E_DVBS2_CRL_NCO_BITS		30
>> +#define PCTV452E_DVBS2_LDPC_MAX_ITER		70
>> +
>> +
>> +static struct stb0899_config stb0899_config = {
>> +	.init_dev	= pctv452e_init_dev,
>> +	.init_s2_demod   = pctv452e_init_s2_demod,
>> +	.init_s1_demod   = pctv452e_init_s1_demod,
>> +	.init_s2_fec     = pctv452e_init_s2_fec,
>> +	.init_tst	= pctv452e_init_tst,
>> +
>> +	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
>> +	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
>> +
>> +	.xtal_freq       = 27000000,	 /* Assume Hz ? */
>> +	.inversion       = IQ_SWAP_ON,       /* ? */
>> +
>> +	.lo_clk	  = 76500000,
>> +	.hi_clk	  = 99000000,
>> +
>> +	.ts_output_mode  = 0,		/* Use parallel mode */
>> +	.clock_polarity  = 0,		/*  */
>> +	.data_clk_parity = 0,		/*  */
>> +	.fec_mode	= 0,		/*  */
>> +
>> +	.esno_ave	    = PCTV452E_DVBS2_ESNO_AVE,
>> +	.esno_quant	  = PCTV452E_DVBS2_ESNO_QUANT,
>> +	.avframes_coarse     = PCTV452E_DVBS2_AVFRAMES_COARSE,
>> +	.avframes_fine       = PCTV452E_DVBS2_AVFRAMES_FINE,
>> +	.miss_threshold      = PCTV452E_DVBS2_MISS_THRESHOLD,
>> +	.uwp_threshold_acq   = PCTV452E_DVBS2_UWP_THRESHOLD_ACQ,
>> +	.uwp_threshold_track = PCTV452E_DVBS2_UWP_THRESHOLD_TRACK,
>> +	.uwp_threshold_sof   = PCTV452E_DVBS2_UWP_THRESHOLD_SOF,
>> +	.sof_search_timeout  = PCTV452E_DVBS2_SOF_SEARCH_TIMEOUT,
>> +
>> +	.btr_nco_bits	  = PCTV452E_DVBS2_BTR_NCO_BITS,
>> +	.btr_gain_shift_offset = PCTV452E_DVBS2_BTR_GAIN_SHIFT_OFFSET,
>> +	.crl_nco_bits	  = PCTV452E_DVBS2_CRL_NCO_BITS,
>> +	.ldpc_max_iter	 = PCTV452E_DVBS2_LDPC_MAX_ITER,
>> +
>> +	.tuner_get_frequency	= stb6100_get_frequency,
>> +	.tuner_set_frequency	= stb6100_set_frequency,
>> +	.tuner_set_bandwidth	= stb6100_set_bandwidth,
>> +	.tuner_get_bandwidth	= stb6100_get_bandwidth,
>> +	.tuner_set_rfsiggain	= NULL,
>> +
>> +	/* helper for switching LED green/orange */
>> +	.postproc = pctv45e_postproc
>> +};
>> +
>> +static struct stb6100_config stb6100_config = {
>> +	.tuner_address = I2C_ADDR_STB6100,
>> +	.refclock      = 27000000
>> +};
>> +
>> +
>> +static struct i2c_algorithm pctv452e_i2c_algo = {
>> +	.master_xfer   = pctv452e_i2c_xfer,
>> +	.functionality = pctv452e_i2c_func
>> +};
>> +
>> +
>> +static struct usb_device_id pctv452e_usb_table[] = {
>> +	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
>> +	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
>> +	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
>> +
>> +static struct dvb_usb_device_properties pctv452e_properties = {
>> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
>> +	.usb_ctrl = DEVICE_SPECIFIC,
>> +
>> +	.size_of_priv     = sizeof(struct pctv452e_state),
>> +
>> +	.identify_state   = 0, // this is a warm only device
>> +
>> +	.power_ctrl       = pctv452e_power_ctrl,
>> +	/* Untested. */
>> +	/* .read_mac_address = pctv452e_read_mac_address, */
>> +
>> +	.rc.legacy = {
>> +		.rc_map_table     = pctv452e_rc_keys,
>> +		.rc_map_size      = ARRAY_SIZE(pctv452e_rc_keys),
>> +		.rc_query         = pctv452e_rc_query,
>> +		.rc_interval      = 100,
>> +	},
>> +
>> +	.num_adapters     = 1,
>> +	.adapter = {{
>> +		.caps	     = 0,
>> +		.pid_filter_count = 0,
>> +
>> +		.streaming_ctrl   = NULL,
>> +
>> +		.frontend_attach  = pctv452e_frontend_attach,
>> +		.tuner_attach     = pctv452e_tuner_attach,
>> +
>> +		/* parameter for the MPEG2-data transfer */
>> +		.stream = {
>> +			.type     = USB_ISOC,
>> +			.count    = ISO_BUF_COUNT,
>> +			.endpoint = 0x02,
>> +			.u = {
>> +				.isoc = {
>> +					.framesperurb = FRAMES_PER_ISO_BUF,
>> +					.framesize    = ISO_FRAME_SIZE,
>> +					.interval     = 1
>> +				}
>> +			}
>> +		},
>> +		.size_of_priv     = 0
>> +	}},
>> +
>> +	.i2c_algo =&pctv452e_i2c_algo,
>> +
>> +	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
>> +
>> +	.num_device_descs = 1,
>> +	.devices = {
>> +		{ .name = "PCTV HDTV USB",
>> +		  .cold_ids = { NULL, NULL }, // this is a warm only device
>> +		  .warm_ids = {&pctv452e_usb_table[0], NULL }
>> +		},
>> +		{ 0 },
>> +	}
>> +};
>> +
>> +static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
>> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
>> +	.usb_ctrl = DEVICE_SPECIFIC,
>> +
>> +	.size_of_priv		= sizeof(struct pctv452e_state),
>> +
>> +	.identify_state		= 0, // this is a warm only device
>> +
>> +	.power_ctrl		= pctv452e_power_ctrl,
>> +	.read_mac_address	= pctv452e_read_mac_address,
>> +
>> +	.rc.legacy = {
>> +		.rc_map_table   = tt_connect_s2_3600_rc_key,
>> +		.rc_map_size    = ARRAY_SIZE(tt_connect_s2_3600_rc_key),
>> +		.rc_query       = pctv452e_rc_query,
>> +		.rc_interval    = 500,
>> +	},
> Please port it to the non-legacy RC support. The legacy one is there only because
> I didn't have all DVB hardware here to remove support for them. Newer drivers shouldn't
> use it.
>
>> +
>> +	.num_adapters		= 1,
>> +	.adapter = {{
>> +		.caps = 0,
>> +		.pid_filter_count = 0,
>> +
>> +		.streaming_ctrl = NULL,
>> +
>> +		.frontend_attach = pctv452e_frontend_attach,
>> +		.tuner_attach = pctv452e_tuner_attach,
>> +
>> +		/* parameter for the MPEG2-data transfer */
>> +		.stream = {
>> +			.type = USB_ISOC,
>> +			.count = 7,
>> +			.endpoint = 0x02,
>> +			.u = {
>> +				.isoc = {
>> +					.framesperurb = 4,
>> +					.framesize = 940,
>> +					.interval = 1
>> +				}
>> +			}
>> +		},
>> +		.size_of_priv = 0
>> +	}},
>> +
>> +	.i2c_algo =&pctv452e_i2c_algo,
>> +
>> +	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
>> +
>> +	.num_device_descs = 2,
>> +	.devices = {
>> +		{ .name = "Technotrend TT Connect S2-3600",
>> +		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
>> +		  .warm_ids = {&pctv452e_usb_table[1], NULL }
>> +		},
>> +		{ .name = "Technotrend TT Connect S2-3650-CI",
>> +		  .cold_ids = { NULL, NULL },
>> +		  .warm_ids = {&pctv452e_usb_table[2], NULL }
>> +		},
>> +		{ 0 },
>> +	}
>> +};
>> +
>> +
>> +
>> +static struct usb_driver pctv452e_usb_driver = {
>> +#if LINUX_VERSION_CODE<=  KERNEL_VERSION(2,6,15)
>> +	.owner      = THIS_MODULE,
>> +#endif
>> +	.name       = "pctv452e",
>> +	.probe      = pctv452e_usb_probe,
>> +	.disconnect = pctv452e_usb_disconnect,
>> +	.id_table   = pctv452e_usb_table,
>> +};
>> +
>> +static struct usb_driver tt_connects2_3600_usb_driver = {
>> +#if LINUX_VERSION_CODE<=  KERNEL_VERSION(2,6,15)
>> +	.owner      = THIS_MODULE,
>> +#endif
> Those ifdefs should be removed when submitting a driver upstream.
>
>> +	.name       = "dvb-usb-tt-connect-s2-3600-01.fw",
>> +	.probe      = pctv452e_usb_probe,
>> +	.disconnect = pctv452e_usb_disconnect,
>> +	.id_table   = pctv452e_usb_table,
>> +};
>> +
>> +static int __init pctv452e_usb_init(void) {
>> +	int err=0;
>> +
>> +	if ((err = usb_register(&pctv452e_usb_driver))) {
>> +		printk("%s: usb_register failed! Error number %d", __FILE__, err);
>> +		return err;
>> +	}
>> +	if ((err = usb_register(&tt_connects2_3600_usb_driver))) {
>> +		printk("%s: usb_register failed! Error number %d", __FILE__, err);
>> +	}
>> +
>> +	return err;
>> +}
>> +
>> +static void __exit pctv452e_usb_exit(void)  {
>> +	usb_deregister(&pctv452e_usb_driver);
>> +	usb_deregister(&tt_connects2_3600_usb_driver);
>> +}
>> +
>> +module_init(pctv452e_usb_init);
>> +module_exit(pctv452e_usb_exit);
>> +
>> +MODULE_AUTHOR("Dominik Kuhlen<dkuhlen@gmx.net>");
>> +MODULE_AUTHOR("Andre Weidemann<Andre.Weidemann@web.de>");
>> +MODULE_AUTHOR("Michael H. Schimek<mschimek@gmx.at>");
>> +MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
>> index 3b0c4bd..8e6f588 100644
>> --- a/drivers/media/dvb/frontends/Makefile
>> +++ b/drivers/media/dvb/frontends/Makefile
>> @@ -49,6 +49,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
>>   obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
>>   obj-$(CONFIG_DVB_CX24123) += cx24123.o
>>   obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
>> +obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
>>   obj-$(CONFIG_DVB_ISL6405) += isl6405.o
>>   obj-$(CONFIG_DVB_ISL6421) += isl6421.o
>>   obj-$(CONFIG_DVB_TDA10086) += tda10086.o
>> diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
>> new file mode 100644
>> index 0000000..48377b2
>> --- /dev/null
>> +++ b/drivers/media/dvb/frontends/lnbp22.c
>> @@ -0,0 +1,140 @@
>> +/*
>> + * lnbp22.h - driver for lnb supply and control ic lnbp22
>> + *
>> + * Copyright (C) 2006 Dominik Kuhlen
>> + * Based on lnbp21 driver
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version 2
>> + * of the License, or (at your option) any later version.
>> + *
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>> + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
>> + *
>> + *
>> + * the project's page is at http://www.linuxtv.org
>> + */
>> +#include<linux/delay.h>
>> +#include<linux/errno.h>
>> +#include<linux/init.h>
>> +#include<linux/kernel.h>
>> +#include<linux/module.h>
>> +#include<linux/moduleparam.h>
>> +#include<linux/string.h>
>> +#include<linux/slab.h>
>> +
>> +#include "dvb_frontend.h"
>> +#include "lnbp22.h"
>> +
>> +static int debug = 0;
>> +module_param(debug, int, 0644);
>> +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
>> +
>> +
>> +#define dprintk(lvl, arg...) if (debug>= (lvl)) printk(arg)
>> +
>> +struct lnbp22 {
>> +	u8                 config[4];
>> +	struct i2c_adapter *i2c;
>> +};
>> +
>> +static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) {
>> +	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
>> +	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
>> +				.buf = (char*)&lnbp22->config,
>> +				.len = sizeof(lnbp22->config) };
>> +
>> +	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __FUNCTION__, voltage,
>> +	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
>> +
>> +	lnbp22->config[3] = 0x60; // Power down
>> +	switch(voltage) {
>> +	case SEC_VOLTAGE_OFF:
>> +		break;
>> +	case SEC_VOLTAGE_13:
>> +		lnbp22->config[3] |= LNBP22_EN;
>> +		break;
>> +	case SEC_VOLTAGE_18:
>> +		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	};
>> +
>> +	dprintk(1, "%s: 0x%02x)\n", __FUNCTION__, lnbp22->config[3]);
>> +	return (i2c_transfer(lnbp22->i2c,&msg, 1) == 1) ? 0 : -EIO;
>> +}
>> +
>> +static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) {
>> +	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
>> +	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
>> +				.buf = (char*)&lnbp22->config,
>> +				.len = sizeof(lnbp22->config) };
>> +
>> +	dprintk(1, "%s: %d\n", __FUNCTION__, (int)arg);
>> +	if (arg)
>> +		lnbp22->config[3] |= LNBP22_LLC;
>> +	else
>> +		lnbp22->config[3]&= ~LNBP22_LLC;
>> +
>> +	return (i2c_transfer(lnbp22->i2c,&msg, 1) == 1) ? 0 : -EIO;
>> +}
>> +
>> +static void lnbp22_release(struct dvb_frontend *fe)
>> +{
>> +
>> +	dprintk(1, "%s\n", __FUNCTION__);
>> +	/* LNBP power off */
>> +	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
>> +
>> +	/* free data */
>> +	kfree(fe->sec_priv);
>> +	fe->sec_priv = NULL;
>> +}
>> +
>> +struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
>> +{
>> +	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
>> +	if (!lnbp22)
>> +		return NULL;
>> +
>> +	/* default configuration */
>> +	lnbp22->config[0] = 0x00; /* ? */
>> +	lnbp22->config[1] = 0x28; /* ? */
>> +	lnbp22->config[2] = 0x48; /* ? */
>> +	lnbp22->config[3] = 0x60; /* Power down */
>> +	lnbp22->i2c = i2c;
>> +	fe->sec_priv = lnbp22;
>> +
>> +	/* detect if it is present or not */
>> +	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
>> +		dprintk(0, "%s LNBP22 not found\n", __FUNCTION__);
>> +		kfree(lnbp22);
>> +		fe->sec_priv = NULL;
>> +		return NULL;
>> +	}
>> +
>> +	/* install release callback */
>> +	fe->ops.release_sec = lnbp22_release;
>> +
>> +	/* override frontend ops */
>> +	fe->ops.set_voltage = lnbp22_set_voltage;
>> +	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
>> +
>> +	return fe;
>> +}
>> +EXPORT_SYMBOL(lnbp22_attach);
>> +
>> +MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
>> +MODULE_AUTHOR("Dominik Kuhlen");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
>> new file mode 100644
>> index 0000000..4149c62
>> --- /dev/null
>> +++ b/drivers/media/dvb/frontends/lnbp22.h
>> @@ -0,0 +1,51 @@
>> +/*
>> + * lnbp22.h - driver for lnb supply and control ic lnbp22
>> + *
>> + * Copyright (C) 2006 Dominik Kuhlen
>> + * Based on lnbp21.h
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version 2
>> + * of the License, or (at your option) any later version.
>> + *
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>> + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
>> + *
>> + *
>> + * the project's page is at http://www.linuxtv.org
>> + */
>> +
>> +#ifndef _LNBP22_H
>> +#define _LNBP22_H
>> +
>> +// Enable
>> +#define LNBP22_EN	  0x10
>> +// Voltage selection
>> +#define LNBP22_VSEL	0x02
>> +// Plus 1 Volt Bit
>> +#define LNBP22_LLC	0x01
>> +
>> +#include<linux/dvb/frontend.h>
>> +
>> +#if defined(CONFIG_DVB_LNBP22) || (defined(CONFIG_DVB_LNBP22_MODULE)&&  defined(MODULE))
>> +/* override_set and override_clear control which system register bits (above) to always set&  clear */
>> +extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c);
>> +#else
>> +static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c)
>> +{
>> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
>> +	return NULL;
>> +}
>> +#endif // CONFIG_DVB_LNBP22
>> +
>> +#endif // _LNBP22_H
>> diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
>> index 7dd54b3..0f54d4f 100644
>> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
>> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
>> @@ -85,6 +85,31 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
>>   	return 0;
>>   }
>>
>> +int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC)
>> +{
>> +	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
>> +		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
>> +		       0x1d, 0x36, 0x64, 0x78};
>> +	u8 data[20];
>> +	int i;
>> +
>> +	/* In case there is a sig check failure have the orig contents available */
>> +	memcpy(data, encodedMAC, 20);
>> +
>> +	for (i = 0; i<  20; i++)
>> +		data[i] ^= xor[i];
>> +	for (i = 0; i<  10; i++)
>> +		data[i] = ((data[2 * i + 1]<<  8) | data[2 * i])
>> +			>>  ((data[2 * i + 1]>>  6)&  3);
>> +
>> +	if (check_mac_tt(data))
>> +		return -ENODEV;
>> +
>> +	decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0];
>> +	decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4];
>> +	return 0;
>> +}
>> +
>>   static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
>>   {
>>   	int ret;
>> diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h
>> index e2dc6cf..fea8bfc 100644
>> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
>> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h
>> @@ -28,6 +28,7 @@
>>   #include<linux/types.h>
>>   #include<linux/i2c.h>
>>
>> +extern int ttpci_eeprom_decode_mac(u8 * decodedMAC, u8 * encodedMAC);
>>   extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
>>
>>   #endif
>> --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c      2011-07-23 11:00:49.000000000 +0000
>> +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c      2011-07-23 11:04:00.000000000 +0000
>> @@ -165,6 +165,7 @@ int ttpci_eeprom_parse_mac(struct i2c_ad
>>   }
>>
>>   EXPORT_SYMBOL(ttpci_eeprom_parse_mac);
>> +EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
>>
>>   MODULE_LICENSE("GPL");
>>   MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
>> diff -Naur original-new-stb0899/linux/drivers/media/dvb/frontends/Kconfig 1/linux/drivers/media/dvb/frontends/Kconfig
>> --- a/drivers/media/dvb/frontends/Kconfig	2007-10-22 01:40:25.000000000 +0100
>> +++ b/drivers/media/dvb/frontends/Kconfig	2007-10-23 19:47:41.000000000 +0100
>> @@ -358,6 +358,12 @@
>>   	help
>>   	  An SEC control chip.
>>
>> +config DVB_LNBP22
>> +	tristate "LNBP22 SEC controller"
>> +	depends on DVB_CORE&&  I2C
>> +	help
>> +	  An SEC control chip.
>> +
>>   config DVB_ISL6421
>>   	tristate "ISL6421 SEC controller"
>>   	depends on DVB_CORE&&  I2C
>> -- 
>> 1.7.1.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-23 20:58       ` Oliver Freyermuth
@ 2011-09-23 21:11         ` Igor M. Liplianin
  2011-09-23 21:38           ` Igor M. Liplianin
  0 siblings, 1 reply; 18+ messages in thread
From: Igor M. Liplianin @ 2011-09-23 21:11 UTC (permalink / raw)
  To: Oliver Freyermuth
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Doychin Dokov,
	Steffen Barszus, Dominik Kuhlen, Andre Weidemann,
	Michael H. Schimek

В сообщении от 23 сентября 2011 23:58:15 автор Oliver Freyermuth написал:
> Thanks for the review!
> 
> As this is the first time I touched module- / kernel-code and I am not
> really familiar with the structures of the rc-system, I do not really
> feel up to porting to non-legacy rc-support (Igors version also appears
> to use rc-legacy), and up to now, it was only combining patches and
> fixing small glitches for me.
> However, feel free to use me as a tester (I have the hardware available,
> after all) or flood me with links to guidelines or further instructions.
> 
> Thanks again,
>      Oliver Freyermuth
>

Note, this patch is good for testing with media_build system. Just in case 
someone want not to load ~500 Mb kernel git tree, then configure, compile, 
install vmlinuz and so on, so on.

-- 
Igor M. Liplianin
Microsoft Windows Free Zone - Linux used for all Computing Tasks

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-23 21:11         ` Igor M. Liplianin
@ 2011-09-23 21:38           ` Igor M. Liplianin
  0 siblings, 0 replies; 18+ messages in thread
From: Igor M. Liplianin @ 2011-09-23 21:38 UTC (permalink / raw)
  To: Oliver Freyermuth
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Doychin Dokov,
	Steffen Barszus, Dominik Kuhlen, Andre Weidemann,
	Michael H. Schimek

[-- Attachment #1: Type: Text/Plain, Size: 1138 bytes --]

В сообщении от 24 сентября 2011 00:11:21 автор Igor M. Liplianin написал:
> В сообщении от 23 сентября 2011 23:58:15 автор Oliver Freyermuth написал:
> > Thanks for the review!
> > 
> > As this is the first time I touched module- / kernel-code and I am not
> > really familiar with the structures of the rc-system, I do not really
> > feel up to porting to non-legacy rc-support (Igors version also appears
> > to use rc-legacy), and up to now, it was only combining patches and
> > fixing small glitches for me.
> > However, feel free to use me as a tester (I have the hardware available,
> > after all) or flood me with links to guidelines or further instructions.
> > 
> > Thanks again,
> > 
> >      Oliver Freyermuth
> 
> Note, this patch is good for testing with media_build system. Just in case
> someone want not to load ~500 Mb kernel git tree, then configure, compile,
> install vmlinuz and so on, so on.
Sorry, wrong patch, forget to amend. This patch.
-- 
Igor M. Liplianin
Microsoft Windows Free Zone - Linux used for all Computing Tasks

[-- Attachment #2: 0001-Add-support-for-pctv452e.patch --]
[-- Type: text/x-patch, Size: 39710 bytes --]

>From ae2acc4401230c17b68f74f806501de5d710a386 Mon Sep 17 00:00:00 2001
From: Igor M. Liplianin <liplianin@me.by>
Date: Sat, 24 Sep 2011 00:33:50 +0300
Subject: [PATCH] Add support for pctv452e
To: <mchehab@infradead.org>, <linux-media@vger.kernel.org>

Signed-off-by: Igor M. Liplianin <liplianin@me.by>
---
 drivers/media/dvb/dvb-usb/Kconfig       |   13 +
 drivers/media/dvb/dvb-usb/Makefile      |    4 +
 drivers/media/dvb/dvb-usb/dvb-usb-ids.h |    3 +
 drivers/media/dvb/dvb-usb/pctv452e.c    | 1093 +++++++++++++++++++++++++++++++
 drivers/media/dvb/frontends/Kconfig     |   10 +
 drivers/media/dvb/frontends/Makefile    |    1 +
 drivers/media/dvb/frontends/lnbp22.c    |  148 +++++
 drivers/media/dvb/frontends/lnbp22.h    |   57 ++
 drivers/media/dvb/ttpci/ttpci-eeprom.c  |   29 +
 drivers/media/dvb/ttpci/ttpci-eeprom.h  |    1 +
 10 files changed, 1359 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/dvb/dvb-usb/pctv452e.c
 create mode 100644 drivers/media/dvb/frontends/lnbp22.c
 create mode 100644 drivers/media/dvb/frontends/lnbp22.h

diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 2c773827..5825716 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -258,6 +258,19 @@ config DVB_USB_AF9005_REMOTE
 	  Say Y here to support the default remote control decoding for the
 	  Afatech AF9005 based receiver.
 
+config DVB_USB_PCTV452E
+	tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
+	depends on DVB_USB
+	select TTPCI_EEPROM
+	select DVB_LNBP22 if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	help
+	  Support for external USB adapter designed by Pinnacle,
+	  shipped under the brand name 'PCTV HDTV Pro USB'.
+	  Also supports TT Connect S2-3600/3650 cards.
+	  Say Y if you own such a device and want to use it.
+
 config DVB_USB_DW2102
 	tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
 	depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 06f75f6..7d0710b 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -64,6 +64,9 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
 dvb-usb-anysee-objs = anysee.o
 obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
 
+dvb-usb-pctv452e-objs = pctv452e.o
+obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
+
 dvb-usb-dw2102-objs = dw2102.o
 obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
 
@@ -104,4 +107,5 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
 ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 ccflags-y += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 7433261..2ad33ba 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -241,6 +241,9 @@
 #define USB_PID_PCTV_200E				0x020e
 #define USB_PID_PCTV_400E				0x020f
 #define USB_PID_PCTV_450E				0x0222
+#define USB_PID_PCTV_452E				0x021f
+#define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
+#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
 #define USB_PID_NEBULA_DIGITV				0x0201
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
new file mode 100644
index 0000000..9a5c811
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/pctv452e.c
@@ -0,0 +1,1093 @@
+/*
+ * PCTV 452e DVB driver
+ *
+ * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
+ *
+ * TT connect S2-3650-CI Common Interface support, MAC readout
+ * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
+ *
+ * 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.
+ */
+
+/* dvb usb framework */
+#define DVB_USB_LOG_PREFIX "pctv452e"
+#include "dvb-usb.h"
+
+/* Demodulator */
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+/* Tuner */
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+/* FE Power */
+#include "lnbp22.h"
+
+#include "dvb_ca_en50221.h"
+#include "ttpci-eeprom.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define ISOC_INTERFACE_ALTERNATIVE 3
+
+#define SYNC_BYTE_OUT 0xaa
+#define SYNC_BYTE_IN  0x55
+
+/* guessed: (copied from ttusb-budget) */
+#define PCTV_CMD_RESET 0x15
+/* command to poll IR receiver */
+#define PCTV_CMD_IR    0x1b
+/* command to send I2C  */
+#define PCTV_CMD_I2C   0x31
+
+#define I2C_ADDR_STB0899 (0xd0 >> 1)
+#define I2C_ADDR_STB6100 (0xc0 >> 1)
+#define I2C_ADDR_LNBP22  (0x10 >> 1)
+#define I2C_ADDR_24C16   (0xa0 >> 1)
+#define I2C_ADDR_24C64   (0xa2 >> 1)
+
+
+/* pctv452e sends us this amount of data for each issued usb-command */
+#define PCTV_ANSWER_LEN 64
+/* Wait up to 1000ms for device  */
+#define PCTV_TIMEOUT 1000
+
+
+#define PCTV_LED_GPIO   STB0899_GPIO01
+#define PCTV_LED_GREEN  0x82
+#define PCTV_LED_ORANGE 0x02
+
+#define ci_dbg(format, arg...)				\
+do {							\
+	if (0)						\
+		printk(KERN_DEBUG DVB_USB_LOG_PREFIX	\
+			": " format "\n" , ## arg);	\
+} while (0)
+
+enum {
+	TT3650_CMD_CI_TEST = 0x40,
+	TT3650_CMD_CI_RD_CTRL,
+	TT3650_CMD_CI_WR_CTRL,
+	TT3650_CMD_CI_RD_ATTR,
+	TT3650_CMD_CI_WR_ATTR,
+	TT3650_CMD_CI_RESET,
+	TT3650_CMD_CI_SET_VIDEO_PORT
+};
+
+
+static struct stb0899_postproc pctv45e_postproc[] = {
+	{ PCTV_LED_GPIO, STB0899_GPIOPULLUP },
+	{ 0, 0 }
+};
+
+/*
+ * stores all private variables for communication with the PCTV452e DVB-S2
+ */
+struct pctv452e_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+
+	u8 c;	   /* transaction counter, wraps around...  */
+	u8 initialized; /* set to 1 if 0x15 has been sent */
+	u16 last_rc_key;
+};
+
+static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
+			 unsigned int write_len, unsigned int read_len)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[64];
+	u8 id;
+	unsigned int rlen;
+	int ret;
+
+	BUG_ON(NULL == data && 0 != (write_len | read_len));
+	BUG_ON(write_len > 64 - 4);
+	BUG_ON(read_len > 64 - 4);
+
+	id = state->c++;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = cmd;
+	buf[3] = write_len;
+
+	memcpy(buf + 4, data, write_len);
+
+	rlen = (read_len > 0) ? 64 : 0;
+	ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
+				  buf, rlen, /* delay_ms */ 0);
+	if (0 != ret)
+		goto failed;
+
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	memcpy(data, buf + 4, read_len);
+
+	return 0;
+
+failed:
+	err("CI error %d; %02X %02X %02X -> %02X %02X %02X.",
+	     ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]);
+
+	return ret;
+}
+
+static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
+				u8 cmd, u8 *data, unsigned int write_len,
+				unsigned int read_len)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	mutex_lock(&state->ca_mutex);
+	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int slot, int address)
+{
+	u8 buf[3];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
+
+	ci_dbg("%s %04x -> %d 0x%02x",
+		__func__, address, ret, buf[2]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[2];
+}
+
+static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+				 int slot, int address, u8 value)
+{
+	u8 buf[3];
+
+	ci_dbg("%s %d 0x%04x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = (address >> 8) & 0x0F;
+	buf[1] = address;
+	buf[2] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
+}
+
+static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address)
+{
+	u8 buf[2];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address & 3;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
+
+	ci_dbg("%s 0x%02x -> %d 0x%02x",
+		__func__, address, ret, buf[1]);
+
+	if (ret < 0)
+		return ret;
+
+	return buf[1];
+}
+
+static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 u8			address,
+				 u8			value)
+{
+	u8 buf[2];
+
+	ci_dbg("%s %d 0x%02x 0x%02x",
+		__func__, slot, address, value);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = address;
+	buf[1] = value;
+
+	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
+}
+
+static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			enable)
+{
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%s %d %d", __func__, slot, enable);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	enable = !!enable;
+	buf[0] = enable;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+	if (ret < 0)
+		return ret;
+
+	if (enable != buf[0]) {
+		err("CI not %sabled.", enable ? "en" : "dis");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
+}
+
+static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
+}
+
+static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[1];
+	int ret;
+
+	ci_dbg("%s %d", __func__, slot);
+
+	if (0 != slot)
+		return -EINVAL;
+
+	buf[0] = 0;
+
+	mutex_lock(&state->ca_mutex);
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 1;
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
+	if (0 != ret)
+		goto failed;
+
+	msleep(500);
+
+	buf[0] = 0; /* FTA */
+
+	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
+
+ failed:
+	mutex_unlock(&state->ca_mutex);
+
+	return ret;
+}
+
+static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
+				 int			slot,
+				 int			open)
+{
+	u8 buf[1];
+	int ret;
+
+	if (0 != slot)
+		return -EINVAL;
+
+	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
+	if (0 != ret)
+		return ret;
+
+	if (1 == buf[0])
+		return DVB_CA_EN50221_POLL_CAM_PRESENT |
+			DVB_CA_EN50221_POLL_CAM_READY;
+
+	return 0;
+
+}
+
+static void tt3650_ci_uninit(struct dvb_usb_device *d)
+{
+	struct pctv452e_state *state;
+
+	ci_dbg("%s", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = (struct pctv452e_state *)d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	/* Error ignored. */
+	tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+static int tt3650_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	int ret;
+
+	ci_dbg("%s", __func__);
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner = THIS_MODULE;
+	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
+	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
+	state->ca.read_cam_control = tt3650_ci_read_cam_control;
+	state->ca.write_cam_control = tt3650_ci_write_cam_control;
+	state->ca.slot_reset = tt3650_ci_slot_reset;
+	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
+	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
+	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
+	state->ca.data = d;
+
+	ret = dvb_ca_en50221_init(&a->dvb_adap,
+				   &state->ca,
+				   /* flags */ 0,
+				   /* n_slots */ 1);
+	if (0 != ret) {
+		err("Cannot initialize CI: Error %d.", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	info("CI initialized.");
+
+	return 0;
+}
+
+#define CMD_BUFFER_SIZE 0x28
+static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
+				const u8 *snd_buf, u8 snd_len,
+				u8 *rcv_buf, u8 rcv_len)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 buf[64];
+	u8 id;
+	int ret;
+
+	id = state->c++;
+
+	ret = -EINVAL;
+	if (snd_len > 64 - 7 || rcv_len > 64 - 7)
+		goto failed;
+
+	buf[0] = SYNC_BYTE_OUT;
+	buf[1] = id;
+	buf[2] = PCTV_CMD_I2C;
+	buf[3] = snd_len + 3;
+	buf[4] = addr << 1;
+	buf[5] = snd_len;
+	buf[6] = rcv_len;
+
+	memcpy(buf + 7, snd_buf, snd_len);
+
+	ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
+				  buf, /* rcv_len */ 64,
+				  /* delay_ms */ 0);
+	if (ret < 0)
+		goto failed;
+
+	/* TT USB protocol error. */
+	ret = -EIO;
+	if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+		goto failed;
+
+	/* I2C device didn't respond as expected. */
+	ret = -EREMOTEIO;
+	if (buf[5] < snd_len || buf[6] < rcv_len)
+		goto failed;
+
+	memcpy(rcv_buf, buf + 7, rcv_len);
+
+	return rcv_len;
+
+failed:
+	err("I2C error %d; %02X %02X  %02X %02X %02X -> "
+	     "%02X %02X  %02X %02X %02X.",
+	     ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
+	     buf[0], buf[1], buf[4], buf[5], buf[6]);
+
+	return ret;
+}
+
+static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
+				int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adapter);
+	int i;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
+		int ret;
+
+		if (msg[i].flags & I2C_M_RD) {
+			addr = msg[i].addr;
+			snd_buf = NULL;
+			snd_len = 0;
+			rcv_buf = msg[i].buf;
+			rcv_len = msg[i].len;
+		} else {
+			addr = msg[i].addr;
+			snd_buf = msg[i].buf;
+			snd_len = msg[i].len;
+			rcv_buf = NULL;
+			rcv_len = 0;
+		}
+
+		ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
+					rcv_len);
+		if (ret < rcv_len)
+			break;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return i;
+}
+
+static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
+	u8 rx[PCTV_ANSWER_LEN];
+	int ret;
+
+	info("%s: %d\n", __func__, i);
+
+	if (!i)
+		return 0;
+
+	if (state->initialized)
+		return 0;
+
+	/* hmm where shoud this should go? */
+	ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
+	if (ret != 0)
+		info("%s: Warning set interface returned: %d\n",
+			__func__, ret);
+
+	/* this is a one-time initialization, dont know where to put */
+	b0[1] = state->c++;
+	/* reset board */
+	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+	if (ret)
+		return ret;
+
+	b0[1] = state->c++;
+	b0[4] = 1;
+	/* reset board (again?) */
+	ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+	if (ret)
+		return ret;
+
+	state->initialized = 1;
+
+	return 0;
+}
+
+static int pctv452e_rc_query(struct dvb_usb_device *d)
+{
+	struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+	u8 b[CMD_BUFFER_SIZE];
+	u8 rx[PCTV_ANSWER_LEN];
+	int ret, i;
+	u8 id = state->c++;
+
+	/* prepare command header  */
+	b[0] = SYNC_BYTE_OUT;
+	b[1] = id;
+	b[2] = PCTV_CMD_IR;
+	b[3] = 0;
+
+	/* send ir request */
+	ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
+	if (ret != 0)
+		return ret;
+
+	if (debug > 3) {
+		info("%s: read: %2d: %02x %02x %02x: ", __func__,
+				ret, rx[0], rx[1], rx[2]);
+		for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
+			info(" %02x", rx[i+3]);
+
+		info("\n");
+	}
+
+	if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
+		/* got a "press" event */
+		state->last_rc_key = (rx[7] << 8) | rx[6];
+		if (debug > 2)
+			info("%s: cmd=0x%02x sys=0x%02x\n",
+				__func__, rx[6], rx[7]);
+
+		rc_keydown(d->rc_dev, state->last_rc_key, 0);
+	} else if (state->last_rc_key) {
+		rc_keyup(d->rc_dev);
+		state->last_rc_key = 0;
+	}
+
+	return 0;
+}
+
+static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	const u8 mem_addr[] = { 0x1f, 0xcc };
+	u8 encoded_mac[20];
+	int ret;
+
+	ret = -EAGAIN;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		goto failed;
+
+	ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
+				mem_addr + 1, /* snd_len */ 1,
+				encoded_mac, /* rcv_len */ 20);
+	if (-EREMOTEIO == ret)
+		/* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
+		   byte write if /WC is low. */
+		ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
+					mem_addr, 2,
+					encoded_mac, 20);
+
+	mutex_unlock(&d->i2c_mutex);
+
+	if (20 != ret)
+		goto failed;
+
+	ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
+	if (0 != ret)
+		goto failed;
+
+	return 0;
+
+failed:
+	memset(mac, 0, 6);
+
+	return ret;
+}
+
+static const struct stb0899_s1_reg pctv452e_init_dev[] = {
+	{ STB0899_DISCNTRL1,	0x26 },
+	{ STB0899_DISCNTRL2,	0x80 },
+	{ STB0899_DISRX_ST0,	0x04 },
+	{ STB0899_DISRX_ST1,	0x20 },
+	{ STB0899_DISPARITY,	0x00 },
+	{ STB0899_DISFIFO,	0x00 },
+	{ STB0899_DISF22,	0x99 },
+	{ STB0899_DISF22RX,	0x85 }, /* 0xa8 */
+	{ STB0899_ACRPRESC,	0x11 },
+	{ STB0899_ACRDIV1,	0x0a },
+	{ STB0899_ACRDIV2,	0x05 },
+	{ STB0899_DACR1	,	0x00 },
+	{ STB0899_DACR2	,	0x00 },
+	{ STB0899_OUTCFG,	0x00 },
+	{ STB0899_MODECFG,	0x00 }, /* Inversion */
+	{ STB0899_IRQMSK_3,	0xf3 },
+	{ STB0899_IRQMSK_2,	0xfc },
+	{ STB0899_IRQMSK_1,	0xff },
+	{ STB0899_IRQMSK_0,	0xff },
+	{ STB0899_I2CCFG,	0x88 },
+	{ STB0899_I2CRPT,	0x58 },
+	{ STB0899_GPIO00CFG,	0x82 },
+	{ STB0899_GPIO01CFG,	0x82 }, /* LED: 0x02 green, 0x82 orange */
+	{ STB0899_GPIO02CFG,	0x82 },
+	{ STB0899_GPIO03CFG,	0x82 },
+	{ STB0899_GPIO04CFG,	0x82 },
+	{ STB0899_GPIO05CFG,	0x82 },
+	{ STB0899_GPIO06CFG,	0x82 },
+	{ STB0899_GPIO07CFG,	0x82 },
+	{ STB0899_GPIO08CFG,	0x82 },
+	{ STB0899_GPIO09CFG,	0x82 },
+	{ STB0899_GPIO10CFG,	0x82 },
+	{ STB0899_GPIO11CFG,	0x82 },
+	{ STB0899_GPIO12CFG,	0x82 },
+	{ STB0899_GPIO13CFG,	0x82 },
+	{ STB0899_GPIO14CFG,	0x82 },
+	{ STB0899_GPIO15CFG,	0x82 },
+	{ STB0899_GPIO16CFG,	0x82 },
+	{ STB0899_GPIO17CFG,	0x82 },
+	{ STB0899_GPIO18CFG,	0x82 },
+	{ STB0899_GPIO19CFG,	0x82 },
+	{ STB0899_GPIO20CFG,	0x82 },
+	{ STB0899_SDATCFG,	0xb8 },
+	{ STB0899_SCLTCFG,	0xba },
+	{ STB0899_AGCRFCFG,	0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
+	{ STB0899_GPIO22,	0x82 },
+	{ STB0899_GPIO21,	0x91 },
+	{ STB0899_DIRCLKCFG,	0x82 },
+	{ STB0899_CLKOUT27CFG,	0x7e },
+	{ STB0899_STDBYCFG,	0x82 },
+	{ STB0899_CS0CFG,	0x82 },
+	{ STB0899_CS1CFG,	0x82 },
+	{ STB0899_DISEQCOCFG,	0x20 },
+	{ STB0899_NCOARSE,	0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
+	{ STB0899_SYNTCTRL,	0x00 }, /* 0x00 CLKI, 0x02 XTALI */
+	{ STB0899_FILTCTRL,	0x00 },
+	{ STB0899_SYSCTRL,	0x00 },
+	{ STB0899_STOPCLK1,	0x20 }, /* orig: 0x00 budget-ci: 0x20 */
+	{ STB0899_STOPCLK2,	0x00 },
+	{ STB0899_INTBUFCTRL,	0x0a },
+	{ STB0899_AGC2I1,	0x00 },
+	{ STB0899_AGC2I2,	0x00 },
+	{ STB0899_AGCIQIN,	0x00 },
+	{ STB0899_TSTRES,	0x40 }, /* rjkm */
+	{ 0xffff,		0xff },
+};
+
+static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
+	{ STB0899_DEMOD,	0x00 },
+	{ STB0899_RCOMPC,	0xc9 },
+	{ STB0899_AGC1CN,	0x01 },
+	{ STB0899_AGC1REF,	0x10 },
+	{ STB0899_RTC,		0x23 },
+	{ STB0899_TMGCFG,	0x4e },
+	{ STB0899_AGC2REF,	0x34 },
+	{ STB0899_TLSR,		0x84 },
+	{ STB0899_CFD,		0xf7 },
+	{ STB0899_ACLC,		0x87 },
+	{ STB0899_BCLC,		0x94 },
+	{ STB0899_EQON,		0x41 },
+	{ STB0899_LDT,		0xf1 },
+	{ STB0899_LDT2,		0xe3 },
+	{ STB0899_EQUALREF,	0xb4 },
+	{ STB0899_TMGRAMP,	0x10 },
+	{ STB0899_TMGTHD,	0x30 },
+	{ STB0899_IDCCOMP,	0xfd },
+	{ STB0899_QDCCOMP,	0xff },
+	{ STB0899_POWERI,	0x0c },
+	{ STB0899_POWERQ,	0x0f },
+	{ STB0899_RCOMP,	0x6c },
+	{ STB0899_AGCIQIN,	0x80 },
+	{ STB0899_AGC2I1,	0x06 },
+	{ STB0899_AGC2I2,	0x00 },
+	{ STB0899_TLIR,		0x30 },
+	{ STB0899_RTF,		0x7f },
+	{ STB0899_DSTATUS,	0x00 },
+	{ STB0899_LDI,		0xbc },
+	{ STB0899_CFRM,		0xea },
+	{ STB0899_CFRL,		0x31 },
+	{ STB0899_NIRM,		0x2b },
+	{ STB0899_NIRL,		0x80 },
+	{ STB0899_ISYMB,	0x1d },
+	{ STB0899_QSYMB,	0xa6 },
+	{ STB0899_SFRH,		0x2f },
+	{ STB0899_SFRM,		0x68 },
+	{ STB0899_SFRL,		0x40 },
+	{ STB0899_SFRUPH,	0x2f },
+	{ STB0899_SFRUPM,	0x68 },
+	{ STB0899_SFRUPL,	0x40 },
+	{ STB0899_EQUAI1,	0x02 },
+	{ STB0899_EQUAQ1,	0xff },
+	{ STB0899_EQUAI2,	0x04 },
+	{ STB0899_EQUAQ2,	0x05 },
+	{ STB0899_EQUAI3,	0x02 },
+	{ STB0899_EQUAQ3,	0xfd },
+	{ STB0899_EQUAI4,	0x03 },
+	{ STB0899_EQUAQ4,	0x07 },
+	{ STB0899_EQUAI5,	0x08 },
+	{ STB0899_EQUAQ5,	0xf5 },
+	{ STB0899_DSTATUS2,	0x00 },
+	{ STB0899_VSTATUS,	0x00 },
+	{ STB0899_VERROR,	0x86 },
+	{ STB0899_IQSWAP,	0x2a },
+	{ STB0899_ECNT1M,	0x00 },
+	{ STB0899_ECNT1L,	0x00 },
+	{ STB0899_ECNT2M,	0x00 },
+	{ STB0899_ECNT2L,	0x00 },
+	{ STB0899_ECNT3M,	0x0a },
+	{ STB0899_ECNT3L,	0xad },
+	{ STB0899_FECAUTO1,	0x06 },
+	{ STB0899_FECM,		0x01 },
+	{ STB0899_VTH12,	0xb0 },
+	{ STB0899_VTH23,	0x7a },
+	{ STB0899_VTH34,	0x58 },
+	{ STB0899_VTH56,	0x38 },
+	{ STB0899_VTH67,	0x34 },
+	{ STB0899_VTH78,	0x24 },
+	{ STB0899_PRVIT,	0xff },
+	{ STB0899_VITSYNC,	0x19 },
+	{ STB0899_RSULC,	0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC,	0x42 },
+	{ STB0899_RSLLC,	0x41 },
+	{ STB0899_TSLPL,	0x12 },
+	{ STB0899_TSCFGH,	0x0c },
+	{ STB0899_TSCFGM,	0x00 },
+	{ STB0899_TSCFGL,	0x00 },
+	{ STB0899_TSOUT,	0x69 }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL,	0x00 },
+	{ STB0899_TSINHDELH,	0x02 },
+	{ STB0899_TSINHDELM,	0x00 },
+	{ STB0899_TSINHDELL,	0x00 },
+	{ STB0899_TSLLSTKM,	0x1b },
+	{ STB0899_TSLLSTKL,	0xb3 },
+	{ STB0899_TSULSTKM,	0x00 },
+	{ STB0899_TSULSTKL,	0x00 },
+	{ STB0899_PCKLENUL,	0xbc },
+	{ STB0899_PCKLENLL,	0xcc },
+	{ STB0899_RSPCKLEN,	0xbd },
+	{ STB0899_TSSTATUS,	0x90 },
+	{ STB0899_ERRCTRL1,	0xb6 },
+	{ STB0899_ERRCTRL2,	0x95 },
+	{ STB0899_ERRCTRL3,	0x8d },
+	{ STB0899_DMONMSK1,	0x27 },
+	{ STB0899_DMONMSK0,	0x03 },
+	{ STB0899_DEMAPVIT,	0x5c },
+	{ STB0899_PLPARM,	0x19 },
+	{ STB0899_PDELCTRL,	0x48 },
+	{ STB0899_PDELCTRL2,	0x00 },
+	{ STB0899_BBHCTRL1,	0x00 },
+	{ STB0899_BBHCTRL2,	0x00 },
+	{ STB0899_HYSTTHRESH,	0x77 },
+	{ STB0899_MATCSTM,	0x00 },
+	{ STB0899_MATCSTL,	0x00 },
+	{ STB0899_UPLCSTM,	0x00 },
+	{ STB0899_UPLCSTL,	0x00 },
+	{ STB0899_DFLCSTM,	0x00 },
+	{ STB0899_DFLCSTL,	0x00 },
+	{ STB0899_SYNCCST,	0x00 },
+	{ STB0899_SYNCDCSTM,	0x00 },
+	{ STB0899_SYNCDCSTL,	0x00 },
+	{ STB0899_ISI_ENTRY,	0x00 },
+	{ STB0899_ISI_BIT_EN,	0x00 },
+	{ STB0899_MATSTRM,	0xf0 },
+	{ STB0899_MATSTRL,	0x02 },
+	{ STB0899_UPLSTRM,	0x45 },
+	{ STB0899_UPLSTRL,	0x60 },
+	{ STB0899_DFLSTRM,	0xe3 },
+	{ STB0899_DFLSTRL,	0x00 },
+	{ STB0899_SYNCSTR,	0x47 },
+	{ STB0899_SYNCDSTRM,	0x05 },
+	{ STB0899_SYNCDSTRL,	0x18 },
+	{ STB0899_CFGPDELSTATUS1, 0x19 },
+	{ STB0899_CFGPDELSTATUS2, 0x2b },
+	{ STB0899_BBFERRORM,	0x00 },
+	{ STB0899_BBFERRORL,	0x01 },
+	{ STB0899_UPKTERRORM,	0x00 },
+	{ STB0899_UPKTERRORL,	0x00 },
+	{ 0xffff,		0xff },
+};
+
+static struct stb0899_config stb0899_config = {
+	.init_dev	= pctv452e_init_dev,
+	.init_s2_demod	= stb0899_s2_init_2,
+	.init_s1_demod	= pctv452e_init_s1_demod,
+	.init_s2_fec	= stb0899_s2_init_4,
+	.init_tst	= stb0899_s1_init_5,
+
+	.demod_address   = I2C_ADDR_STB0899, /* I2C Address */
+	.block_sync_mode = STB0899_SYNC_FORCED, /* ? */
+
+	.xtal_freq       = 27000000,	 /* Assume Hz ? */
+	.inversion       = IQ_SWAP_ON,       /* ? */
+
+	.lo_clk	  = 76500000,
+	.hi_clk	  = 99000000,
+
+	.ts_output_mode  = 0,	/* Use parallel mode */
+	.clock_polarity  = 0,
+	.data_clk_parity = 0,
+	.fec_mode	= 0,
+
+	.esno_ave	    = STB0899_DVBS2_ESNO_AVE,
+	.esno_quant	  = STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse     = STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine       = STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold      = STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq   = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof   = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout  = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits	  = STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits	  = STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter	 = STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL,
+
+	/* helper for switching LED green/orange */
+	.postproc = pctv45e_postproc
+};
+
+static struct stb6100_config stb6100_config = {
+	.tuner_address = I2C_ADDR_STB6100,
+	.refclock      = 27000000
+};
+
+
+static struct i2c_algorithm pctv452e_i2c_algo = {
+	.master_xfer   = pctv452e_i2c_xfer,
+	.functionality = pctv452e_i2c_func
+};
+
+static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
+{
+	struct usb_device_id *id;
+
+	a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config,
+						&a->dev->i2c_adap);
+	if (!a->fe_adap[0].fe)
+		return -ENODEV;
+	if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
+					&a->dev->i2c_adap)) == 0)
+		err("Cannot attach lnbp22\n");
+
+	id = a->dev->desc->warm_ids[0];
+	if (USB_VID_TECHNOTREND == id->idVendor
+	    && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
+		/* Error ignored. */
+		tt3650_ci_init(a);
+
+	return 0;
+}
+
+static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
+{
+	if (!a->fe_adap[0].fe)
+		return -ENODEV;
+	if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
+					&a->dev->i2c_adap) == 0) {
+		err("%s failed\n", __func__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct usb_device_id pctv452e_usb_table[] = {
+	{USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)},
+	{USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)},
+	{USB_DEVICE(USB_VID_TECHNOTREND,
+				USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
+
+static struct dvb_usb_device_properties pctv452e_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv     = sizeof(struct pctv452e_state),
+
+	.power_ctrl       = pctv452e_power_ctrl,
+
+	.rc.core = {
+		.rc_codes	= RC_MAP_DIB0700_RC5_TABLE,
+		.allowed_protos	= RC_TYPE_UNKNOWN,
+		.rc_query	= pctv452e_rc_query,
+		.rc_interval	= 100,
+	},
+
+	.num_adapters     = 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach  = pctv452e_frontend_attach,
+			.tuner_attach     = pctv452e_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type     = USB_ISOC,
+				.count    = 4,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize    = 940,
+						.interval     = 1
+					}
+				}
+			},
+		} },
+	} },
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "PCTV HDTV USB",
+		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
+		  .warm_ids = { &pctv452e_usb_table[0], NULL }
+		},
+		{ 0 },
+	}
+};
+
+static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
+	.usb_ctrl = DEVICE_SPECIFIC,
+
+	.size_of_priv		= sizeof(struct pctv452e_state),
+
+	.power_ctrl		= pctv452e_power_ctrl,
+	.read_mac_address	= pctv452e_read_mac_address,
+
+	.rc.core = {
+		.rc_codes	= RC_MAP_TT_1500,
+		.allowed_protos	= RC_TYPE_UNKNOWN,
+		.rc_query	= pctv452e_rc_query,
+		.rc_interval	= 100,
+	},
+
+	.num_adapters		= 1,
+	.adapter = {{
+		.num_frontends = 1,
+		.fe = {{
+			.frontend_attach = pctv452e_frontend_attach,
+			.tuner_attach = pctv452e_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 7,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1
+					}
+				}
+			},
+
+		} },
+	} },
+
+	.i2c_algo = &pctv452e_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/
+
+	.num_device_descs = 2,
+	.devices = {
+		{ .name = "Technotrend TT Connect S2-3600",
+		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
+		  .warm_ids = { &pctv452e_usb_table[1], NULL }
+		},
+		{ .name = "Technotrend TT Connect S2-3650-CI",
+		  .cold_ids = { NULL, NULL },
+		  .warm_ids = { &pctv452e_usb_table[2], NULL }
+		},
+		{ 0 },
+	}
+};
+
+static void pctv452e_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+
+	tt3650_ci_uninit(d);
+	dvb_usb_device_exit(intf);
+}
+
+static int pctv452e_usb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
+					THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
+					THIS_MODULE, NULL, adapter_nr))
+		return 0;
+
+	return -ENODEV;
+}
+
+static struct usb_driver pctv452e_usb_driver = {
+	.name       = "pctv452e",
+	.probe      = pctv452e_usb_probe,
+	.disconnect = pctv452e_usb_disconnect,
+	.id_table   = pctv452e_usb_table,
+};
+
+static struct usb_driver tt_connects2_3600_usb_driver = {
+	.name       = "dvb-usb-tt-connect-s2-3600-01.fw",
+	.probe      = pctv452e_usb_probe,
+	.disconnect = pctv452e_usb_disconnect,
+	.id_table   = pctv452e_usb_table,
+};
+
+static int __init pctv452e_usb_init(void)
+{
+	int ret = usb_register(&pctv452e_usb_driver);
+
+	if (ret) {
+		err("%s: usb_register failed! Error %d", __FILE__, ret);
+		return ret;
+	}
+	ret = usb_register(&tt_connects2_3600_usb_driver);
+	if (ret)
+		err("%s: usb_register failed! Error %d", __FILE__, ret);
+
+	return ret;
+}
+
+static void __exit pctv452e_usb_exit(void)
+{
+	usb_deregister(&pctv452e_usb_driver);
+	usb_deregister(&tt_connects2_3600_usb_driver);
+}
+
+module_init(pctv452e_usb_init);
+module_exit(pctv452e_usb_exit);
+
+MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
+MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
+MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
+MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 28fbb5c..4a2d2e6 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -607,6 +607,16 @@ config DVB_LNBP21
 	help
 	  An SEC control chips.
 
+config DVB_LNBP22
+	tristate "LNBP22 SEC controllers"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  LNB power supply and control voltage
+	  regulator chip with step-up converter
+	  and I2C interface.
+	  Say Y when you want to support this chip.
+
 config DVB_ISL6405
 	tristate "ISL6405 SEC controller"
 	depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 36c8d81..f639f67 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c
new file mode 100644
index 0000000..84ad039
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp22.c
@@ -0,0 +1,148 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21 driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp22.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+
+#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
+
+struct lnbp22 {
+	u8		    config[4];
+	struct i2c_adapter *i2c;
+};
+
+static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv;
+	struct i2c_msg msg = {
+		.addr = 0x08,
+		.flags = 0,
+		.buf = (char *)&lnbp22->config,
+		.len = sizeof(lnbp22->config),
+	};
+
+	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __func__, voltage,
+	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
+
+	lnbp22->config[3] = 0x60; /* Power down */
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp22->config[3] |= LNBP22_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]);
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
+	struct i2c_msg msg = {
+		.addr = 0x08,
+		.flags = 0,
+		.buf = (char *)&lnbp22->config,
+		.len = sizeof(lnbp22->config),
+	};
+
+	dprintk(1, "%s: %d\n", __func__, (int)arg);
+	if (arg)
+		lnbp22->config[3] |= LNBP22_LLC;
+	else
+		lnbp22->config[3] &= ~LNBP22_LLC;
+
+	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp22_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s\n", __func__);
+	/* LNBP power off */
+	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c)
+{
+	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
+	if (!lnbp22)
+		return NULL;
+
+	/* default configuration */
+	lnbp22->config[0] = 0x00; /* ? */
+	lnbp22->config[1] = 0x28; /* ? */
+	lnbp22->config[2] = 0x48; /* ? */
+	lnbp22->config[3] = 0x60; /* Power down */
+	lnbp22->i2c = i2c;
+	fe->sec_priv = lnbp22;
+
+	/* detect if it is present or not */
+	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		dprintk(0, "%s LNBP22 not found\n", __func__);
+		kfree(lnbp22);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = lnbp22_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = lnbp22_set_voltage;
+	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
+
+	return fe;
+}
+EXPORT_SYMBOL(lnbp22_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
+MODULE_AUTHOR("Dominik Kuhlen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h
new file mode 100644
index 0000000..63e2dec
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp22.h
@@ -0,0 +1,57 @@
+/*
+ * lnbp22.h - driver for lnb supply and control ic lnbp22
+ *
+ * Copyright (C) 2006 Dominik Kuhlen
+ * Based on lnbp21.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP22_H
+#define _LNBP22_H
+
+/* Enable */
+#define LNBP22_EN	  0x10
+/* Voltage selection */
+#define LNBP22_VSEL	0x02
+/* Plus 1 Volt Bit */
+#define LNBP22_LLC	0x01
+
+#include <linux/dvb/frontend.h>
+
+#if defined(CONFIG_DVB_LNBP22) || \
+		(defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
+/*
+ * override_set and override_clear control which system register bits (above)
+ * to always set & clear
+ */
+extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LNBP22 */
+
+#endif /* _LNBP22_H */
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
index 7dd54b3..32d4315 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
@@ -85,6 +85,35 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC)
 	return 0;
 }
 
+int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC)
+{
+	u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c,
+		       0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6,
+		       0x1d, 0x36, 0x64, 0x78};
+	u8 data[20];
+	int i;
+
+	memcpy(data, encodedMAC, 20);
+
+	for (i = 0; i < 20; i++)
+		data[i] ^= xor[i];
+	for (i = 0; i < 10; i++)
+		data[i] = ((data[2 * i + 1] << 8) | data[2 * i])
+			>> ((data[2 * i + 1] >> 6) & 3);
+
+	if (check_mac_tt(data))
+		return -ENODEV;
+
+	decodedMAC[0] = data[2];
+	decodedMAC[1] = data[1];
+	decodedMAC[2] = data[0];
+	decodedMAC[3] = data[6];
+	decodedMAC[4] = data[5];
+	decodedMAC[5] = data[4];
+	return 0;
+}
+EXPORT_SYMBOL(ttpci_eeprom_decode_mac);
+
 static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
 {
 	int ret;
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h
index e2dc6cf..dcc33d5 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.h
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 
+extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC);
 extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
 
 #endif
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-13  6:04         ` Steffen Barszus
@ 2011-09-27  7:55           ` Dominik Kuhlen
  2011-09-27 11:28             ` Igor M. Liplianin
  2011-09-27 11:36             ` Mauro Carvalho Chehab
  0 siblings, 2 replies; 18+ messages in thread
From: Dominik Kuhlen @ 2011-09-27  7:55 UTC (permalink / raw)
  To: Steffen Barszus
  Cc: Igor M. Liplianin, linux-media, Doychin Dokov,
	Konstantin Dimitrov, Hans Petter Selasky, Michael H. Schimek,
	Mauro Chehab

Hi all,

sorry for being quiet such a long time....

On Tuesday 13 September 2011 08:04:51 Steffen Barszus wrote:
> On Wed, 15 Jun 2011 18:44:35 +0300
> "Igor M. Liplianin" <liplianin@me.by> wrote:
> 
> > From my point of view we can count the beginning was here:
> > 
> > http://www.spinics.net/lists/linux-dvb/msg26431.html
> > 
> > The later history is difficult to restore, but possible.
> >
> 
> After some searching it looks like this is the first occurrence of the
> driver:
> http://www.linuxtv.org/pipermail/linux-dvb/2007-October/021403.html
> 
> Further it looks like Dominik Kuhlen is not responding at that mail (as
> he has been on copy on one of the last mails. 
> 
> So looks like we cant get the signed-off-by from him. 
Where do you want me to put that line?
Although I cannot test the current code atm I trust the other testers and 
I'd like to see it included in the main tree. Improvements can still be added later...

Dominik

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-27  7:55           ` Dominik Kuhlen
@ 2011-09-27 11:28             ` Igor M. Liplianin
  2011-09-27 11:36             ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 18+ messages in thread
From: Igor M. Liplianin @ 2011-09-27 11:28 UTC (permalink / raw)
  To: Dominik Kuhlen
  Cc: Steffen Barszus, linux-media, Doychin Dokov, Konstantin Dimitrov,
	Hans Petter Selasky, Michael H. Schimek, Mauro Chehab

В сообщении от 27 сентября 2011 10:55:11 автор Dominik Kuhlen написал:
> Hi all,
> 
> sorry for being quiet such a long time....
> 
> On Tuesday 13 September 2011 08:04:51 Steffen Barszus wrote:
> > On Wed, 15 Jun 2011 18:44:35 +0300
> > 
> > "Igor M. Liplianin" <liplianin@me.by> wrote:
> > > From my point of view we can count the beginning was here:
> > > 
> > > http://www.spinics.net/lists/linux-dvb/msg26431.html
> > > 
> > > The later history is difficult to restore, but possible.
> > 
> > After some searching it looks like this is the first occurrence of the
> > driver:
> > http://www.linuxtv.org/pipermail/linux-dvb/2007-October/021403.html
> > 
> > Further it looks like Dominik Kuhlen is not responding at that mail (as
> > he has been on copy on one of the last mails.
> > 
> > So looks like we cant get the signed-off-by from him.
> 
> Where do you want me to put that line?
> Although I cannot test the current code atm I trust the other testers and
> I'd like to see it included in the main tree. Improvements can still be
> added later...
> 
> Dominik
Welcome, Dominik!

Igor
-- 
Igor M. Liplianin
Microsoft Windows Free Zone - Linux used for all Computing Tasks

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-27  7:55           ` Dominik Kuhlen
  2011-09-27 11:28             ` Igor M. Liplianin
@ 2011-09-27 11:36             ` Mauro Carvalho Chehab
  2011-09-27 20:24               ` Dominik Kuhlen
  1 sibling, 1 reply; 18+ messages in thread
From: Mauro Carvalho Chehab @ 2011-09-27 11:36 UTC (permalink / raw)
  To: Dominik Kuhlen
  Cc: Steffen Barszus, Igor M. Liplianin, linux-media, Doychin Dokov,
	Konstantin Dimitrov, Hans Petter Selasky, Michael H. Schimek

Em 27-09-2011 04:55, Dominik Kuhlen escreveu:
> Hi all,
> 
> sorry for being quiet such a long time....
> 
> On Tuesday 13 September 2011 08:04:51 Steffen Barszus wrote:
>> On Wed, 15 Jun 2011 18:44:35 +0300
>> "Igor M. Liplianin" <liplianin@me.by> wrote:
>>
>>> From my point of view we can count the beginning was here:
>>>
>>> http://www.spinics.net/lists/linux-dvb/msg26431.html
>>>
>>> The later history is difficult to restore, but possible.
>>>
>>
>> After some searching it looks like this is the first occurrence of the
>> driver:
>> http://www.linuxtv.org/pipermail/linux-dvb/2007-October/021403.html
>>
>> Further it looks like Dominik Kuhlen is not responding at that mail (as
>> he has been on copy on one of the last mails. 
>>
>> So looks like we cant get the signed-off-by from him. 
> Where do you want me to put that line?
> Although I cannot test the current code atm I trust the other testers and 
> I'd like to see it included in the main tree. Improvements can still be added later...

Just reply to this thread with your Signed-off-by: and I'll add it when submitting
the patch upstream.

Thank you!
Mauro

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Add support for PCTV452E.
  2011-09-27 11:36             ` Mauro Carvalho Chehab
@ 2011-09-27 20:24               ` Dominik Kuhlen
  0 siblings, 0 replies; 18+ messages in thread
From: Dominik Kuhlen @ 2011-09-27 20:24 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Steffen Barszus, Igor M. Liplianin, linux-media, Doychin Dokov,
	Konstantin Dimitrov, Hans Petter Selasky, Michael H. Schimek

[-- Attachment #1: Type: text/plain, Size: 1333 bytes --]

On Tuesday 27 September 2011 13:36:12 Mauro Carvalho Chehab wrote:
> Em 27-09-2011 04:55, Dominik Kuhlen escreveu:
> > Hi all,
> > 
> > sorry for being quiet such a long time....
> > 
> > On Tuesday 13 September 2011 08:04:51 Steffen Barszus wrote:
> >> On Wed, 15 Jun 2011 18:44:35 +0300
> >> "Igor M. Liplianin" <liplianin@me.by> wrote:
> >>
> >>> From my point of view we can count the beginning was here:
> >>>
> >>> http://www.spinics.net/lists/linux-dvb/msg26431.html
> >>>
> >>> The later history is difficult to restore, but possible.
> >>>
> >>
> >> After some searching it looks like this is the first occurrence of the
> >> driver:
> >> http://www.linuxtv.org/pipermail/linux-dvb/2007-October/021403.html
> >>
> >> Further it looks like Dominik Kuhlen is not responding at that mail (as
> >> he has been on copy on one of the last mails. 
> >>
> >> So looks like we cant get the signed-off-by from him. 
> > Where do you want me to put that line?
> > Although I cannot test the current code atm I trust the other testers and 
> > I'd like to see it included in the main tree. Improvements can still be added later...
> 
> Just reply to this thread with your Signed-off-by: and I'll add it when submitting
> the patch upstream.
Signed-off-by: Dominik Kuhlen <dkuhlen@gmx.net>



Dominik

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2011-09-27 20:25 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <201105242151.22826.hselasky@c2i.net>
2011-06-01 20:16 ` [PATCH] Add support for PCTV452E Mauro Carvalho Chehab
     [not found] ` <4DF399EA.6090508@net1.cc>
     [not found]   ` <4DF52148.4060704@net1.cc>
     [not found]     ` <4DF531BE.8090005@net1.cc>
2011-06-12 22:34       ` Doychin Dokov
2011-06-15 15:44       ` Igor M. Liplianin
2011-09-13  6:04         ` Steffen Barszus
2011-09-27  7:55           ` Dominik Kuhlen
2011-09-27 11:28             ` Igor M. Liplianin
2011-09-27 11:36             ` Mauro Carvalho Chehab
2011-09-27 20:24               ` Dominik Kuhlen
2011-07-23 11:24 ` Steffen Barszus
2011-07-30 21:12   ` Oliver Freyermuth
2011-09-05 21:27   ` Oliver Freyermuth
2011-09-23 20:03     ` Mauro Carvalho Chehab
2011-09-23 20:22       ` Steffen Barszus
2011-09-23 20:26       ` Steffen Barszus
2011-09-23 20:48       ` Igor M. Liplianin
2011-09-23 20:58       ` Oliver Freyermuth
2011-09-23 21:11         ` Igor M. Liplianin
2011-09-23 21:38           ` Igor M. Liplianin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.