diff --git a/packages/3rdparty/multimedia/vdr-plugin-vnsiserver/build b/packages/3rdparty/multimedia/vdr-plugin-vnsiserver/build
new file mode 100755
index 0000000000..7519ca69b0
--- /dev/null
+++ b/packages/3rdparty/multimedia/vdr-plugin-vnsiserver/build
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv)
+#
+# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to
+# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA.
+# http://www.gnu.org/copyleft/gpl.html
+################################################################################
+
+. config/options $1
+
+VDR_DIR=`basename $BUILD/vdr-[0-9]*`
+
+cd $PKG_BUILD
+ make VDRDIR="../$VDR_DIR" LIBDIR="." LOCALEDIR="./locale"
+
diff --git a/packages/3rdparty/multimedia/vdr-plugin-vnsiserver/meta b/packages/3rdparty/multimedia/vdr-plugin-vnsiserver/meta
new file mode 100644
index 0000000000..01d4368603
--- /dev/null
+++ b/packages/3rdparty/multimedia/vdr-plugin-vnsiserver/meta
@@ -0,0 +1,37 @@
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv)
+#
+# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to
+# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA.
+# http://www.gnu.org/copyleft/gpl.html
+################################################################################
+
+PKG_NAME="vdr-plugin-vnsiserver"
+PKG_VERSION="e3c185b"
+PKG_REV="1"
+PKG_ARCH="any"
+PKG_LICENSE="GPL"
+PKG_SITE="https://github.com/opdenkamp/xbmc-pvr-addons/tree/master/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver"
+PKG_URL="$DISTRO_SRC/$PKG_NAME-$PKG_VERSION.tar.xz"
+PKG_DEPENDS="vdr"
+PKG_BUILD_DEPENDS="toolchain vdr"
+PKG_PRIORITY="optional"
+PKG_SECTION="multimedia"
+PKG_SHORTDESC="TV"
+PKG_LONGDESC="TV"
+
+PKG_IS_ADDON="no"
+
+PKG_AUTORECONF="no"
diff --git a/packages/3rdparty/multimedia/vdr-plugin-xvdr/meta b/packages/3rdparty/multimedia/vdr-plugin-xvdr/meta
index c6f3381df4..8d3c562e7d 100644
--- a/packages/3rdparty/multimedia/vdr-plugin-xvdr/meta
+++ b/packages/3rdparty/multimedia/vdr-plugin-xvdr/meta
@@ -19,7 +19,7 @@
################################################################################
PKG_NAME="vdr-plugin-xvdr"
-PKG_VERSION="b62ccbd"
+PKG_VERSION="c2fa08a"
PKG_REV="1"
PKG_ARCH="any"
PKG_LICENSE="GPL"
diff --git a/packages/addons/service/multimedia/vdr-addon/addon b/packages/addons/service/multimedia/vdr-addon/addon
index b9d13a98c6..0c4d26f258 100755
--- a/packages/addons/service/multimedia/vdr-addon/addon
+++ b/packages/addons/service/multimedia/vdr-addon/addon
@@ -47,6 +47,7 @@ mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/config/epgsources/epgdata2xmltv
mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/plugin
cp -PR $BUILD/vdr-plugin-xvdr-*/libvdr*.so.* $ADDON_BUILD/$PKG_ADDON_ID/plugin
+ cp -PR $BUILD/vdr-plugin-vnsiserver-*/libvdr*.so.* $ADDON_BUILD/$PKG_ADDON_ID/plugin
cp -PR $BUILD/vdr-dynamite-*/libvdr*.so.* $ADDON_BUILD/$PKG_ADDON_ID/plugin
cp -PR $BUILD/vdr-iptv-*/libvdr*.so.* $ADDON_BUILD/$PKG_ADDON_ID/plugin
cp -PR $BUILD/vdr-wirbelscan-*/libvdr*.so.* $ADDON_BUILD/$PKG_ADDON_ID/plugin
@@ -72,6 +73,9 @@ mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/plugin
mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/config/plugins/xvdr
cp -PR $BUILD/vdr-plugin-xvdr-*/xvdr/allowed_hosts.conf $ADDON_BUILD/$PKG_ADDON_ID/config/plugins/xvdr
+mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/config/plugins/vnsiserver
+ cp -PR $BUILD/vdr-plugin-vnsiserver-*/vnsiserver/allowed_hosts.conf $ADDON_BUILD/$PKG_ADDON_ID/config/plugins/vnsiserver
+
mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/bin
cp -P $BUILD/vdr-[0-9]*/vdr $ADDON_BUILD/$PKG_ADDON_ID/bin/vdr.bin
cp -P $BUILD/vdr-plugin-xmltv2vdr*/dist/epgdata2xmltv/epgdata2xmltv $ADDON_BUILD/$PKG_ADDON_ID/bin
diff --git a/packages/addons/service/multimedia/vdr-addon/config/settings.xml b/packages/addons/service/multimedia/vdr-addon/config/settings.xml
index c20d288e02..868e2dce1f 100644
--- a/packages/addons/service/multimedia/vdr-addon/config/settings.xml
+++ b/packages/addons/service/multimedia/vdr-addon/config/settings.xml
@@ -3,6 +3,7 @@
+
diff --git a/packages/addons/service/multimedia/vdr-addon/source/bin/vdr.start b/packages/addons/service/multimedia/vdr-addon/source/bin/vdr.start
index b2d9efce6b..b91d677310 100755
--- a/packages/addons/service/multimedia/vdr-addon/source/bin/vdr.start
+++ b/packages/addons/service/multimedia/vdr-addon/source/bin/vdr.start
@@ -51,7 +51,7 @@ VDR_ARG="-g /tmp --no-kbd --log=3 --port=0"
VDR_ARG="$VDR_ARG --config=$ADDON_CONFIG_DIR"
VDR_ARG="$VDR_ARG --lib=$ADDON_PLUGIN_DIR"
VDR_ARG="$VDR_ARG --video=\"$VDR_VIDEO_DIR\""
-VDR_ARG="$VDR_ARG -P xvdr"
+VDR_ARG="$VDR_ARG -P $PVR_PLUGIN"
if [ "$ENABLE_SOFTCAM" == "true" ] ; then
VDR_ARG="$VDR_ARG -P $SOFTCAM_PLUGIN"
diff --git a/packages/addons/service/multimedia/vdr-addon/source/resources/language/English/strings.xml b/packages/addons/service/multimedia/vdr-addon/source/resources/language/English/strings.xml
index cf98f031a9..ff5dbacfbe 100644
--- a/packages/addons/service/multimedia/vdr-addon/source/resources/language/English/strings.xml
+++ b/packages/addons/service/multimedia/vdr-addon/source/resources/language/English/strings.xml
@@ -30,4 +30,5 @@
Enable plugin: text2skin
VDR Configuration
VDR Video Dir
+ PVR plugin
diff --git a/packages/addons/service/multimedia/vdr-addon/source/resources/settings.xml b/packages/addons/service/multimedia/vdr-addon/source/resources/settings.xml
index 465ab5559a..0ff09ec8c6 100644
--- a/packages/addons/service/multimedia/vdr-addon/source/resources/settings.xml
+++ b/packages/addons/service/multimedia/vdr-addon/source/resources/settings.xml
@@ -15,6 +15,7 @@
+
diff --git a/packages/linux-drivers/linux-tbs-drivers/meta b/packages/linux-drivers/linux-tbs-drivers/meta
index 4a19b81683..0623b0bf3d 100644
--- a/packages/linux-drivers/linux-tbs-drivers/meta
+++ b/packages/linux-drivers/linux-tbs-drivers/meta
@@ -19,7 +19,7 @@
################################################################################
PKG_NAME="linux-tbs-drivers"
-PKG_VERSION="120814"
+PKG_VERSION="121119"
PKG_REV="1"
PKG_ARCH="any"
PKG_LICENSE="GPL"
diff --git a/packages/linux/patches/linux-3.6.7-210-dvbsky.patch b/packages/linux/patches/linux-3.6.7-210-dvbsky.patch
new file mode 100644
index 0000000000..9a910cadcb
--- /dev/null
+++ b/packages/linux/patches/linux-3.6.7-210-dvbsky.patch
@@ -0,0 +1,5788 @@
+diff -urN a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
+--- a/drivers/media/dvb/dvb-usb/dw2102.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/dvb/dvb-usb/dw2102.c 2012-11-18 23:22:52.641154591 +0800
+@@ -19,6 +19,7 @@
+ #include "stb6000.h"
+ #include "eds1547.h"
+ #include "cx24116.h"
++#include "m88ds3103.h"
+ #include "tda1002x.h"
+ #include "mt312.h"
+ #include "zl10039.h"
+@@ -830,6 +831,39 @@
+ return 0;
+ }
+
++static int dvbsky_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
++{
++ int i;
++ u8 obuf[] = { 0x1e, 0x00 };
++ u8 ibuf[] = { 0 };
++ struct i2c_msg msg[] = {
++ {
++ .addr = 0x51,
++ .flags = 0,
++ .buf = obuf,
++ .len = 2,
++ }, {
++ .addr = 0x51,
++ .flags = I2C_M_RD,
++ .buf = ibuf,
++ .len = 1,
++
++ }
++ };
++
++ for (i = 0; i < 6; i++) {
++ obuf[1] = i;
++ if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
++ break;
++ else
++ mac[i] = ibuf[0];
++
++ debug_dump(mac, 6, printk);
++ }
++
++ return 0;
++}
++
+ static int su3000_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+@@ -878,6 +912,43 @@
+ return 0;
+ }
+
++static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++{
++
++ struct dvb_usb_adapter *udev_adap =
++ (struct dvb_usb_adapter *)(fe->dvb->priv);
++
++ u8 obuf[3] = { 0xe, 0x80, 0 };
++ u8 ibuf[] = { 0 };
++
++ info("US6830: %s!\n", __func__);
++
++ if (voltage == SEC_VOLTAGE_OFF)
++ obuf[2] = 0;
++ else
++ obuf[2] = 1;
++
++ if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x0e transfer failed.");
++
++ return 0;
++}
++
++static int bstusb_restart(struct dvb_frontend *fe)
++{
++
++ struct dvb_usb_adapter *udev_adap =
++ (struct dvb_usb_adapter *)(fe->dvb->priv);
++
++ u8 obuf[3] = { 0x36, 3, 0 };
++ u8 ibuf[] = { 0 };
++
++ if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x36 transfer failed.");
++
++ return 0;
++}
++
+ static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
+ {
+ static u8 led_off[] = { 0 };
+@@ -983,6 +1054,24 @@
+ .ci_mode = 1,
+ };
+
++static struct m88ds3103_config US6830_ds3103_config = {
++ .demod_address = 0x68,
++ .ci_mode = 1,
++ .pin_ctrl = 0x83,
++ .ts_mode = 0,
++ .start_ctrl = bstusb_restart,
++ .set_voltage = bstusb_set_voltage,
++};
++
++static struct m88ds3103_config US6832_ds3103_config = {
++ .demod_address = 0x68,
++ .ci_mode = 1,
++ .pin_ctrl = 0x80,
++ .ts_mode = 0,
++ .start_ctrl = bstusb_restart,
++ .set_voltage = bstusb_set_voltage,
++};
++
+ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
+ {
+ struct dvb_tuner_ops *tuner_ops = NULL;
+@@ -1210,6 +1299,87 @@
+ return 0;
+ }
+
++static int US6830_frontend_attach(struct dvb_usb_adapter *d)
++{
++ u8 obuf[3] = { 0xe, 0x04, 1 };
++ u8 ibuf[] = { 0 };
++
++ info("US6830: %s!\n", __func__);
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x0e transfer failed.");
++
++ obuf[0] = 0xe;
++ obuf[1] = 0x83;
++ obuf[2] = 0;
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x0e transfer failed.");
++
++ msleep(20);
++
++ obuf[0] = 0xe;
++ obuf[1] = 0x83;
++ obuf[2] = 1;
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x0e transfer failed.");
++
++ obuf[0] = 0x51;
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
++ err("command 0x51 transfer failed.");
++
++ d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6830_ds3103_config,
++ &d->dev->i2c_adap);
++ if (d->fe_adap[0].fe == NULL)
++ return -EIO;
++
++ info("Attached M88DS3103!\n");
++
++ return 0;
++}
++
++static int US6832_frontend_attach(struct dvb_usb_adapter *d)
++{
++ u8 obuf[3] = { 0xe, 0x04, 1 };
++ u8 ibuf[] = { 0 };
++
++ info("US6832: %s!\n", __func__);
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x0e transfer failed.");
++
++ obuf[0] = 0xe;
++ obuf[1] = 0x83;
++ obuf[2] = 0;
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x0e transfer failed.");
++
++ msleep(20);
++ obuf[0] = 0xe;
++ obuf[1] = 0x83;
++ obuf[2] = 1;
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
++ err("command 0x0e transfer failed.");
++
++ obuf[0] = 0x51;
++
++ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
++ err("command 0x51 transfer failed.");
++
++ d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6832_ds3103_config,
++ &d->dev->i2c_adap);
++ if (d->fe_adap[0].fe == NULL)
++ return -EIO;
++
++ info("Attached M88DS3103!\n");
++
++ return 0;
++}
++
+ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+ dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
+@@ -1447,6 +1617,9 @@
+ TEVII_S480_1,
+ TEVII_S480_2,
+ X3M_SPC1400HD,
++ BST_US6830HD,
++ BST_US6831HD,
++ BST_US6832HD,
+ };
+
+ static struct usb_device_id dw2102_table[] = {
+@@ -1465,6 +1638,9 @@
+ [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
+ [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
+ [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
++ [BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)},
++ [BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)},
++ [BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)},
+ { }
+ };
+
+@@ -1870,6 +2046,106 @@
+ }
+ };
+
++static struct dvb_usb_device_properties US6830_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
++ .usb_ctrl = DEVICE_SPECIFIC,
++ .size_of_priv = sizeof(struct su3000_state),
++ .power_ctrl = su3000_power_ctrl,
++ .num_adapters = 1,
++ .identify_state = su3000_identify_state,
++ .i2c_algo = &su3000_i2c_algo,
++
++ .rc.legacy = {
++ .rc_map_table = rc_map_su3000_table,
++ .rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
++ .rc_interval = 150,
++ .rc_query = dw2102_rc_query,
++ },
++
++ .read_mac_address = dvbsky_read_mac_address,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
++
++ .adapter = {
++ {
++ .num_frontends = 1,
++ .fe = {{
++ .streaming_ctrl = su3000_streaming_ctrl,
++ .frontend_attach = US6830_frontend_attach,
++ .stream = {
++ .type = USB_BULK,
++ .count = 8,
++ .endpoint = 0x82,
++ .u = {
++ .bulk = {
++ .buffersize = 4096,
++ }
++ }
++ }
++ }},
++ }
++ },
++ .num_device_descs = 2,
++ .devices = {
++ { "Bestunar US6830 HD",
++ { &dw2102_table[BST_US6830HD], NULL },
++ { NULL },
++ },
++ { "Bestunar US6831 HD",
++ { &dw2102_table[BST_US6831HD], NULL },
++ { NULL },
++ },
++ }
++};
++
++static struct dvb_usb_device_properties US6832_properties = {
++ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
++ .usb_ctrl = DEVICE_SPECIFIC,
++ .size_of_priv = sizeof(struct su3000_state),
++ .power_ctrl = su3000_power_ctrl,
++ .num_adapters = 1,
++ .identify_state = su3000_identify_state,
++ .i2c_algo = &su3000_i2c_algo,
++
++ .rc.legacy = {
++ .rc_map_table = rc_map_su3000_table,
++ .rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
++ .rc_interval = 150,
++ .rc_query = dw2102_rc_query,
++ },
++
++ .read_mac_address = dvbsky_read_mac_address,
++
++ .generic_bulk_ctrl_endpoint = 0x01,
++
++ .adapter = {
++ {
++ .num_frontends = 1,
++ .fe = {{
++ .streaming_ctrl = su3000_streaming_ctrl,
++ .frontend_attach = US6832_frontend_attach,
++ .stream = {
++ .type = USB_BULK,
++ .count = 8,
++ .endpoint = 0x82,
++ .u = {
++ .bulk = {
++ .buffersize = 4096,
++ }
++ }
++ }
++ }},
++ }
++ },
++ .num_device_descs = 1,
++ .devices = {
++ { "Bestunar US6832 HD",
++ { &dw2102_table[BST_US6832HD], NULL },
++ { NULL },
++ },
++ }
++};
++
+ static int dw2102_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+ {
+@@ -1926,6 +2202,10 @@
+ 0 == dvb_usb_device_init(intf, p7500,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &su3000_properties,
++ THIS_MODULE, NULL, adapter_nr) ||
++ 0 == dvb_usb_device_init(intf, &US6830_properties,
++ THIS_MODULE, NULL, adapter_nr) ||
++ 0 == dvb_usb_device_init(intf, &US6832_properties,
+ THIS_MODULE, NULL, adapter_nr))
+ return 0;
+
+diff -urN a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
+--- a/drivers/media/dvb/dvb-usb/Kconfig 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/dvb/dvb-usb/Kconfig 2012-11-18 23:23:02.517154858 +0800
+@@ -279,6 +279,7 @@
+ select DVB_STV0288 if !DVB_FE_CUSTOMISE
+ select DVB_STB6000 if !DVB_FE_CUSTOMISE
+ select DVB_CX24116 if !DVB_FE_CUSTOMISE
++ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
+ select DVB_SI21XX if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+ select DVB_MT312 if !DVB_FE_CUSTOMISE
+diff -urN a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
+--- a/drivers/media/dvb/frontends/Kconfig 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/dvb/frontends/Kconfig 2012-11-18 23:23:15.397155199 +0800
+@@ -215,6 +215,20 @@
+ help
+ A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
++config DVB_M88DS3103
++ tristate "Montage DS3103 based"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
++
++config DVB_M88DC2800
++ tristate "Montage DC2800 DVB-C"
++ depends on DVB_CORE && I2C
++ default m if DVB_FE_CUSTOMISE
++ help
++ A DVB-C tuner module. Say Y when you want to support this frontend.
++
+ config DVB_SI21XX
+ tristate "Silicon Labs SI21XX based"
+ depends on DVB_CORE && I2C
+diff -urN a/drivers/media/dvb/frontends/m88dc2800.c b/drivers/media/dvb/frontends/m88dc2800.c
+--- a/drivers/media/dvb/frontends/m88dc2800.c 1970-01-01 08:00:00.000000000 +0800
++++ b/drivers/media/dvb/frontends/m88dc2800.c 2012-11-18 23:23:20.205155329 +0800
+@@ -0,0 +1,2235 @@
++/*
++ M88DC2800/M88TC2800 - DVB-C demodulator and tuner from Montage
++
++ Copyright (C) 2012 Max nibble
++ Copyright (C) 2011 Montage Technology
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include "dvb_frontend.h"
++#include "m88dc2800.h"
++
++struct m88dc2800_state {
++ struct i2c_adapter* i2c;
++ const struct m88dc2800_config *config;
++ struct dvb_frontend frontend;
++ u32 freq;
++ u32 ber;
++ u32 sym;
++ u16 qam;
++ u8 inverted;
++ u32 xtal;
++ /*tuner state*/
++ u8 tuner_init_OK; /* Tuner initialize status */
++ u8 tuner_dev_addr; /* Tuner device address */
++ u32 tuner_freq; /* RF frequency to be set, unit: KHz */
++ u16 tuner_qam; /* Reserved */
++ u16 tuner_mode;
++ u8 tuner_bandwidth; /* Bandwidth of the channel, unit: MHz, 6/7/8 */
++ u8 tuner_loopthrough; /* Tuner loop through switch, 0/1 */
++ u32 tuner_crystal; /* Tuner crystal frequency, unit: KHz */
++ u32 tuner_dac; /* Tuner DAC frequency, unit: KHz */
++ u16 tuner_mtt; /* Tuner chip version, D1: 0x0d, E0: 0x0e, E1: 0x8e */
++ u16 tuner_custom_cfg;
++ u32 tuner_version; /* Tuner driver version number */
++ u32 tuner_time;
++};
++
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
++
++#define dprintk(args...) \
++ do { \
++ if (debug) \
++ printk(KERN_INFO "m88dc2800: " args); \
++ } while (0)
++
++
++static int m88dc2800_i2c_write(struct m88dc2800_state *state, u8 addr, u8 *p_data, u8 len)
++{
++ struct i2c_msg msg = { .flags = 0 };
++
++ msg.addr = addr;
++ msg.buf = p_data;
++ msg.len = len;
++
++ return i2c_transfer(state->i2c, &msg, 1);
++}
++
++static int m88dc2800_i2c_read(struct m88dc2800_state *state, u8 addr, u8 *p_data, u8 len)
++{
++ struct i2c_msg msg = { .flags = I2C_M_RD };
++
++ msg.addr = addr;
++ msg.buf = p_data;
++ msg.len = len;
++
++ return i2c_transfer(state->i2c, &msg, 1);
++}
++
++/*demod register operations.*/
++static int WriteReg(struct m88dc2800_state *state, u8 reg, u8 data)
++{
++ u8 buf[] = { reg, data };
++ u8 addr = state->config->demod_address;
++ int err;
++
++ if (debug > 1)
++ printk("m88dc2800: %s: write reg 0x%02x, value 0x%02x\n",
++ __func__, reg, data);
++
++ err = m88dc2800_i2c_write(state, addr, buf, 2);
++
++ if (err != 1) {
++ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
++ " value == 0x%02x)\n", __func__, err, reg, data);
++ return -EIO;
++ }
++ return 0;
++}
++
++static int ReadReg(struct m88dc2800_state *state, u8 reg)
++{
++ int ret;
++ u8 b0[] = { reg };
++ u8 b1[] = { 0 };
++ u8 addr = state->config->demod_address;
++
++ ret = m88dc2800_i2c_write(state, addr, b0, 1);
++
++ if (ret != 1) {
++ printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
++ __func__, reg, ret);
++ return -EIO;
++ }
++
++ ret = m88dc2800_i2c_read(state, addr, b1, 1);
++
++ if (debug > 1)
++ printk(KERN_INFO "m88dc2800: read reg 0x%02x, value 0x%02x\n",
++ reg, b1[0]);
++ return b1[0];
++}
++
++static int _mt_fe_tn_set_reg(struct m88dc2800_state *state, u8 reg, u8 data)
++{
++ int ret;
++ u8 buf[2];
++ u8 addr = state->tuner_dev_addr;
++
++ buf[1] = ReadReg(state, 0x86);
++ buf[1] |= 0x80;
++ ret = WriteReg(state, 0x86, buf[1]);
++
++ buf[0] = reg;
++ buf[1] = data;
++
++ ret = m88dc2800_i2c_write(state, addr, buf, 2);
++ if(ret != 1)
++ return -EIO;
++ return 0;
++}
++
++static int _mt_fe_tn_get_reg(struct m88dc2800_state *state, u8 reg, u8 *p_data)
++{
++ int ret;
++ u8 buf[2];
++ u8 addr = state->tuner_dev_addr;
++
++ buf[1] = ReadReg(state, 0x86);
++ buf[1] |= 0x80;
++ ret = WriteReg(state, 0x86, buf[1]);
++
++ buf[0] = reg;
++ ret = m88dc2800_i2c_write(state, addr, buf, 1);
++
++ msleep(1);
++
++ buf[1] = ReadReg(state, 0x86);
++ buf[1] |= 0x80;
++ ret = WriteReg(state, 0x86, buf[1]);
++
++ return m88dc2800_i2c_read(state, addr, p_data, 1);
++}
++
++/* Tuner operation functions.*/
++static int _mt_fe_tn_set_RF_front_tc2800(struct m88dc2800_state *state)
++{
++ u32 freq_KHz = state->tuner_freq;
++
++ if (state->tuner_mtt == 0xD1) { /* D1 */
++ if (freq_KHz <= 123000) {
++ if (freq_KHz <= 56000) {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x00);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x00);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x00);
++ }else if (freq_KHz <= 64000) {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x10);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x01);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x08);
++ }else if (freq_KHz <= 72000) {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x20);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x02);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x10);
++ }else if (freq_KHz <= 80000) {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x30);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x03);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x18);
++ }else if (freq_KHz <= 88000) {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x40);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x04);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x20);
++ }else if (freq_KHz <= 96000) {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x50);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x05);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x28);
++ }else if (freq_KHz <= 104000) {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x60);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x06);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x30);
++ }else {
++ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
++ _mt_fe_tn_set_reg(state, 0x59, 0x70);
++ _mt_fe_tn_set_reg(state, 0x5d, 0x07);
++ _mt_fe_tn_set_reg(state, 0x5e, 0x38);
++ }
++ _mt_fe_tn_set_reg(state, 0x5a, 0x75);
++ _mt_fe_tn_set_reg(state, 0x73, 0x0c);
++ } else { /* if (freq_KHz > 112000) */
++ _mt_fe_tn_set_reg(state, 0x58, 0x7b);
++ if (freq_KHz <= 304000) {
++ if (freq_KHz <= 136000) {
++ _mt_fe_tn_set_reg(state, 0x5e, 0x40);
++ }else if (freq_KHz <= 160000) {
++ _mt_fe_tn_set_reg(state, 0x5e, 0x48);
++ }else if (freq_KHz <= 184000) {
++ _mt_fe_tn_set_reg(state, 0x5e, 0x50);
++ }else if (freq_KHz <= 208000) {
++ _mt_fe_tn_set_reg(state, 0x5e, 0x58);
++ }else if (freq_KHz <= 232000) {
++ _mt_fe_tn_set_reg(state, 0x5e, 0x60);
++ }else if (freq_KHz <= 256000) {
++ _mt_fe_tn_set_reg(state, 0x5e, 0x68);
++ }else if (freq_KHz <= 280000) {
++ _mt_fe_tn_set_reg(state, 0x5e, 0x70);
++ }else { /*if (freq_KHz <= 304000)*/
++ _mt_fe_tn_set_reg(state, 0x5e, 0x78);
++ }
++ if (freq_KHz <= 171000) {
++ _mt_fe_tn_set_reg(state, 0x73, 0x08);
++ }else if (freq_KHz <= 211000) {
++ _mt_fe_tn_set_reg(state, 0x73, 0x0a);
++ }else {
++ _mt_fe_tn_set_reg(state, 0x73, 0x0e);
++ }
++ }else { /* if (freq_KHz > 304000) */
++ _mt_fe_tn_set_reg(state, 0x5e, 0x88);
++ if (freq_KHz <= 400000) {
++ _mt_fe_tn_set_reg(state, 0x73, 0x0c);
++ }else if (freq_KHz <= 450000) {
++ _mt_fe_tn_set_reg(state, 0x73, 0x09);
++ }else if (freq_KHz <= 550000) {
++ _mt_fe_tn_set_reg(state, 0x73, 0x0e);
++ }else if (freq_KHz <= 650000) {
++ _mt_fe_tn_set_reg(state, 0x73, 0x0d);
++ }else { /*if (freq_KHz > 650000) */
++ _mt_fe_tn_set_reg(state, 0x73, 0x0e);
++ }
++ }
++ }
++
++ if (freq_KHz > 800000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x24);
++ else if (freq_KHz > 700000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x34);
++ else if (freq_KHz > 500000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x44);
++ else if (freq_KHz > 300000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x43);
++ else if (freq_KHz > 220000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++ else if (freq_KHz > 110000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x14);
++ else
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++
++ if (freq_KHz > 600000)
++ _mt_fe_tn_set_reg(state, 0x6a, 0x53);
++ else if (freq_KHz > 500000)
++ _mt_fe_tn_set_reg(state, 0x6a, 0x57);
++ else
++ _mt_fe_tn_set_reg(state, 0x6a, 0x59);
++
++ if (freq_KHz < 200000) {
++ _mt_fe_tn_set_reg(state, 0x20, 0x5d);
++ }else if (freq_KHz < 500000) {
++ _mt_fe_tn_set_reg(state, 0x20, 0x7d);
++ }else {
++ _mt_fe_tn_set_reg(state, 0x20, 0xfd);
++ }/* end of 0xD1 */
++ }else if (state->tuner_mtt == 0xE1) { /* E1 */
++ if (freq_KHz <= 112000) { /* 123MHz */
++ if (freq_KHz <= 56000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x01);
++ }else if (freq_KHz <= 64000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x09);
++ }else if (freq_KHz <= 72000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x11);
++ }else if (freq_KHz <= 80000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x19);
++ }else if (freq_KHz <= 88000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x21);
++ }else if (freq_KHz <= 96000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x29);
++ }else if (freq_KHz <= 104000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x31);
++ }else {/* if (freq_KHz <= 112000) */
++ _mt_fe_tn_set_reg(state, 0x5c, 0x39);
++ }
++ _mt_fe_tn_set_reg(state, 0x5b, 0x30);
++ }else { /* if (freq_KHz > 112000) */
++ if (freq_KHz <= 304000) {
++ if (freq_KHz <= 136000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x41);
++ }else if (freq_KHz <= 160000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x49);
++ }else if (freq_KHz <= 184000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x51);
++ }else if (freq_KHz <= 208000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x59);
++ }else if (freq_KHz <= 232000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x61);
++ }else if (freq_KHz <= 256000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x69);
++ }else if (freq_KHz <= 280000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x71);
++ }else { /*if (freq_KHz <= 304000)*/
++ _mt_fe_tn_set_reg(state, 0x5c, 0x79);
++ }
++
++ if (freq_KHz <= 150000) {
++ _mt_fe_tn_set_reg(state, 0x5b, 0x28);
++ }else if (freq_KHz <= 256000) {
++ _mt_fe_tn_set_reg(state, 0x5b, 0x29);
++ }else {
++ _mt_fe_tn_set_reg(state, 0x5b, 0x2a);
++ }
++ }else { /* if (freq_KHz > 304000) */
++ if (freq_KHz <= 400000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x89);
++ }else if (freq_KHz <= 450000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x91);
++ }else if (freq_KHz <= 650000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0x98);
++ }else if (freq_KHz <= 850000) {
++ _mt_fe_tn_set_reg(state, 0x5c, 0xa0);
++ }else {
++ _mt_fe_tn_set_reg(state, 0x5c, 0xa8);
++ }
++ _mt_fe_tn_set_reg(state, 0x5b, 0x08);
++ }
++ }
++ } /* end of 0xE1 */
++ return 0;
++}
++
++static int _mt_fe_tn_cali_PLL_tc2800(struct m88dc2800_state *state, u32 freq_KHz, u32 cali_freq_thres_div2, u32 cali_freq_thres_div3r, u32 cali_freq_thres_div3)
++{
++ s32 N, F, MUL;
++ u8 buf, tmp, tmp2;
++ s32 M;
++ const s32 crystal_KHz = state->tuner_crystal;
++
++ if (state->tuner_mtt == 0xD1) {
++ M = state->tuner_crystal / 4000;
++ if (freq_KHz > cali_freq_thres_div2) {
++ MUL = 4;
++ tmp = 2;
++ }else if (freq_KHz > 300000) {
++ MUL = 8;
++ tmp = 3;
++ }else if (freq_KHz > (cali_freq_thres_div2 / 2)) {
++ MUL = 8;
++ tmp = 4;
++ }else if (freq_KHz > (cali_freq_thres_div2 / 4)) {
++ MUL = 16;
++ tmp = 5;
++ }else if (freq_KHz > (cali_freq_thres_div2 / 8)) {
++ MUL = 32;
++ tmp = 6;
++ }else if (freq_KHz > (cali_freq_thres_div2 / 16)){
++ MUL = 64;
++ tmp = 7;
++ }else { /* invalid */
++ MUL = 0;
++ tmp = 0;
++ return 1;
++ }
++ }else if (state->tuner_mtt == 0xE1) {
++ M = state->tuner_crystal / 1000;
++
++ _mt_fe_tn_set_reg(state, 0x30, 0xff);
++ _mt_fe_tn_set_reg(state, 0x32, 0xe0);
++ _mt_fe_tn_set_reg(state, 0x33, 0x86);
++ _mt_fe_tn_set_reg(state, 0x37, 0x70);
++ _mt_fe_tn_set_reg(state, 0x38, 0x20);
++ _mt_fe_tn_set_reg(state, 0x39, 0x18);
++ _mt_fe_tn_set_reg(state, 0x89, 0x83);
++
++ if (freq_KHz > cali_freq_thres_div2) {
++ M = M / 4;
++ MUL = 4;
++ tmp = 2;
++ tmp2 = M + 16; /*48*/
++ }else if (freq_KHz > cali_freq_thres_div3r) {
++ M = M / 3;
++ MUL = 6;
++ tmp = 2;
++ tmp2 = M + 32; /*32*/
++ }else if (freq_KHz > cali_freq_thres_div3) {
++ M = M / 3;
++ MUL = 6;
++ tmp = 2;
++ tmp2 = M; /*16*/
++ }else if (freq_KHz > 304000) {
++ M = M / 4;
++ MUL = 8;
++ tmp = 3;
++ tmp2 = M + 16; /*48*/
++ }else if (freq_KHz > (cali_freq_thres_div2 / 2)) {
++ M = M / 4;
++ MUL = 8;
++ tmp = 4;
++ tmp2 = M + 16; /*48*/
++ }else if (freq_KHz > (cali_freq_thres_div3r / 2)) {
++ M = M / 3;
++ MUL = 12;
++ tmp = 4;
++ tmp2 = M + 32; /*32*/
++ }else if (freq_KHz > (cali_freq_thres_div3 / 2)) {
++ M = M / 3;
++ MUL = 12;
++ tmp = 4;
++ tmp2 = M; /*16*/
++ }else if (freq_KHz > (cali_freq_thres_div2 / 4)) {
++ M = M / 4;
++ MUL = 16;
++ tmp = 5;
++ tmp2 = M + 16; /*48*/
++ }else if (freq_KHz > (cali_freq_thres_div3r / 4)) {
++ M = M / 3;
++ MUL = 24;
++ tmp = 5;
++ tmp2 = M + 32; /*32*/
++ }else if (freq_KHz > (cali_freq_thres_div3 / 4)) {
++ M = M / 3;
++ MUL = 24;
++ tmp = 5;
++ tmp2 = M; /*16*/
++ }else if (freq_KHz > (cali_freq_thres_div2 / 8)) {
++ M = M / 4;
++ MUL = 32;
++ tmp = 6;
++ tmp2 = M + 16; /*48*/
++ }else if (freq_KHz > (cali_freq_thres_div3r / 8)) {
++ M = M / 3;
++ MUL = 48;
++ tmp = 6;
++ tmp2 = M + 32; /*32*/
++ }else if (freq_KHz > (cali_freq_thres_div3 / 8)) {
++ M = M / 3;
++ MUL = 48;
++ tmp = 6;
++ tmp2 = M; /*16*/
++ }else if (freq_KHz > (cali_freq_thres_div2 / 16)) {
++ M = M / 4;
++ MUL = 64;
++ tmp = 7;
++ tmp2 = M + 16; /*48*/
++ }else if (freq_KHz > (cali_freq_thres_div3r / 16)) {
++ M = M / 3;
++ MUL = 96;
++ tmp = 7;
++ tmp2 = M + 32; /*32*/
++ }else if (freq_KHz > (cali_freq_thres_div3 / 16)) {
++ M = M / 3;
++ MUL = 96;
++ tmp = 7;
++ tmp2 = M; /*16*/
++ }else { /* invalid */
++ M = M / 4;
++ MUL = 0;
++ tmp = 0;
++ tmp2 = 48;
++ return 1;
++ }
++
++ if (freq_KHz == 291000) {
++ M = state->tuner_crystal / 1000 / 3;
++ MUL = 12;
++ tmp = 4;
++ tmp2 = M + 32; /*32*/
++ }
++ /*
++ if (freq_KHz == 578000) {
++ M = state->tuner_crystal / 1000 / 4;
++ MUL = 4;
++ tmp = 2;
++ tmp2 = M + 16; //48
++ }
++ */
++ if (freq_KHz == 690000) {
++ M = state->tuner_crystal / 1000 / 3;
++ MUL = 4;
++ tmp = 2;
++ tmp2 = M + 16; /*48*/
++ }
++ _mt_fe_tn_get_reg(state, 0x33, &buf);
++ buf &= 0xc0;
++ buf += tmp2;
++ _mt_fe_tn_set_reg(state, 0x33, buf);
++ }else {
++ return 1;
++ }
++
++ _mt_fe_tn_get_reg(state, 0x39, &buf);
++ buf &= 0xf8;
++ buf += tmp;
++ _mt_fe_tn_set_reg(state, 0x39, buf);
++
++ N = (freq_KHz * MUL * M / crystal_KHz) / 2 * 2 - 256;
++
++ buf = (N >> 8) & 0xcf;
++ if (state->tuner_mtt == 0xE1) {
++ buf |= 0x30;
++ }
++ _mt_fe_tn_set_reg(state, 0x34, buf);
++
++ buf = N & 0xff;
++ _mt_fe_tn_set_reg(state, 0x35, buf);
++
++ F = ((freq_KHz * MUL * M / (crystal_KHz / 1000) / 2) - (freq_KHz * MUL * M / crystal_KHz / 2 * 1000)) * 64 / 1000;
++
++ buf = F & 0xff;
++ _mt_fe_tn_set_reg(state, 0x36, buf);
++
++ if (F == 0) {
++ if (state->tuner_mtt == 0xD1) {
++ _mt_fe_tn_set_reg(state, 0x3d, 0xca);
++ }else if (state->tuner_mtt == 0xE1) {
++ _mt_fe_tn_set_reg(state, 0x3d, 0xfe);
++ } else {
++ return 1;
++ }
++ _mt_fe_tn_set_reg(state, 0x3e, 0x9c);
++ _mt_fe_tn_set_reg(state, 0x3f, 0x34);
++ }
++
++ if (F > 0) {
++ if (state->tuner_mtt == 0xD1) {
++ if ((F == 32) || (F == 16) || (F == 48)) {
++ _mt_fe_tn_set_reg(state, 0x3e, 0xa4);
++ _mt_fe_tn_set_reg(state, 0x3d, 0x4a);
++ _mt_fe_tn_set_reg(state, 0x3f, 0x36);
++ }else {
++ _mt_fe_tn_set_reg(state, 0x3e, 0xa4);
++ _mt_fe_tn_set_reg(state, 0x3d, 0x4a);
++ _mt_fe_tn_set_reg(state, 0x3f, 0x36);
++ }
++ }else if (state->tuner_mtt == 0xE1) {
++ _mt_fe_tn_set_reg(state, 0x3e, 0xa4);
++ _mt_fe_tn_set_reg(state, 0x3d, 0x7e);
++ _mt_fe_tn_set_reg(state, 0x3f, 0x36);
++ _mt_fe_tn_set_reg(state, 0x89, 0x84);
++ _mt_fe_tn_get_reg(state, 0x39, &buf);
++ buf = buf & 0x1f;
++ _mt_fe_tn_set_reg(state, 0x39, buf);
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = buf | 0x02;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++ }else {
++ return 1;
++ }
++ }
++
++ _mt_fe_tn_set_reg(state, 0x41, 0x00);
++ if (state->tuner_mtt == 0xD1) {
++ msleep(5);
++ }else if (state->tuner_mtt == 0xE1) {
++ msleep(2);
++ }else {
++ return 1;
++ }
++ _mt_fe_tn_set_reg(state, 0x41, 0x02);
++ _mt_fe_tn_set_reg(state, 0x30, 0x7f);
++ _mt_fe_tn_set_reg(state, 0x30, 0xff);
++ _mt_fe_tn_set_reg(state, 0x31, 0x80);
++ _mt_fe_tn_set_reg(state, 0x31, 0x00);
++
++ return 0;
++}
++
++static int _mt_fe_tn_set_PLL_freq_tc2800(struct m88dc2800_state *state)
++{
++ u8 buf, buf1;
++ u32 freq_thres_div2_KHz, freq_thres_div3r_KHz, freq_thres_div3_KHz;
++
++ const u32 freq_KHz = state->tuner_freq;
++
++ if (state->tuner_mtt == 0xD1) {
++ _mt_fe_tn_set_reg(state, 0x32, 0xe1);
++ _mt_fe_tn_set_reg(state, 0x33, 0xa6);
++ _mt_fe_tn_set_reg(state, 0x37, 0x7f);
++ _mt_fe_tn_set_reg(state, 0x38, 0x20);
++ _mt_fe_tn_set_reg(state, 0x39, 0x18);
++ _mt_fe_tn_set_reg(state, 0x40, 0x40);
++
++ freq_thres_div2_KHz = 520000;
++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, 0, 0);
++
++ msleep(5);
++ _mt_fe_tn_get_reg(state, 0x3a, &buf);
++ buf1 = buf;
++ buf = buf & 0x03;
++ buf1 = buf1 & 0x01;
++ if ((buf1 == 0) || (buf == 3)) {
++ freq_thres_div2_KHz = 420000;
++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, 0, 0);
++ msleep(5);
++
++ _mt_fe_tn_get_reg(state, 0x3a, &buf);
++ buf = buf & 0x07;
++ if (buf == 5) {
++ freq_thres_div2_KHz = 520000;
++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, 0, 0);
++ msleep(5);
++ }
++ }
++
++ _mt_fe_tn_get_reg(state, 0x38, &buf);
++ _mt_fe_tn_set_reg(state, 0x38, buf);
++
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = buf | 0x10;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++
++ _mt_fe_tn_set_reg(state, 0x30, 0x7f);
++ _mt_fe_tn_set_reg(state, 0x30, 0xff);
++
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = buf & 0xdf;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++ _mt_fe_tn_set_reg(state, 0x40, 0x0);
++
++ _mt_fe_tn_set_reg(state, 0x30, 0x7f);
++ _mt_fe_tn_set_reg(state, 0x30, 0xff);
++ _mt_fe_tn_set_reg(state, 0x31, 0x80);
++ _mt_fe_tn_set_reg(state, 0x31, 0x00);
++ msleep(5);
++
++ _mt_fe_tn_get_reg(state, 0x39, &buf);
++ buf = buf >> 5;
++ if (buf < 5) {
++ _mt_fe_tn_get_reg(state, 0x39, &buf);
++ buf = buf | 0xa0;
++ buf = buf & 0xbf;
++ _mt_fe_tn_set_reg(state, 0x39, buf);
++
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = buf | 0x02;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++ }
++
++ _mt_fe_tn_get_reg(state, 0x37, &buf);
++ if (buf > 0x70) {
++ buf = 0x7f;
++ _mt_fe_tn_set_reg(state, 0x40, 0x40);
++ }
++ _mt_fe_tn_set_reg(state, 0x37, buf);
++
++
++ _mt_fe_tn_get_reg(state, 0x38, &buf);
++ if (buf < 0x0f) {
++ buf = (buf & 0x0f) << 2;
++ buf = buf + 0x0f;
++ _mt_fe_tn_set_reg(state, 0x37, buf);
++ }else if (buf < 0x1f) {
++ buf= buf + 0x0f;
++ _mt_fe_tn_set_reg(state, 0x37, buf);
++ }
++
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = (buf | 0x20) & 0xef;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++
++ _mt_fe_tn_set_reg(state, 0x41, 0x00);
++ msleep(5);
++ _mt_fe_tn_set_reg(state, 0x41, 0x02);
++
++ }else if (state->tuner_mtt == 0xE1){
++ freq_thres_div2_KHz = 580000;
++ freq_thres_div3r_KHz = 500000;
++ freq_thres_div3_KHz = 440000;
++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, freq_thres_div3r_KHz, freq_thres_div3_KHz);
++
++ msleep(3);
++
++ _mt_fe_tn_get_reg(state, 0x38, &buf);
++ _mt_fe_tn_set_reg(state, 0x38, buf);
++
++ _mt_fe_tn_set_reg(state, 0x30, 0x7f);
++ _mt_fe_tn_set_reg(state, 0x30, 0xff);
++ _mt_fe_tn_set_reg(state, 0x31, 0x80);
++ _mt_fe_tn_set_reg(state, 0x31, 0x00);
++ msleep(3);
++ _mt_fe_tn_get_reg(state, 0x38, &buf);
++ _mt_fe_tn_set_reg(state, 0x38, buf);
++
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = buf | 0x10;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++
++ _mt_fe_tn_set_reg(state, 0x30, 0x7f);
++ _mt_fe_tn_set_reg(state, 0x30, 0xff);
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = buf & 0xdf;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++ _mt_fe_tn_set_reg(state, 0x31, 0x80);
++ _mt_fe_tn_set_reg(state, 0x31, 0x00);
++ msleep(3);
++
++ _mt_fe_tn_get_reg(state, 0x37, &buf);
++ _mt_fe_tn_set_reg(state, 0x37, buf);
++ /*
++ if ((freq_KHz == 802000) || (freq_KHz == 826000)) {
++ _mt_fe_tn_set_reg(state, 0x37, 0x5e);
++ }
++ */
++
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = (buf & 0xef) | 0x30;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++
++ _mt_fe_tn_set_reg(state, 0x41, 0x00);
++ msleep(2);
++ _mt_fe_tn_set_reg(state, 0x41, 0x02);
++ } else {
++ return 1;
++ }
++
++ return 0;
++}
++
++static int _mt_fe_tn_set_BB_tc2800(struct m88dc2800_state *state)
++{
++ return 0;
++}
++
++static int _mt_fe_tn_set_appendix_tc2800(struct m88dc2800_state *state)
++{
++ u8 buf;
++ const u32 freq_KHz = state->tuner_freq;
++
++ if (state->tuner_mtt == 0xD1) {
++ if ((freq_KHz == 123000) || (freq_KHz == 147000) || (freq_KHz == 171000)
++ || (freq_KHz == 195000))
++ _mt_fe_tn_set_reg(state, 0x20, 0x1b);
++
++ if ((freq_KHz == 371000) || (freq_KHz == 419000) || (freq_KHz == 610000)
++ || (freq_KHz == 730000) || (freq_KHz == 754000) || (freq_KHz == 826000)) {
++ _mt_fe_tn_get_reg(state, 0x0d, &buf);
++ _mt_fe_tn_set_reg(state, 0x0d, (u8)(buf + 1));
++ }
++
++ if ((freq_KHz == 522000) || (freq_KHz == 578000) || (freq_KHz == 634000)
++ || (freq_KHz == 690000) || (freq_KHz == 834000)) {
++ _mt_fe_tn_get_reg(state, 0x0d, &buf);
++ _mt_fe_tn_set_reg(state, 0x0d, (u8)(buf - 1));
++ }
++ } else if (state->tuner_mtt == 0xE1) {
++ _mt_fe_tn_set_reg(state, 0x20, 0xfc);
++
++ if ((freq_KHz == 123000) || (freq_KHz == 147000) || (freq_KHz == 171000)
++ || (freq_KHz == 195000) || (freq_KHz == 219000) || (freq_KHz == 267000)
++ || (freq_KHz == 291000) || (freq_KHz == 339000) || (freq_KHz == 387000)
++ || (freq_KHz == 435000) || (freq_KHz == 482000) || (freq_KHz == 530000)
++ || (freq_KHz == 722000)
++ || ((state->tuner_custom_cfg == 1) && (freq_KHz == 315000))) {
++ _mt_fe_tn_set_reg(state, 0x20, 0x5c);
++ }
++ }
++ return 0;
++}
++
++static int _mt_fe_tn_set_DAC_tc2800(struct m88dc2800_state *state)
++{
++ u8 buf, tempnumber;
++ s32 N;
++ s32 f1f2number, f1, f2, delta1, Totalnum1;
++ s32 cntT, cntin, NCOI, z0, z1, z2, tmp;
++ u32 fc, fadc, fsd, f2d;
++ u32 FreqTrue108_Hz;
++
++ s32 M = state->tuner_crystal / 4000;
++
++/* const u8 bandwidth = state->tuner_bandwidth; */
++ const u16 DAC_fre = 108;
++ const u32 crystal_KHz = state->tuner_crystal;
++ const u32 DACFreq_KHz = state->tuner_dac;
++
++ const u32 freq_KHz = state->tuner_freq;
++
++ if (state->tuner_mtt == 0xE1) {
++ _mt_fe_tn_get_reg(state, 0x33, &buf);
++ M = buf & 0x0f;
++ if (M == 0)
++ M = 6;
++ }
++
++ _mt_fe_tn_get_reg(state, 0x34, &buf);
++ N = buf & 0x07;
++
++ _mt_fe_tn_get_reg(state, 0x35, &buf);
++ N = (N << 8) + buf;
++
++
++ buf = ((N + 256) * crystal_KHz / M / DAC_fre + 500) / 1000;
++
++ if (state->tuner_mtt == 0xE1) {
++ _mt_fe_tn_set_appendix_tc2800(state);
++
++ if ((freq_KHz == 187000) || (freq_KHz == 195000) || (freq_KHz == 131000)
++ || (freq_KHz == 211000) || (freq_KHz == 219000) || (freq_KHz == 227000)
++ || (freq_KHz == 267000) || (freq_KHz == 299000) || (freq_KHz == 347000)
++ || (freq_KHz == 363000) || (freq_KHz == 395000) || (freq_KHz == 403000)
++ || (freq_KHz == 435000) || (freq_KHz == 482000) || (freq_KHz == 474000)
++ || (freq_KHz == 490000) || (freq_KHz == 610000) || (freq_KHz == 642000)
++ || (freq_KHz == 666000) || (freq_KHz == 722000) || (freq_KHz == 754000)
++ || (((freq_KHz == 379000) || (freq_KHz == 467000) || (freq_KHz == 762000))
++ && (state->tuner_custom_cfg != 1))) {
++ buf = buf + 1;
++ }
++
++ if ((freq_KHz == 123000) || (freq_KHz == 139000) || (freq_KHz == 147000)
++ || (freq_KHz == 171000) || (freq_KHz == 179000) || (freq_KHz == 203000)
++ || (freq_KHz == 235000) || (freq_KHz == 251000) || (freq_KHz == 259000)
++ || (freq_KHz == 283000) || (freq_KHz == 331000) || (freq_KHz == 363000)
++ || (freq_KHz == 371000) || (freq_KHz == 387000) || (freq_KHz == 411000)
++ || (freq_KHz == 427000) || (freq_KHz == 443000) || (freq_KHz == 451000)
++ || (freq_KHz == 459000) || (freq_KHz == 506000) || (freq_KHz == 514000)
++ || (freq_KHz == 538000) || (freq_KHz == 546000) || (freq_KHz == 554000)
++ || (freq_KHz == 562000) || (freq_KHz == 570000) || (freq_KHz == 578000)
++ || (freq_KHz == 602000) || (freq_KHz == 626000) || (freq_KHz == 658000)
++ || (freq_KHz == 690000) || (freq_KHz == 714000) || (freq_KHz == 746000)
++ || (freq_KHz == 522000) || (freq_KHz == 826000) || (freq_KHz == 155000)
++ || (freq_KHz == 530000)
++ || (((freq_KHz == 275000) || (freq_KHz == 355000)) && (state->tuner_custom_cfg != 1))
++ || (((freq_KHz == 467000) || (freq_KHz == 762000) || (freq_KHz == 778000)
++ || (freq_KHz == 818000)) && (state->tuner_custom_cfg == 1))) {
++ buf = buf - 1;
++ }
++ }
++
++ _mt_fe_tn_set_reg(state, 0x0e, buf);
++ _mt_fe_tn_set_reg(state, 0x0d, buf);
++
++ f1f2number = (((DACFreq_KHz * M * buf) / crystal_KHz) << 16) / (N + 256)
++ + (((DACFreq_KHz * M * buf) % crystal_KHz) << 16) / ((N + 256) * crystal_KHz);
++
++
++ _mt_fe_tn_set_reg(state, 0xf1, (u8)((f1f2number & 0xff00) >> 8));
++ _mt_fe_tn_set_reg(state, 0xf2, (u8)(f1f2number & 0x00ff));
++
++ FreqTrue108_Hz = (N + 256) * crystal_KHz / (M * buf) * 1000 + (((N + 256) * crystal_KHz) % (M * buf)) * 1000 / (M * buf);
++
++ f1 = 4096;
++ fc = FreqTrue108_Hz;
++ fadc = fc / 4;
++ fsd = 27000000;
++ f2d = state->tuner_bandwidth * 1000 / 2 -150;
++ f2 = (fsd / 250) * f2d / ((fc + 500) / 1000);
++ delta1 = ((f1 - f2) << 15) / f2;
++
++ Totalnum1 = ((f1 - f2) << 15) - delta1 * f2;
++
++ cntT = f2;
++ cntin = Totalnum1;
++ NCOI = delta1;
++
++ z0 = cntin;
++ z1 = cntT;
++ z2 = NCOI;
++
++ tempnumber = (z0 & 0xff00) >> 8;
++ _mt_fe_tn_set_reg(state, 0xc9, (u8)(tempnumber & 0x0f));
++ tempnumber = (z0 & 0xff);
++ _mt_fe_tn_set_reg(state, 0xca, tempnumber);
++
++ tempnumber = (z1 & 0xff00) >> 8;
++ _mt_fe_tn_set_reg(state, 0xcb, tempnumber);
++ tempnumber = (z1 & 0xff);
++ _mt_fe_tn_set_reg(state, 0xcc, tempnumber);
++
++ tempnumber = (z2 & 0xff00) >> 8;
++ _mt_fe_tn_set_reg(state, 0xcd, tempnumber);
++ tempnumber = (z2 & 0xff);
++ _mt_fe_tn_set_reg(state, 0xce, tempnumber);
++
++ tmp = f1;
++ f1 = f2;
++ f2 = tmp / 2;
++ delta1 = ((f1 - f2) << 15) / f2;
++ Totalnum1 = ((f1 - f2) << 15) - delta1 * f2;
++ NCOI = (f1 << 15) / f2 - (1 << 15);
++ cntT = f2;
++ cntin = Totalnum1;
++ z0 = cntin;
++ z1 = cntT;
++ z2 = NCOI;
++
++ tempnumber = (z0 & 0xff00) >> 8;
++ _mt_fe_tn_set_reg(state, 0xd9, (u8)(tempnumber & 0x0f));
++ tempnumber = (z0 & 0xff);
++ _mt_fe_tn_set_reg(state, 0xda, tempnumber);
++
++ tempnumber = (z1 & 0xff00) >> 8;
++ _mt_fe_tn_set_reg(state, 0xdb, tempnumber);
++ tempnumber = (z1 & 0xff);
++ _mt_fe_tn_set_reg(state, 0xdc, tempnumber);
++
++ tempnumber = (z2 & 0xff00) >> 8;
++ _mt_fe_tn_set_reg(state, 0xdd, tempnumber);
++ tempnumber = (z2 & 0xff);
++ _mt_fe_tn_set_reg(state, 0xde, tempnumber);
++
++ return 0;
++}
++
++static int _mt_fe_tn_preset_tc2800(struct m88dc2800_state *state)
++{
++ if (state->tuner_mtt == 0xD1) {
++ _mt_fe_tn_set_reg(state, 0x19, 0x4a);
++ _mt_fe_tn_set_reg(state, 0x1b, 0x4b);
++
++ _mt_fe_tn_set_reg(state, 0x04, 0x04);
++ _mt_fe_tn_set_reg(state, 0x17, 0x0d);
++ _mt_fe_tn_set_reg(state, 0x62, 0x6c);
++ _mt_fe_tn_set_reg(state, 0x63, 0xf4);
++ _mt_fe_tn_set_reg(state, 0x1f, 0x0e);
++ _mt_fe_tn_set_reg(state, 0x6b, 0xf4);
++ _mt_fe_tn_set_reg(state, 0x14, 0x01);
++ _mt_fe_tn_set_reg(state, 0x5a, 0x75);
++ _mt_fe_tn_set_reg(state, 0x66, 0x74);
++ _mt_fe_tn_set_reg(state, 0x72, 0xe0);
++ _mt_fe_tn_set_reg(state, 0x70, 0x07);
++ _mt_fe_tn_set_reg(state, 0x15, 0x7b);
++ _mt_fe_tn_set_reg(state, 0x55, 0x71);
++
++ _mt_fe_tn_set_reg(state, 0x75, 0x55);
++ _mt_fe_tn_set_reg(state, 0x76, 0xac);
++ _mt_fe_tn_set_reg(state, 0x77, 0x6c);
++ _mt_fe_tn_set_reg(state, 0x78, 0x8b);
++ _mt_fe_tn_set_reg(state, 0x79, 0x42);
++ _mt_fe_tn_set_reg(state, 0x7a, 0xd2);
++
++ _mt_fe_tn_set_reg(state, 0x81, 0x01);
++ _mt_fe_tn_set_reg(state, 0x82, 0x00);
++ _mt_fe_tn_set_reg(state, 0x82, 0x02);
++ _mt_fe_tn_set_reg(state, 0x82, 0x04);
++ _mt_fe_tn_set_reg(state, 0x82, 0x06);
++ _mt_fe_tn_set_reg(state, 0x82, 0x08);
++ _mt_fe_tn_set_reg(state, 0x82, 0x09);
++ _mt_fe_tn_set_reg(state, 0x82, 0x29);
++ _mt_fe_tn_set_reg(state, 0x82, 0x49);
++ _mt_fe_tn_set_reg(state, 0x82, 0x58);
++ _mt_fe_tn_set_reg(state, 0x82, 0x59);
++ _mt_fe_tn_set_reg(state, 0x82, 0x98);
++ _mt_fe_tn_set_reg(state, 0x82, 0x99);
++
++
++ _mt_fe_tn_set_reg(state, 0x10, 0x05);
++ _mt_fe_tn_set_reg(state, 0x10, 0x0d);
++ _mt_fe_tn_set_reg(state, 0x11, 0x95);
++ _mt_fe_tn_set_reg(state, 0x11, 0x9d);
++
++
++ if (state->tuner_loopthrough != 0) {
++ _mt_fe_tn_set_reg(state, 0x67, 0x25);
++ } else {
++ _mt_fe_tn_set_reg(state, 0x67, 0x05);
++ }
++ } else if (state->tuner_mtt == 0xE1) {
++ _mt_fe_tn_set_reg(state, 0x1b, 0x47);
++ if(state->tuner_mode == 0) // DVB-C
++ {
++ _mt_fe_tn_set_reg(state, 0x66, 0x74);
++ _mt_fe_tn_set_reg(state, 0x62, 0x2c);
++ _mt_fe_tn_set_reg(state, 0x63, 0x54);
++ _mt_fe_tn_set_reg(state, 0x68, 0x0b);
++ _mt_fe_tn_set_reg(state, 0x14, 0x00);
++ }
++ else // CTTB
++ {
++ _mt_fe_tn_set_reg(state, 0x66, 0x74);
++ _mt_fe_tn_set_reg(state, 0x62, 0x0c);
++ _mt_fe_tn_set_reg(state, 0x63, 0x54);
++ _mt_fe_tn_set_reg(state, 0x68, 0x0b);
++ _mt_fe_tn_set_reg(state, 0x14, 0x05);
++ }
++ _mt_fe_tn_set_reg(state, 0x6f, 0x00);
++ _mt_fe_tn_set_reg(state, 0x84, 0x04);
++ _mt_fe_tn_set_reg(state, 0x5e, 0xbe);
++ _mt_fe_tn_set_reg(state, 0x87, 0x07);
++ _mt_fe_tn_set_reg(state, 0x8a, 0x1f);
++ _mt_fe_tn_set_reg(state, 0x8b, 0x1f);
++ _mt_fe_tn_set_reg(state, 0x88, 0x30);
++ _mt_fe_tn_set_reg(state, 0x58, 0x34);
++ _mt_fe_tn_set_reg(state, 0x61, 0x8c);
++ _mt_fe_tn_set_reg(state, 0x6a, 0x42);
++ }
++ return 0;
++}
++
++static int mt_fe_tn_wakeup_tc2800(struct m88dc2800_state *state)
++{
++ _mt_fe_tn_set_reg(state, 0x16, 0xb1);
++ _mt_fe_tn_set_reg(state, 0x09, 0x7d);
++ return 0;
++}
++
++
++static int mt_fe_tn_sleep_tc2800(struct m88dc2800_state *state)
++{
++ _mt_fe_tn_set_reg(state, 0x16, 0xb0);
++ _mt_fe_tn_set_reg(state, 0x09, 0x6d);
++ return 0;
++}
++
++static int mt_fe_tn_init_tc2800(struct m88dc2800_state *state)
++{
++ if (state->tuner_init_OK != 1) {
++ state->tuner_dev_addr = 0x61; /* TUNER_I2C_ADDR_TC2800 */
++ state->tuner_freq = 650000;
++ state->tuner_qam = 0;
++ state->tuner_mode = 0; // 0: DVB-C, 1: CTTB
++
++ state->tuner_bandwidth = 8;
++ state->tuner_loopthrough = 0;
++ state->tuner_crystal = 24000;
++ state->tuner_dac = 7200;
++ state->tuner_mtt = 0x00;
++ state->tuner_custom_cfg = 0;
++ state->tuner_version = 30022; /* Driver version number */
++ state->tuner_time = 12092611;
++ state->tuner_init_OK = 1;
++ }
++
++ _mt_fe_tn_set_reg(state, 0x2b, 0x46);
++ _mt_fe_tn_set_reg(state, 0x2c, 0x75);
++
++ if (state->tuner_mtt == 0x00) {
++ u8 tmp = 0;
++ _mt_fe_tn_get_reg(state, 0x01, &tmp);
++ printk("m88dc2800: tuner id = 0x%02x ", tmp);
++ switch(tmp) {
++ case 0x0d:
++ state->tuner_mtt = 0xD1;
++ break;
++ case 0x8e:
++ default:
++ state->tuner_mtt = 0xE1;
++ break;
++ }
++ }
++ return 0;
++}
++
++static int mt_fe_tn_set_freq_tc2800(struct m88dc2800_state *state, u32 freq_KHz)
++{
++ u8 buf;
++ u8 buf1;
++
++ mt_fe_tn_init_tc2800(state);
++
++ state->tuner_freq = freq_KHz;
++
++ if (freq_KHz > 500000)
++ _mt_fe_tn_set_reg(state, 0x21, 0xb9);
++ else
++ _mt_fe_tn_set_reg(state, 0x21, 0x99);
++
++ mt_fe_tn_wakeup_tc2800(state);
++
++ _mt_fe_tn_set_reg(state, 0x05, 0x7f);
++ _mt_fe_tn_set_reg(state, 0x06, 0xf8);
++
++ _mt_fe_tn_set_RF_front_tc2800(state);
++ _mt_fe_tn_set_PLL_freq_tc2800(state);
++ _mt_fe_tn_set_DAC_tc2800(state);
++ _mt_fe_tn_set_BB_tc2800(state);
++ _mt_fe_tn_preset_tc2800(state);
++
++ _mt_fe_tn_set_reg(state, 0x05, 0x00);
++ _mt_fe_tn_set_reg(state, 0x06, 0x00);
++
++ if (state->tuner_mtt == 0xD1) {
++ _mt_fe_tn_set_reg(state, 0x00, 0x01);
++ _mt_fe_tn_set_reg(state, 0x00, 0x00);
++
++ msleep(5);
++ _mt_fe_tn_set_reg(state, 0x41, 0x00);
++ msleep(5);
++ _mt_fe_tn_set_reg(state, 0x41, 0x02);
++
++ _mt_fe_tn_get_reg(state, 0x69, &buf1);
++ buf1 = buf1 & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x61, &buf);
++ buf = buf & 0x0f;
++ if (buf == 0x0c)
++ {
++ _mt_fe_tn_set_reg(state, 0x6a, 0x59);
++ }
++
++ if(buf1 > 0x02)
++ {
++ if (freq_KHz > 600000)
++ _mt_fe_tn_set_reg(state, 0x66, 0x44);
++ else if (freq_KHz > 500000)
++ _mt_fe_tn_set_reg(state, 0x66, 0x64);
++ else
++ _mt_fe_tn_set_reg(state, 0x66, 0x74);
++ }
++
++ if (buf1 < 0x03)
++ {
++ if (freq_KHz > 800000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x64);
++ else if (freq_KHz > 600000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++ else if (freq_KHz > 500000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++ else if (freq_KHz > 300000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x43);
++ else if (freq_KHz > 220000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++ else if (freq_KHz > 110000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x14);
++ else
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++
++ msleep(5);
++ }
++ else if (buf < 0x0c)
++ {
++ if (freq_KHz > 800000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x14);
++ else if (freq_KHz >600000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x14);
++ else if (freq_KHz > 500000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x34);
++ else if (freq_KHz > 300000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x43);
++ else if (freq_KHz > 220000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++ else if (freq_KHz > 110000)
++ _mt_fe_tn_set_reg(state, 0x87, 0x14);
++ else
++ _mt_fe_tn_set_reg(state, 0x87, 0x54);
++
++ msleep(5);
++ }
++ } else if ((state->tuner_mtt == 0xE1)) {
++ _mt_fe_tn_set_reg(state, 0x00, 0x01);
++ _mt_fe_tn_set_reg(state, 0x00, 0x00);
++
++ msleep(20);
++
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = (buf & 0xef) | 0x28;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++
++ msleep(50);
++ _mt_fe_tn_get_reg(state, 0x38, &buf);
++ _mt_fe_tn_set_reg(state, 0x38, buf);
++ _mt_fe_tn_get_reg(state, 0x32, &buf);
++ buf = (buf & 0xf7)| 0x10 ;
++ _mt_fe_tn_set_reg(state, 0x32, buf);
++
++ msleep(10);
++
++ _mt_fe_tn_get_reg(state, 0x69, &buf);
++ buf = buf & 0x03;
++ _mt_fe_tn_set_reg(state, 0x2a, buf);
++
++ if(buf > 0)
++ {
++ msleep(20);
++ _mt_fe_tn_get_reg(state, 0x84, &buf);
++ buf = buf & 0x1f;
++ _mt_fe_tn_set_reg(state, 0x68, 0x0a);
++ _mt_fe_tn_get_reg(state, 0x88, &buf1);
++ buf1 = buf1 & 0x1f;
++ if(buf <= buf1)
++ _mt_fe_tn_set_reg(state, 0x66, 0x44);
++ else
++ _mt_fe_tn_set_reg(state, 0x66, 0x74);
++ }
++ else
++ {
++ if (freq_KHz <= 600000)
++ {
++ _mt_fe_tn_set_reg(state, 0x68, 0x0c);
++ }
++ else
++ {
++ _mt_fe_tn_set_reg(state, 0x68, 0x0e);
++ }
++ _mt_fe_tn_set_reg(state, 0x30, 0xfb);
++ _mt_fe_tn_set_reg(state, 0x30, 0xff);
++ _mt_fe_tn_set_reg(state, 0x31, 0x04);
++ _mt_fe_tn_set_reg(state, 0x31, 0x00);
++ }
++ if(state->tuner_loopthrough != 0) {
++ _mt_fe_tn_get_reg(state, 0x28, &buf);
++ if (buf == 0) {
++ _mt_fe_tn_set_reg(state, 0x28, 0xff);
++ _mt_fe_tn_get_reg(state, 0x61, &buf);
++ buf = buf & 0x0f;
++ if(buf > 9)
++ _mt_fe_tn_set_reg(state, 0x67, 0x74);
++ else if (buf >6)
++ _mt_fe_tn_set_reg(state, 0x67, 0x64);
++ else if (buf >3)
++ _mt_fe_tn_set_reg(state, 0x67, 0x54);
++ else
++ _mt_fe_tn_set_reg(state, 0x67, 0x44);
++ }
++ } else {
++ _mt_fe_tn_set_reg(state, 0x67, 0x34);
++ }
++ } else {
++ return 1;
++ }
++ return 0;
++}
++
++/*
++static int mt_fe_tn_set_BB_filter_band_tc2800(struct m88dc2800_state *state, u8 bandwidth)
++{
++ u8 buf, tmp;
++
++ _mt_fe_tn_get_reg(state, 0x53, &tmp);
++
++ if (bandwidth == 6)
++ buf = 0x01 << 1;
++ else if (bandwidth == 7)
++ buf = 0x02 << 1;
++ else if (bandwidth == 8)
++ buf = 0x04 << 1;
++ else
++ buf = 0x04 << 1;
++
++ tmp &= 0xf1;
++ tmp |= buf;
++ _mt_fe_tn_set_reg(state, 0x53, tmp);
++ state->tuner_bandwidth = bandwidth;
++ return 0;
++}
++*/
++
++/*static s64 mt_fe_tn_get_signal_strength_tc2800(struct m88dc2800_state *state)*/
++static s32 mt_fe_tn_get_signal_strength_tc2800(struct m88dc2800_state *state)
++{
++ /*s64 level = -107;*/
++ s32 level = -107;
++ s32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
++ s32 val1, val2, val;
++ s32 result2, result3, result4, result5, result6;
++ s32 append;
++ u8 tmp;
++ s32 freq_KHz = (s32)state->tuner_freq;
++
++ if (state->tuner_mtt == 0xD1) {
++ _mt_fe_tn_get_reg(state, 0x61, &tmp);
++ tmp1 = tmp & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x69, &tmp);
++ tmp2 = tmp & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x73, &tmp);
++ tmp3 = tmp & 0x07;
++
++ _mt_fe_tn_get_reg(state, 0x7c, &tmp);
++ tmp4 = (tmp >> 4) & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x7b, &tmp);
++ tmp5 = tmp & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x7f, &tmp);
++ tmp6 = (tmp >> 5) & 0x01;
++
++ if (tmp1 > 6) {
++ val1 = 0;
++ if (freq_KHz <= 200000) {
++ val2 = (tmp1 - 6) * 267;
++ } else if (freq_KHz <= 600000) {
++ val2 = (tmp1 - 6) * 280;
++ } else {
++ val2 = (tmp1 - 6) * 290;
++ }
++ val = val1 + val2;
++ } else {
++ if (tmp1 == 0) {
++ val1 = -550;
++ } else {
++ val1 = 0;
++ }
++ if ((tmp1 < 4) && (freq_KHz >= 506000)) {
++ val1 = -850;
++ }
++ val2 = 0;
++ val = val1 + val2;
++ }
++
++ if (freq_KHz <= 95000) {
++ result2 = tmp2 * 289;
++ } else if (freq_KHz <= 155000) {
++ result2 = tmp2 * 278;
++ } else if (freq_KHz <= 245000) {
++ result2 = tmp2 * 267;
++ } else if (freq_KHz <= 305000) {
++ result2 = tmp2 * 256;
++ } else if (freq_KHz <= 335000) {
++ result2 = tmp2 * 244;
++ } else if (freq_KHz <= 425000) {
++ result2 = tmp2 * 233;
++ } else if (freq_KHz <= 575000) {
++ result2 = tmp2 * 222;
++ } else if (freq_KHz <= 665000) {
++ result2 = tmp2 * 211;
++ } else {
++ result2 = tmp2 * 200;
++ }
++ result3 = (6 - tmp3) * 100;
++ result4 = 300 * tmp4;
++ result5 = 50 * tmp5;
++ result6 = 300 * tmp6;
++ if (freq_KHz < 105000) {
++ append = -450;
++ } else if (freq_KHz <= 227000) {
++ append = -4 * (freq_KHz / 1000 - 100) + 150;
++ } else if (freq_KHz <= 305000) {
++ append = -4 * (freq_KHz / 1000 - 100);
++ } else if (freq_KHz <= 419000) {
++ append = 500 - 40 * (freq_KHz / 1000 - 300) / 17 + 130;
++ } else if (freq_KHz <= 640000) {
++ append = 500 - 40 * (freq_KHz / 1000 - 300) / 17;
++ } else {
++ append = -500;
++ }
++ level = append - (val + result2 + result3 + result4 + result5 + result6);
++ level /= 100;
++ } else if (state->tuner_mtt == 0xE1) {
++ _mt_fe_tn_get_reg(state, 0x61, &tmp);
++ tmp1 = tmp & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x84, &tmp);
++ tmp2 = tmp & 0x1f;
++
++ _mt_fe_tn_get_reg(state, 0x69, &tmp);
++ tmp3 = tmp & 0x03;
++
++ _mt_fe_tn_get_reg(state, 0x73, &tmp);
++ tmp4 = tmp & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x7c, &tmp);
++ tmp5 = (tmp >> 4) & 0x0f;
++
++ _mt_fe_tn_get_reg(state, 0x7b, &tmp);
++ tmp6 = tmp & 0x0f;
++
++ if (freq_KHz < 151000) {
++ result2 = (1150 - freq_KHz / 100) * 163 / 33 + 4230;
++ result3 = (1150 - freq_KHz / 100) * 115 / 33 + 1850;
++ result4 = -3676 * (freq_KHz / 1000) / 100 + 6115;
++ } else if (freq_KHz < 257000) {
++ result2 = (1540 - freq_KHz / 100) * 11 / 4 + 3870;
++ result3 = (1540 - freq_KHz / 100) * 205 / 96 + 2100;
++ result4 = -21 * freq_KHz / 1000 + 5084;
++ } else if (freq_KHz < 305000) {
++ result2 = (2620 - freq_KHz / 100) * 5 / 3 + 2770;
++ result3 = (2620 - freq_KHz / 100) * 10 / 7 + 1700;
++ result4 = 650;
++ } else if (freq_KHz < 449000) {
++ result2 = (307 - freq_KHz / 1000) * 82 / 27 + 11270;
++ result3 = (3100 - freq_KHz / 100) * 5 / 3 + 10000;
++ result4 = 134 * freq_KHz / 10000 + 11875;
++ } else {
++ result2 = (307 - freq_KHz / 1000) * 82 / 27 + 11270;
++ result3 = 8400;
++ result4 = 5300;
++ }
++
++ if (tmp1 > 6) {
++ val1 = result2;
++ val2 = 2900;
++ val = 500;
++ } else if (tmp1 > 0) {
++ val1 = result3;
++ val2 = 2700;
++ val = 500;
++ } else {
++ val1 = result4;
++ val2 = 2700;
++ val = 400;
++ }
++ level = val1 - (val2 * tmp1 + 500 * tmp2 + 3000 * tmp3 - 500 * tmp4 + 3000 * tmp5 + val * tmp6) - 1000;
++ level /= 1000;
++ }
++ return level;
++}
++
++/* m88dc2800 operation functions */
++u8 M88DC2000GetLock(struct m88dc2800_state *state)
++{
++ u8 u8ret = 0;
++
++ if (ReadReg(state, 0x80) < 0x06) {
++ if ((ReadReg(state, 0xdf)&0x80)==0x80
++ && (ReadReg(state, 0x91)&0x23)==0x03
++ && (ReadReg(state, 0x43)&0x08)==0x08)
++ u8ret = 1;
++ else
++ u8ret = 0;
++ } else {
++ if ((ReadReg(state, 0x85)&0x08)==0x08)
++ u8ret = 1;
++ else
++ u8ret = 0;
++ }
++ printk("%s, lock=%d\n", __func__,u8ret);
++ return u8ret;
++}
++
++static int M88DC2000SetTsType(struct m88dc2800_state *state, u8 type)
++{
++ u8 regC2H;
++
++ if (type == 3) {
++ WriteReg(state, 0x84, 0x6A);
++ WriteReg(state, 0xC0, 0x43);
++ WriteReg(state, 0xE2, 0x06);
++ regC2H = ReadReg(state, 0xC2);
++ regC2H &= 0xC0;
++ regC2H |= 0x1B;
++ WriteReg(state, 0xC2, regC2H);
++ WriteReg(state, 0xC1, 0x60); /* common interface */
++ } else if (type == 1) {
++ WriteReg(state, 0x84, 0x6A);
++ WriteReg(state, 0xC0, 0x47); /* serial format */
++ WriteReg(state, 0xE2, 0x02);
++ regC2H = ReadReg(state, 0xC2);
++ regC2H &= 0xC7;
++ WriteReg(state, 0xC2, regC2H);
++ WriteReg(state, 0xC1, 0x00);
++ } else {
++ WriteReg(state, 0x84, 0x6C);
++ WriteReg(state, 0xC0, 0x43); /* parallel format */
++ WriteReg(state, 0xE2, 0x06);
++ regC2H = ReadReg(state, 0xC2);
++ regC2H &= 0xC7;
++ WriteReg(state, 0xC2, regC2H);
++ WriteReg(state, 0xC1, 0x00);
++ }
++ return 0;
++}
++
++static int M88DC2000RegInitial_TC2800(struct m88dc2800_state *state)
++{
++ u8 RegE3H, RegE4H;
++
++ WriteReg(state, 0x00, 0x48);
++ WriteReg(state, 0x01, 0x09);
++ WriteReg(state, 0xFB, 0x0A);
++ WriteReg(state, 0xFC, 0x0B);
++ WriteReg(state, 0x02, 0x0B);
++ WriteReg(state, 0x03, 0x18);
++ WriteReg(state, 0x05, 0x0D);
++ WriteReg(state, 0x36, 0x80);
++ WriteReg(state, 0x43, 0x40);
++ WriteReg(state, 0x55, 0x7A);
++ WriteReg(state, 0x56, 0xD9);
++ WriteReg(state, 0x57, 0xDF);
++ WriteReg(state, 0x58, 0x39);
++ WriteReg(state, 0x5A, 0x00);
++ WriteReg(state, 0x5C, 0x71);
++ WriteReg(state, 0x5D, 0x23);
++ WriteReg(state, 0x86, 0x40);
++ WriteReg(state, 0xF9, 0x08);
++ WriteReg(state, 0x61, 0x40);
++ WriteReg(state, 0x62, 0x0A);
++ WriteReg(state, 0x90, 0x06);
++ WriteReg(state, 0xDE, 0x00);
++ WriteReg(state, 0xA0, 0x03);
++ WriteReg(state, 0xDF, 0x81);
++ WriteReg(state, 0xFA, 0x40);
++ WriteReg(state, 0x37, 0x10);
++ WriteReg(state, 0xF0, 0x40);
++ WriteReg(state, 0xF2, 0x9C);
++ WriteReg(state, 0xF3, 0x40);
++
++ RegE3H = ReadReg(state, 0xE3);
++ RegE4H = ReadReg(state, 0xE4);
++ if (((RegE3H & 0xC0) == 0x00) && ((RegE4H & 0xC0) == 0x00)) {
++ WriteReg(state, 0x30, 0xFF);
++ WriteReg(state, 0x31, 0x00);
++ WriteReg(state, 0x32, 0x00);
++ WriteReg(state, 0x33, 0x00);
++ WriteReg(state, 0x35, 0x32);
++ WriteReg(state, 0x40, 0x00);
++ WriteReg(state, 0x41, 0x10);
++ WriteReg(state, 0xF1, 0x02);
++ WriteReg(state, 0xF4, 0x04);
++ WriteReg(state, 0xF5, 0x00);
++ WriteReg(state, 0x42, 0x14);
++ WriteReg(state, 0xE1, 0x25);
++ } else if (((RegE3H & 0xC0) == 0x80) && ((RegE4H & 0xC0) == 0x40)) {
++ WriteReg(state, 0x30, 0xFF);
++ WriteReg(state, 0x31, 0x00);
++ WriteReg(state, 0x32, 0x00);
++ WriteReg(state, 0x33, 0x00);
++ WriteReg(state, 0x35, 0x32);
++ WriteReg(state, 0x39, 0x00);
++ WriteReg(state, 0x3A, 0x00);
++ WriteReg(state, 0x40, 0x00);
++ WriteReg(state, 0x41, 0x10);
++ WriteReg(state, 0xF1, 0x00);
++ WriteReg(state, 0xF4, 0x00);
++ WriteReg(state, 0xF5, 0x40);
++ WriteReg(state, 0x42, 0x14);
++ WriteReg(state, 0xE1, 0x25);
++ } else if ((RegE3H == 0x80 || RegE3H == 0x81) && (RegE4H == 0x80 || RegE4H == 0x81)) {
++ WriteReg(state, 0x30, 0xFF);
++ WriteReg(state, 0x31, 0x00);
++ WriteReg(state, 0x32, 0x00);
++ WriteReg(state, 0x33, 0x00);
++ WriteReg(state, 0x35, 0x32);
++ WriteReg(state, 0x39, 0x00);
++ WriteReg(state, 0x3A, 0x00);
++ WriteReg(state, 0xF1, 0x00);
++ WriteReg(state, 0xF4, 0x00);
++ WriteReg(state, 0xF5, 0x40);
++ WriteReg(state, 0x42, 0x24);
++ WriteReg(state, 0xE1, 0x25);
++
++ WriteReg(state, 0x92, 0x7F);
++ WriteReg(state, 0x93, 0x91);
++ WriteReg(state, 0x95, 0x00);
++ WriteReg(state, 0x2B, 0x33);
++ WriteReg(state, 0x2A, 0x2A);
++ WriteReg(state, 0x2E, 0x80);
++ WriteReg(state, 0x25, 0x25);
++ WriteReg(state, 0x2D, 0xFF);
++ WriteReg(state, 0x26, 0xFF);
++ WriteReg(state, 0x27, 0x00);
++ WriteReg(state, 0x24, 0x25);
++ WriteReg(state, 0xA4, 0xFF);
++ WriteReg(state, 0xA3, 0x0D);
++ } else {
++ WriteReg(state, 0x30, 0xFF);
++ WriteReg(state, 0x31, 0x00);
++ WriteReg(state, 0x32, 0x00);
++ WriteReg(state, 0x33, 0x00);
++ WriteReg(state, 0x35, 0x32);
++ WriteReg(state, 0x39, 0x00);
++ WriteReg(state, 0x3A, 0x00);
++ WriteReg(state, 0xF1, 0x00);
++ WriteReg(state, 0xF4, 0x00);
++ WriteReg(state, 0xF5, 0x40);
++ WriteReg(state, 0x42, 0x24);
++ WriteReg(state, 0xE1, 0x27);
++
++ WriteReg(state, 0x92, 0x7F);
++ WriteReg(state, 0x93, 0x91);
++ WriteReg(state, 0x95, 0x00);
++ WriteReg(state, 0x2B, 0x33);
++ WriteReg(state, 0x2A, 0x2A);
++ WriteReg(state, 0x2E, 0x80);
++ WriteReg(state, 0x25, 0x25);
++ WriteReg(state, 0x2D, 0xFF);
++ WriteReg(state, 0x26, 0xFF);
++ WriteReg(state, 0x27, 0x00);
++ WriteReg(state, 0x24, 0x25);
++ WriteReg(state, 0xA4, 0xFF);
++ WriteReg(state, 0xA3, 0x10);
++ }
++
++ WriteReg(state, 0xF6, 0x4E);
++ WriteReg(state, 0xF7, 0x20);
++ WriteReg(state, 0x89, 0x02);
++ WriteReg(state, 0x14, 0x08);
++ WriteReg(state, 0x6F, 0x0D);
++ WriteReg(state, 0x10, 0xFF);
++ WriteReg(state, 0x11, 0x00);
++ WriteReg(state, 0x12, 0x30);
++ WriteReg(state, 0x13, 0x23);
++ WriteReg(state, 0x60, 0x00);
++ WriteReg(state, 0x69, 0x00);
++ WriteReg(state, 0x6A, 0x03);
++ WriteReg(state, 0xE0, 0x75);
++ WriteReg(state, 0x8D, 0x29);
++ WriteReg(state, 0x4E, 0xD8);
++ WriteReg(state, 0x88, 0x80);
++ WriteReg(state, 0x52, 0x79);
++ WriteReg(state, 0x53, 0x03);
++ WriteReg(state, 0x59, 0x30);
++ WriteReg(state, 0x5E, 0x02);
++ WriteReg(state, 0x5F, 0x0F);
++ WriteReg(state, 0x71, 0x03);
++ WriteReg(state, 0x72, 0x12);
++ WriteReg(state, 0x73, 0x12);
++
++ return 0;
++}
++
++static int M88DC2000AutoTSClock_P(struct m88dc2800_state *state, u32 sym, u16 qam)
++{
++ u32 dataRate;
++ u8 clk_div, value;
++ printk("m88dc2800: M88DC2000AutoTSClock_P, symrate=%d qam=%d\n",sym,qam);
++ switch(qam)
++ {
++ case 16:
++ dataRate = 4;
++ break;
++ case 32:
++ dataRate = 5;
++ break;
++ case 128:
++ dataRate = 7;
++ break;
++ case 256:
++ dataRate = 8;
++ break;
++ case 64:
++ default:
++ dataRate = 6;
++ break;
++ }
++ dataRate *= sym * 105;
++ dataRate /= 800;
++
++ if(dataRate <= 4115)
++ clk_div = 0x05;
++ else if(dataRate <= 4800)
++ clk_div = 0x04;
++ else if(dataRate <= 5760)
++ clk_div = 0x03;
++ else if(dataRate <= 7200)
++ clk_div = 0x02;
++ else if(dataRate <= 9600)
++ clk_div = 0x01;
++ else
++ clk_div = 0x00;
++
++ value = ReadReg(state, 0xC2);
++ value &= 0xc0;
++ value |= clk_div;
++ WriteReg(state, 0xC2, value);
++ return 0;
++}
++
++static int M88DC2000AutoTSClock_C(struct m88dc2800_state *state, u32 sym, u16 qam)
++{
++ u32 dataRate;
++ u8 clk_div, value;
++ printk("m88dc2800: M88DC2000AutoTSClock_C, symrate=%d qam=%d\n",sym,qam);
++ switch(qam)
++ {
++ case 16:
++ dataRate = 4;
++ break;
++ case 32:
++ dataRate = 5;
++ break;
++ case 128:
++ dataRate = 7;
++ break;
++ case 256:
++ dataRate = 8;
++ break;
++ case 64:
++ default:
++ dataRate = 6;
++ break;
++ }
++ dataRate *= sym * 105;
++ dataRate /= 800;
++
++ if(dataRate <= 4115)
++ clk_div = 0x3F;
++ else if(dataRate <= 4800)
++ clk_div = 0x36;
++ else if(dataRate <= 5760)
++ clk_div = 0x2D;
++ else if(dataRate <= 7200)
++ clk_div = 0x24;
++ else if(dataRate <= 9600)
++ clk_div = 0x1B;
++ else
++ clk_div = 0x12;
++
++ value = ReadReg(state, 0xC2);
++ value &= 0xc0;
++ value |= clk_div;
++ WriteReg(state, 0xC2, value);
++ return 0;
++}
++
++static int M88DC2000SetTxMode(struct m88dc2800_state *state, u8 inverted, u8 j83)
++{
++ u8 value = 0;
++ if (inverted)
++ value |= 0x08; /* spectrum inverted */
++ if (j83)
++ value |= 0x01; /* J83C */
++ WriteReg(state, 0x83, value);
++ return 0;
++}
++
++static int M88DC2000SoftReset(struct m88dc2800_state *state)
++{
++ WriteReg(state, 0x80, 0x01);
++ WriteReg(state, 0x82, 0x00);
++ msleep(1);
++ WriteReg(state, 0x80, 0x00);
++ return 0;
++}
++
++static int M88DC2000SetSym(struct m88dc2800_state *state, u32 sym, u32 xtal)
++{
++ u8 value;
++ u8 reg6FH, reg12H;
++ u64 fValue;
++ u32 dwValue;
++ printk("%s, sym=%d, xtal=%d\n", __func__, sym, xtal);
++
++ fValue = 4294967296 * (sym + 10);
++ do_div(fValue, xtal);
++/* fValue = 4294967296 * (sym + 10) / xtal; */
++
++ dwValue = (u32)fValue;
++ printk("%s, fvalue1=%x\n", __func__, dwValue);
++
++ WriteReg(state, 0x58, (u8)((dwValue >> 24) & 0xff));
++ WriteReg(state, 0x57, (u8)((dwValue >> 16) & 0xff));
++ WriteReg(state, 0x56, (u8)((dwValue >> 8) & 0xff));
++ WriteReg(state, 0x55, (u8)((dwValue >> 0) & 0xff));
++
++/* fValue = 2048 * xtal / sym; */
++ fValue = 2048 * xtal;
++ do_div(fValue, sym);
++
++ dwValue = (u32)fValue;
++ printk("%s, fvalue2=%x\n", __func__, dwValue);
++ WriteReg(state, 0x5D, (u8)((dwValue >> 8) & 0xff));
++ WriteReg(state, 0x5C, (u8)((dwValue >> 0) & 0xff));
++
++ value = ReadReg(state, 0x5A);
++ if (((dwValue >> 16) & 0x0001) == 0)
++ value &= 0x7F;
++ else
++ value |= 0x80;
++ WriteReg(state, 0x5A, value);
++
++ value = ReadReg(state, 0x89);
++ if (sym <= 1800)
++ value |= 0x01;
++ else
++ value &= 0xFE;
++ WriteReg(state, 0x89, value);
++
++ if (sym >= 6700){
++ reg6FH = 0x0D;
++ reg12H = 0x30;
++ } else if (sym >= 4000) {
++ fValue = 22 * 4096 / sym;
++ reg6FH = (u8)fValue;
++ reg12H = 0x30;
++ } else if (sym >= 2000) {
++ fValue = 14 * 4096 / sym;
++ reg6FH = (u8)fValue;
++ reg12H = 0x20;
++ } else {
++ fValue = 7 * 4096 / sym;
++ reg6FH = (u8)fValue;
++ reg12H = 0x10;
++ }
++ WriteReg(state, 0x6F, reg6FH);
++ WriteReg(state, 0x12, reg12H);
++
++ if (((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) {
++ if(sym < 3000) {
++ WriteReg(state, 0x6C, 0x16);
++ WriteReg(state, 0x6D, 0x10);
++ WriteReg(state, 0x6E, 0x18);
++ } else {
++ WriteReg(state, 0x6C, 0x14);
++ WriteReg(state, 0x6D, 0x0E);
++ WriteReg(state, 0x6E, 0x36);
++ }
++ } else {
++ WriteReg(state, 0x6C, 0x16);
++ WriteReg(state, 0x6D, 0x10);
++ WriteReg(state, 0x6E, 0x18);
++ }
++ return 0;
++}
++
++static int M88DC2000SetQAM(struct m88dc2800_state *state, u16 qam)
++{
++ u8 reg00H, reg4AH, regC2H, reg44H, reg4CH, reg4DH, reg74H, value;
++ u8 reg8BH, reg8EH;
++ printk("%s, qam=%d\n", __func__, qam);
++ regC2H = ReadReg(state, 0xC2);
++ regC2H &= 0xF8;
++ switch(qam){
++ case 16: /* 16 QAM */
++ reg00H = 0x08;
++ reg4AH = 0x0F;
++ regC2H |= 0x02;
++ reg44H = 0xAA;
++ reg4CH = 0x0C;
++ reg4DH = 0xF7;
++ reg74H = 0x0E;
++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) {
++ reg8BH = 0x5A;
++ reg8EH = 0xBD;
++ } else {
++ reg8BH = 0x5B;
++ reg8EH = 0x9D;
++ }
++ WriteReg(state, 0x6E, 0x18);
++ break;
++ case 32: /* 32 QAM */
++ reg00H = 0x18;
++ reg4AH = 0xFB;
++ regC2H |= 0x02;
++ reg44H = 0xAA;
++ reg4CH = 0x0C;
++ reg4DH = 0xF7;
++ reg74H = 0x0E;
++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) {
++ reg8BH = 0x5A;
++ reg8EH = 0xBD;
++ } else {
++ reg8BH = 0x5B;
++ reg8EH = 0x9D;
++ }
++ WriteReg(state, 0x6E, 0x18);
++ break;
++ case 64: /* 64 QAM */
++ reg00H = 0x48;
++ reg4AH = 0xCD;
++ regC2H |= 0x02;
++ reg44H = 0xAA;
++ reg4CH = 0x0C;
++ reg4DH = 0xF7;
++ reg74H = 0x0E;
++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) {
++ reg8BH = 0x5A;
++ reg8EH = 0xBD;
++ } else {
++ reg8BH = 0x5B;
++ reg8EH = 0x9D;
++ }
++ break;
++ case 128: /* 128 QAM */
++ reg00H = 0x28;
++ reg4AH = 0xFF;
++ regC2H |= 0x02;
++ reg44H = 0xA9;
++ reg4CH = 0x08;
++ reg4DH = 0xF5;
++ reg74H = 0x0E;
++ reg8BH = 0x5B;
++ reg8EH = 0x9D;
++ break;
++ case 256: /* 256 QAM */
++ reg00H = 0x38;
++ reg4AH = 0xCD;
++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) {
++ regC2H |= 0x02;
++ } else {
++ regC2H |= 0x01;
++ }
++ reg44H = 0xA9;
++ reg4CH = 0x08;
++ reg4DH = 0xF5;
++ reg74H = 0x0E;
++ reg8BH = 0x5B;
++ reg8EH = 0x9D;
++ break;
++ default: /* 64 QAM */
++ reg00H = 0x48;
++ reg4AH = 0xCD;
++ regC2H |= 0x02;
++ reg44H = 0xAA;
++ reg4CH = 0x0C;
++ reg4DH = 0xF7;
++ reg74H = 0x0E;
++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) {
++ reg8BH = 0x5A;
++ reg8EH = 0xBD;
++ } else {
++ reg8BH = 0x5B;
++ reg8EH = 0x9D;
++ }
++ break;
++ }
++ WriteReg(state, 0x00, reg00H);
++
++ value = ReadReg(state, 0x88);
++ value |= 0x08;
++ WriteReg(state, 0x88, value);
++ WriteReg(state, 0x4B, 0xFF);
++ WriteReg(state, 0x4A, reg4AH);
++ value &= 0xF7;
++ WriteReg(state, 0x88, value);
++
++ WriteReg(state, 0xC2, regC2H);
++ WriteReg(state, 0x44, reg44H);
++ WriteReg(state, 0x4C, reg4CH);
++ WriteReg(state, 0x4D, reg4DH);
++ WriteReg(state, 0x74, reg74H);
++ WriteReg(state, 0x8B, reg8BH);
++ WriteReg(state, 0x8E, reg8EH);
++ return 0;
++}
++
++static int M88DC2000WriteTuner_TC2800(struct m88dc2800_state *state, u32 freq_KHz)
++{
++ printk("%s, freq=%d KHz\n", __func__, freq_KHz);
++ return mt_fe_tn_set_freq_tc2800(state, freq_KHz);
++}
++
++static int m88dc2800_init(struct dvb_frontend *fe)
++{
++ dprintk("%s()\n", __func__);
++ return 0;
++}
++
++static int m88dc2800_set_parameters(struct dvb_frontend *fe)
++{
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ u8 is_annex_c, is_update;
++ u16 temp_qam;
++ s32 waiting_time;
++ struct m88dc2800_state* state = fe->demodulator_priv;
++
++ if(c->delivery_system == SYS_DVBC_ANNEX_C)
++ is_annex_c = 1;
++ else
++ is_annex_c = 0;
++
++ switch (c->modulation) {
++ case QAM_16:
++ temp_qam = 16;
++ break;
++ case QAM_32:
++ temp_qam = 32;
++ break;
++ case QAM_128:
++ temp_qam = 128;
++ break;
++ case QAM_256:
++ temp_qam = 256;
++ break;
++ default: /* QAM_64 */
++ temp_qam = 64;
++ break;
++ }
++
++ if(c->inversion == INVERSION_ON)
++ state->inverted = 1;
++ else
++ state->inverted = 0;
++
++ printk("m88dc2800: state, freq=%d qam=%d sym=%d inverted=%d xtal=%d\n", state->freq,state->qam,state->sym,state->inverted,state->xtal);
++ printk("m88dc2800: set frequency to %d qam=%d symrate=%d annex-c=%d\n", c->frequency,temp_qam,c->symbol_rate,is_annex_c);
++
++ is_update = 0;
++ WriteReg(state, 0x80, 0x01);
++ if(c->frequency != state->freq){
++ M88DC2000WriteTuner_TC2800(state, c->frequency/1000);
++ state->freq = c->frequency;
++ }
++ if(c->symbol_rate != state->sym){
++ M88DC2000SetSym(state, c->symbol_rate/1000, state->xtal);
++ state->sym = c->symbol_rate;
++ is_update = 1;
++ }
++ if(temp_qam != state->qam){
++ M88DC2000SetQAM(state, temp_qam);
++ state->qam = temp_qam;
++ is_update = 1;
++ }
++
++ if(is_update != 0){
++ if(state->config->ts_mode == 3)
++ M88DC2000AutoTSClock_C(state, state->sym/1000, temp_qam);
++ else
++ M88DC2000AutoTSClock_P(state, state->sym/1000, temp_qam);
++ }
++
++ M88DC2000SetTxMode(state, state->inverted, is_annex_c);
++ M88DC2000SoftReset(state);
++ if (((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80))
++ waiting_time = 800;
++ else
++ waiting_time = 500;
++ while (waiting_time > 0) {
++ msleep(50);
++ waiting_time -= 50;
++ if (M88DC2000GetLock(state))
++ return 0;
++ }
++
++ if (state->inverted != 0)
++ state->inverted = 0;
++ else
++ state->inverted = 1;
++ M88DC2000SetTxMode(state, state->inverted, is_annex_c);
++ M88DC2000SoftReset(state);
++ if (((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80))
++ waiting_time = 800;
++ else
++ waiting_time = 500;
++ while (waiting_time > 0) {
++ msleep(50);
++ waiting_time -= 50;
++ if (M88DC2000GetLock(state))
++ return 0;
++ }
++ return 0;
++}
++
++static int m88dc2800_read_status(struct dvb_frontend* fe, fe_status_t* status)
++{
++ struct m88dc2800_state* state = fe->demodulator_priv;
++ *status = 0;
++
++ if (M88DC2000GetLock(state)) {
++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER
++ | FE_HAS_SYNC|FE_HAS_VITERBI | FE_HAS_LOCK;
++ }
++ return 0;
++}
++
++static int m88dc2800_read_ber(struct dvb_frontend* fe, u32* ber)
++{
++ struct m88dc2800_state* state = fe->demodulator_priv;
++ u16 tmp;
++
++ if (M88DC2000GetLock(state) == 0) {
++ state->ber = 0;
++ } else if ((ReadReg(state, 0xA0) & 0x80) != 0x80) {
++ tmp = ReadReg(state, 0xA2) << 8;
++ tmp += ReadReg(state, 0xA1);
++ state->ber = tmp;
++ WriteReg(state, 0xA0, 0x05);
++ WriteReg(state, 0xA0, 0x85);
++ }
++ *ber = state->ber;
++ return 0;
++}
++
++static int m88dc2800_read_signal_strength(struct dvb_frontend* fe, u16* strength)
++{
++ struct m88dc2800_state* state = fe->demodulator_priv;
++
++ s16 tuner_strength;
++ tuner_strength = (s16)mt_fe_tn_get_signal_strength_tc2800(state);
++
++ if(tuner_strength < -107)
++ *strength = 0;
++ else
++ *strength = tuner_strength + 107;
++
++ return 0;
++}
++
++static int m88dc2800_read_snr(struct dvb_frontend* fe, u16* snr)
++{
++ struct m88dc2800_state* state = fe->demodulator_priv;
++
++ const u32 mes_log[] = {
++ 0, 3010, 4771, 6021, 6990, 7781, 8451, 9031, 9542, 10000,
++ 10414, 10792, 11139, 11461, 11761, 12041, 12304, 12553, 12788, 13010,
++ 13222, 13424, 13617, 13802, 13979, 14150, 14314, 14472, 14624, 14771,
++ 14914, 15052, 15185, 15315, 15441, 15563, 15682, 15798, 15911, 16021,
++ 16128, 16232, 16335, 16435, 16532, 16628, 16721, 16812, 16902, 16990,
++ 17076, 17160, 17243, 17324, 17404, 17482, 17559, 17634, 17709, 17782,
++ 17853, 17924, 17993, 18062, 18129, 18195, 18261, 18325, 18388, 18451,
++ 18513, 18573, 18633, 18692, 18751, 18808, 18865, 18921, 18976, 19031
++ };
++ u8 i;
++ u32 _snr, mse;
++
++ if ((ReadReg(state, 0x91)&0x23)!=0x03) {
++ *snr = 0;
++ return 0;
++ }
++
++ mse = 0;
++ for (i=0; i<30; i++) {
++ mse += (ReadReg(state, 0x08) << 8) + ReadReg(state, 0x07);
++ }
++ mse /= 30;
++ if (mse > 80)
++ mse = 80;
++
++ switch (state->qam) {
++ case 16: _snr = 34080; break; /* 16QAM */
++ case 32: _snr = 37600; break; /* 32QAM */
++ case 64: _snr = 40310; break; /* 64QAM */
++ case 128: _snr = 43720; break; /* 128QAM */
++ case 256: _snr = 46390; break; /* 256QAM */
++ default: _snr = 40310; break;
++ }
++ _snr -= mes_log[mse-1]; /* C - 10*log10(MSE) */
++ _snr /= 1000;
++ if (_snr > 0xff)
++ _snr = 0xff;
++
++ *snr = _snr;
++ return 0;
++}
++
++static int m88dc2800_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
++{
++ struct m88dc2800_state* state = fe->demodulator_priv;
++ u8 u8Value;
++
++ u8Value = ReadReg(state, 0xdf);
++ u8Value |= 0x02; /* Hold */
++ WriteReg(state, 0xdf, u8Value);
++
++ *ucblocks = ReadReg(state, 0xd5);
++ *ucblocks = (*ucblocks << 8) | ReadReg(state, 0xd4);
++
++ u8Value &= 0xfe; /* Clear */
++ WriteReg(state, 0xdf, u8Value);
++ u8Value &= 0xfc; /* Update */
++ u8Value |= 0x01;
++ WriteReg(state, 0xdf, u8Value);
++
++ return 0;
++}
++
++static int m88dc2800_sleep(struct dvb_frontend* fe)
++{
++ struct m88dc2800_state* state = fe->demodulator_priv;
++
++ mt_fe_tn_sleep_tc2800(state);
++ state->freq = 0;
++
++ return 0;
++}
++
++static void m88dc2800_release(struct dvb_frontend* fe)
++{
++ struct m88dc2800_state* state = fe->demodulator_priv;
++ kfree(state);
++}
++
++static struct dvb_frontend_ops m88dc2800_ops;
++
++struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config,
++ struct i2c_adapter* i2c)
++{
++ struct m88dc2800_state* state = NULL;
++
++ /* allocate memory for the internal state */
++ state = kzalloc(sizeof(struct m88dc2800_state), GFP_KERNEL);
++ if (state == NULL) goto error;
++
++ /* setup the state */
++ state->config = config;
++ state->i2c = i2c;
++ state->xtal = 28800;
++
++ WriteReg(state, 0x80, 0x01);
++ M88DC2000RegInitial_TC2800(state);
++ M88DC2000SetTsType(state, state->config->ts_mode);
++ mt_fe_tn_init_tc2800(state);
++
++ /* create dvb_frontend */
++ memcpy(&state->frontend.ops, &m88dc2800_ops, sizeof(struct dvb_frontend_ops));
++ state->frontend.demodulator_priv = state;
++ return &state->frontend;
++
++error:
++ kfree(state);
++ return NULL;
++}
++EXPORT_SYMBOL(m88dc2800_attach);
++
++static struct dvb_frontend_ops m88dc2800_ops = {
++ .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
++ .info = {
++ .name = "Montage M88DC2800 DVB-C",
++ .frequency_stepsize = 62500,
++ .frequency_min = 48000000,
++ .frequency_max = 870000000,
++ .symbol_rate_min = 870000,
++ .symbol_rate_max = 9000000,
++ .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
++ FE_CAN_QAM_128 | FE_CAN_QAM_256 |
++ FE_CAN_FEC_AUTO
++ },
++
++ .release = m88dc2800_release,
++ .init = m88dc2800_init,
++ .sleep = m88dc2800_sleep,
++ .set_frontend = m88dc2800_set_parameters,
++ .read_status = m88dc2800_read_status,
++ .read_ber = m88dc2800_read_ber,
++ .read_signal_strength = m88dc2800_read_signal_strength,
++ .read_snr = m88dc2800_read_snr,
++ .read_ucblocks = m88dc2800_read_ucblocks,
++};
++
++MODULE_DESCRIPTION("Montage DVB-C demodulator driver");
++MODULE_AUTHOR("Max nibble");
++MODULE_LICENSE("GPL");
+diff -urN a/drivers/media/dvb/frontends/m88dc2800.h b/drivers/media/dvb/frontends/m88dc2800.h
+--- a/drivers/media/dvb/frontends/m88dc2800.h 1970-01-01 08:00:00.000000000 +0800
++++ b/drivers/media/dvb/frontends/m88dc2800.h 2012-11-18 23:23:23.993155429 +0800
+@@ -0,0 +1,43 @@
++/*
++ M88DC2800/M88TC2800 - DVB-C demodulator and tuner from Montage
++
++ Copyright (C) 2012 Max nibble
++ Copyright (C) 2011 Montage Technology
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#ifndef M88DC2800_H
++#define M88DC2800_H
++
++#include
++
++struct m88dc2800_config {
++ u8 demod_address;
++ u8 ts_mode;
++};
++
++#if defined(CONFIG_DVB_M88DC2800) || (defined(CONFIG_DVB_M88DC2800_MODULE) && defined(MODULE))
++extern struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config,
++ struct i2c_adapter* i2c);
++#else
++static inline struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config,
++ struct i2c_adapter* i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif // CONFIG_DVB_M88DC2800
++#endif // M88DC2800_H
+diff -urN a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
+--- a/drivers/media/dvb/frontends/m88ds3103.c 1970-01-01 08:00:00.000000000 +0800
++++ b/drivers/media/dvb/frontends/m88ds3103.c 2012-11-18 23:23:27.661155528 +0800
+@@ -0,0 +1,1710 @@
++/*
++ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
++
++ Copyright (C) 2011 Max nibble
++ Copyright (C) 2010 Montage Technology
++ Copyright (C) 2009 Konstantin Dimitrov.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++
++#include "dvb_frontend.h"
++#include "m88ds3103.h"
++#include "m88ds3103_priv.h"
++
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
++
++#define dprintk(args...) \
++ do { \
++ if (debug) \
++ printk(KERN_INFO "m88ds3103: " args); \
++ } while (0)
++
++/*demod register operations.*/
++static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data)
++{
++ u8 buf[] = { reg, data };
++ struct i2c_msg msg = { .addr = state->config->demod_address,
++ .flags = 0, .buf = buf, .len = 2 };
++ int err;
++
++ if (debug > 1)
++ printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
++ __func__, reg, data);
++
++ err = i2c_transfer(state->i2c, &msg, 1);
++ if (err != 1) {
++ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
++ " value == 0x%02x)\n", __func__, err, reg, data);
++ return -EREMOTEIO;
++ }
++ return 0;
++}
++
++static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
++{
++ int ret;
++ u8 b0[] = { reg };
++ u8 b1[] = { 0 };
++ struct i2c_msg msg[] = {
++ { .addr = state->config->demod_address, .flags = 0,
++ .buf = b0, .len = 1 },
++ { .addr = state->config->demod_address, .flags = I2C_M_RD,
++ .buf = b1, .len = 1 }
++ };
++ ret = i2c_transfer(state->i2c, msg, 2);
++
++ if (ret != 2) {
++ printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
++ __func__, reg, ret);
++ return ret;
++ }
++
++ if (debug > 1)
++ printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
++ reg, b1[0]);
++
++ return b1[0];
++}
++
++/*tuner register operations.*/
++static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data)
++{
++ u8 buf[] = { reg, data };
++ struct i2c_msg msg = { .addr = 0x60,
++ .flags = 0, .buf = buf, .len = 2 };
++ int err;
++
++ m88ds3103_writereg(state, 0x03, 0x11);
++ err = i2c_transfer(state->i2c, &msg, 1);
++
++ if (err != 1) {
++ printk("%s: writereg error(err == %i, reg == 0x%02x,"
++ " value == 0x%02x)\n", __func__, err, reg, data);
++ return -EREMOTEIO;
++ }
++
++ return 0;
++}
++
++static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg)
++{
++ int ret;
++ u8 b0[] = { reg };
++ u8 b1[] = { 0 };
++ struct i2c_msg msg[] = {
++ { .addr = 0x60, .flags = 0,
++ .buf = b0, .len = 1 },
++ { .addr = 0x60, .flags = I2C_M_RD,
++ .buf = b1, .len = 1 }
++ };
++
++ m88ds3103_writereg(state, 0x03, 0x11);
++ ret = i2c_transfer(state->i2c, msg, 2);
++
++ if (ret != 2) {
++ printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
++ return ret;
++ }
++
++ return b1[0];
++}
++
++/* Bulk demod I2C write, for firmware download. */
++static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
++ const u8 *data, u16 len)
++{
++ int ret = -EREMOTEIO;
++ struct i2c_msg msg;
++ u8 *buf;
++
++ buf = kmalloc(len + 1, GFP_KERNEL);
++ if (buf == NULL) {
++ printk("Unable to kmalloc\n");
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ *(buf) = reg;
++ memcpy(buf + 1, data, len);
++
++ msg.addr = state->config->demod_address;
++ msg.flags = 0;
++ msg.buf = buf;
++ msg.len = len + 1;
++
++ if (debug > 1)
++ printk(KERN_INFO "m88ds3103: %s: write regN 0x%02x, len = %d\n",
++ __func__, reg, len);
++
++ ret = i2c_transfer(state->i2c, &msg, 1);
++ if (ret != 1) {
++ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
++ __func__, ret, reg);
++ ret = -EREMOTEIO;
++ }
++
++error:
++ kfree(buf);
++
++ return ret;
++}
++
++static int m88ds3103_load_firmware(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ const struct firmware *fw;
++ int i, ret = 0;
++
++ dprintk("%s()\n", __func__);
++
++ if (state->skip_fw_load)
++ return 0;
++ /* Load firmware */
++ /* request the firmware, this will block until someone uploads it */
++ if(state->demod_id == DS3000_ID){
++ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
++ DS3000_DEFAULT_FIRMWARE);
++ ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
++ state->i2c->dev.parent);
++ }else if(state->demod_id == DS3103_ID){
++ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
++ DS3103_DEFAULT_FIRMWARE);
++ ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
++ state->i2c->dev.parent);
++ }
++
++ printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
++ if (ret) {
++ printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
++ "found?)\n", __func__);
++ return ret;
++ }
++
++ /* Make sure we don't recurse back through here during loading */
++ state->skip_fw_load = 1;
++
++ dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
++ fw->size,
++ fw->data[0],
++ fw->data[1],
++ fw->data[fw->size - 2],
++ fw->data[fw->size - 1]);
++
++ /* stop internal mcu. */
++ m88ds3103_writereg(state, 0xb2, 0x01);
++ /* split firmware to download.*/
++ for(i = 0; i < FW_DOWN_LOOP; i++){
++ ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
++ if(ret != 1) break;
++ }
++ /* start internal mcu. */
++ if(ret == 1)
++ m88ds3103_writereg(state, 0xb2, 0x00);
++
++ release_firmware(fw);
++
++ dprintk("%s: Firmware upload %s\n", __func__,
++ ret == 1 ? "complete" : "failed");
++
++ if(ret == 1) ret = 0;
++
++ /* Ensure firmware is always loaded if required */
++ state->skip_fw_load = 0;
++
++ return ret;
++}
++
++
++static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 data;
++
++ dprintk("%s(%d)\n", __func__, voltage);
++
++ dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
++
++ if(state->config->set_voltage)
++ state->config->set_voltage(fe, voltage);
++
++ data = m88ds3103_readreg(state, 0xa2);
++
++ if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/
++ data &= ~0x03; /* bit0 V/H, bit1 off/on */
++ if(state->config->pin_ctrl & 0x02)
++ data |= 0x02;
++
++ switch (voltage) {
++ case SEC_VOLTAGE_18:
++ if((state->config->pin_ctrl & 0x01) == 0)
++ data |= 0x01;
++ break;
++ case SEC_VOLTAGE_13:
++ if(state->config->pin_ctrl & 0x01)
++ data |= 0x01;
++ break;
++ case SEC_VOLTAGE_OFF:
++ if(state->config->pin_ctrl & 0x02)
++ data &= ~0x02;
++ else
++ data |= 0x02;
++ break;
++ }
++ }
++
++ m88ds3103_writereg(state, 0xa2, data);
++
++ return 0;
++}
++
++static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ int lock = 0;
++
++ *status = 0;
++
++ switch (state->delivery_system){
++ case SYS_DVBS:
++ lock = m88ds3103_readreg(state, 0xd1);
++ dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
++
++ if ((lock & 0x07) == 0x07){
++ /*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER
++ | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
++
++ }
++ break;
++ case SYS_DVBS2:
++ lock = m88ds3103_readreg(state, 0x0d);
++ dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
++
++ if ((lock & 0x8f) == 0x8f)
++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER
++ | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
++
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 tmp1, tmp2, tmp3;
++ u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
++
++ dprintk("%s()\n", __func__);
++
++ switch (state->delivery_system) {
++ case SYS_DVBS:
++ m88ds3103_writereg(state, 0xf9, 0x04);
++ tmp3 = m88ds3103_readreg(state, 0xf8);
++ if ((tmp3&0x10) == 0){
++ tmp1 = m88ds3103_readreg(state, 0xf7);
++ tmp2 = m88ds3103_readreg(state, 0xf6);
++ tmp3 |= 0x10;
++ m88ds3103_writereg(state, 0xf8, tmp3);
++ state->preBer = (tmp1<<8) | tmp2;
++ }
++ break;
++ case SYS_DVBS2:
++ tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
++ switch(tmp1){
++ case 0: code_rate_fac = 16008 - 80; break;
++ case 1: code_rate_fac = 21408 - 80; break;
++ case 2: code_rate_fac = 25728 - 80; break;
++ case 3: code_rate_fac = 32208 - 80; break;
++ case 4: code_rate_fac = 38688 - 80; break;
++ case 5: code_rate_fac = 43040 - 80; break;
++ case 6: code_rate_fac = 48408 - 80; break;
++ case 7: code_rate_fac = 51648 - 80; break;
++ case 8: code_rate_fac = 53840 - 80; break;
++ case 9: code_rate_fac = 57472 - 80; break;
++ case 10: code_rate_fac = 58192 - 80; break;
++ }
++
++ tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
++ tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
++ tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;
++ ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
++
++ tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
++ tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
++ pre_err_packags = tmp1<<8 | tmp2;
++
++ if (ldpc_frame_cnt > 1000){
++ m88ds3103_writereg(state, 0xd1, 0x01);
++ m88ds3103_writereg(state, 0xf9, 0x01);
++ m88ds3103_writereg(state, 0xf9, 0x00);
++ m88ds3103_writereg(state, 0xd1, 0x00);
++ state->preBer = pre_err_packags;
++ }
++ break;
++ default:
++ break;
++ }
++ *ber = state->preBer;
++
++ return 0;
++}
++
++static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
++ u16 *signal_strength)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u16 gain;
++ u8 gain1, gain2, gain3 = 0;
++
++ dprintk("%s()\n", __func__);
++
++ gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f;
++ dprintk("%s: gain1 = 0x%02x \n", __func__, gain1);
++
++ if (gain1 > 15) gain1 = 15;
++ gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f;
++ dprintk("%s: gain2 = 0x%02x \n", __func__, gain2);
++
++ if(state->tuner_id == TS2022_ID){
++ gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07;
++ dprintk("%s: gain3 = 0x%02x \n", __func__, gain3);
++
++ if (gain2 > 16) gain2 = 16;
++ if (gain2 < 2) gain2 = 2;
++ if (gain3 > 6) gain3 = 6;
++ }else{
++ if (gain2 > 13) gain2 = 13;
++ gain3 = 0;
++ }
++
++ gain = gain1*23 + gain2*35 + gain3*29;
++ *signal_strength = 60000 - gain*55;
++
++ return 0;
++}
++
++
++static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 val, npow1, npow2, spow1, cnt;
++ u16 tmp, snr;
++ u32 npow, spow, snr_total;
++ static const u16 mes_log10[] ={
++ 0, 3010, 4771, 6021, 6990, 7781, 8451, 9031, 9542, 10000,
++ 10414, 10792, 11139, 11461, 11761, 12041, 12304, 12553, 12788, 13010,
++ 13222, 13424, 13617, 13802, 13979, 14150, 14314, 14472, 14624, 14771,
++ 14914, 15052, 15185, 15315, 15441, 15563, 15682, 15798, 15911, 16021,
++ 16128, 16232, 16335, 16435, 16532, 16628, 16721, 16812, 16902, 16990,
++ 17076, 17160, 17243, 17324, 17404, 17482, 17559, 17634, 17709, 17782,
++ 17853, 17924, 17993, 18062, 18129, 18195, 18261, 18325, 18388, 18451,
++ 18513, 18573, 18633, 18692, 18751, 18808, 18865, 18921, 18976, 19031
++ };
++ static const u16 mes_loge[] ={
++ 0, 6931, 10986, 13863, 16094, 17918, 19459, 20794, 21972, 23026,
++ 23979, 24849, 25649, 26391, 27081, 27726, 28332, 28904, 29444, 29957,
++ 30445, 30910, 31355, 31781, 32189, 32581, 32958, 33322, 33673, 34012,
++ 34340, 34657,
++ };
++
++ dprintk("%s()\n", __func__);
++
++ snr = 0;
++
++ switch (state->delivery_system){
++ case SYS_DVBS:
++ cnt = 10; snr_total = 0;
++ while(cnt > 0){
++ val = m88ds3103_readreg(state, 0xff);
++ snr_total += val;
++ cnt--;
++ }
++ tmp = (u16)(snr_total/80);
++ if(tmp > 0){
++ if (tmp > 32) tmp = 32;
++ snr = (mes_loge[tmp - 1] * 100) / 45;
++ }else{
++ snr = 0;
++ }
++ break;
++ case SYS_DVBS2:
++ cnt = 10; npow = 0; spow = 0;
++ while(cnt >0){
++ npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
++ npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
++ npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
++
++ spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
++ spow += ((spow1 * spow1) >> 1);
++ cnt--;
++ }
++ npow /= 10; spow /= 10;
++ if(spow == 0){
++ snr = 0;
++ }else if(npow == 0){
++ snr = 19;
++ }else{
++ if(spow > npow){
++ tmp = (u16)(spow / npow);
++ if (tmp > 80) tmp = 80;
++ snr = mes_log10[tmp - 1]*3;
++ }else{
++ tmp = (u16)(npow / spow);
++ if (tmp > 80) tmp = 80;
++ snr = -(mes_log10[tmp - 1] / 1000);
++ }
++ }
++ break;
++ default:
++ break;
++ }
++ *p_snr = snr;
++
++ return 0;
++}
++
++
++static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 tmp1, tmp2, tmp3, data;
++
++ dprintk("%s()\n", __func__);
++
++ switch (state->delivery_system) {
++ case SYS_DVBS:
++ data = m88ds3103_readreg(state, 0xf8);
++ data |= 0x40;
++ m88ds3103_writereg(state, 0xf8, data);
++ tmp1 = m88ds3103_readreg(state, 0xf5);
++ tmp2 = m88ds3103_readreg(state, 0xf4);
++ *ucblocks = (tmp1 <<8) | tmp2;
++ data &= ~0x20;
++ m88ds3103_writereg(state, 0xf8, data);
++ data |= 0x20;
++ m88ds3103_writereg(state, 0xf8, data);
++ data &= ~0x40;
++ m88ds3103_writereg(state, 0xf8, data);
++ break;
++ case SYS_DVBS2:
++ tmp1 = m88ds3103_readreg(state, 0xda);
++ tmp2 = m88ds3103_readreg(state, 0xd9);
++ tmp3 = m88ds3103_readreg(state, 0xd8);
++ *ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3;
++ data = m88ds3103_readreg(state, 0xd1);
++ data |= 0x01;
++ m88ds3103_writereg(state, 0xd1, data);
++ data &= ~0x01;
++ m88ds3103_writereg(state, 0xd1, data);
++ break;
++ default:
++ break;
++ }
++ return 0;
++}
++
++static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 data_a1, data_a2;
++
++ dprintk("%s(%d)\n", __func__, tone);
++ if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
++ printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
++ return -EINVAL;
++ }
++
++ data_a1 = m88ds3103_readreg(state, 0xa1);
++ data_a2 = m88ds3103_readreg(state, 0xa2);
++ if(state->demod_id == DS3103_ID)
++ data_a2 &= 0xdf; /* Normal mode */
++ switch (tone) {
++ case SEC_TONE_ON:
++ dprintk("%s: SEC_TONE_ON\n", __func__);
++ data_a1 |= 0x04;
++ data_a1 &= ~0x03;
++ data_a1 &= ~0x40;
++ data_a2 &= ~0xc0;
++ break;
++ case SEC_TONE_OFF:
++ dprintk("%s: SEC_TONE_OFF\n", __func__);
++ data_a2 &= ~0xc0;
++ data_a2 |= 0x80;
++ break;
++ }
++ m88ds3103_writereg(state, 0xa2, data_a2);
++ m88ds3103_writereg(state, 0xa1, data_a1);
++ return 0;
++}
++
++static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
++ struct dvb_diseqc_master_cmd *d)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ int i, ret = 0;
++ u8 tmp, time_out;
++
++ /* Dump DiSEqC message */
++ if (debug) {
++ printk(KERN_INFO "m88ds3103: %s(", __func__);
++ for (i = 0 ; i < d->msg_len ;) {
++ printk(KERN_INFO "0x%02x", d->msg[i]);
++ if (++i < d->msg_len)
++ printk(KERN_INFO ", ");
++ }
++ }
++
++ tmp = m88ds3103_readreg(state, 0xa2);
++ tmp &= ~0xc0;
++ if(state->demod_id == DS3103_ID)
++ tmp &= ~0x20;
++ m88ds3103_writereg(state, 0xa2, tmp);
++
++ for (i = 0; i < d->msg_len; i ++)
++ m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
++
++ tmp = m88ds3103_readreg(state, 0xa1);
++ tmp &= ~0x38;
++ tmp &= ~0x40;
++ tmp |= ((d->msg_len-1) << 3) | 0x07;
++ tmp &= ~0x80;
++ m88ds3103_writereg(state, 0xa1, tmp);
++ /* 1.5 * 9 * 8 = 108ms */
++ time_out = 150;
++ while (time_out > 0){
++ msleep(10);
++ time_out -= 10;
++ tmp = m88ds3103_readreg(state, 0xa1);
++ if ((tmp & 0x40) == 0)
++ break;
++ }
++ if (time_out == 0){
++ tmp = m88ds3103_readreg(state, 0xa1);
++ tmp &= ~0x80;
++ tmp |= 0x40;
++ m88ds3103_writereg(state, 0xa1, tmp);
++ ret = 1;
++ }
++ tmp = m88ds3103_readreg(state, 0xa2);
++ tmp &= ~0xc0;
++ tmp |= 0x80;
++ m88ds3103_writereg(state, 0xa2, tmp);
++ return ret;
++}
++
++
++static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
++ fe_sec_mini_cmd_t burst)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 val, time_out;
++
++ dprintk("%s()\n", __func__);
++
++ val = m88ds3103_readreg(state, 0xa2);
++ val &= ~0xc0;
++ if(state->demod_id == DS3103_ID)
++ val &= 0xdf; /* Normal mode */
++ m88ds3103_writereg(state, 0xa2, val);
++ /* DiSEqC burst */
++ if (burst == SEC_MINI_B)
++ m88ds3103_writereg(state, 0xa1, 0x01);
++ else
++ m88ds3103_writereg(state, 0xa1, 0x02);
++
++ msleep(13);
++
++ time_out = 5;
++ do{
++ val = m88ds3103_readreg(state, 0xa1);
++ if ((val & 0x40) == 0)
++ break;
++ msleep(1);
++ time_out --;
++ } while (time_out > 0);
++
++ val = m88ds3103_readreg(state, 0xa2);
++ val &= ~0xc0;
++ val |= 0x80;
++ m88ds3103_writereg(state, 0xa2, val);
++
++ return 0;
++}
++
++static void m88ds3103_release(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++
++ dprintk("%s\n", __func__);
++ kfree(state);
++}
++
++static int m88ds3103_check_id(struct m88ds3103_state *state)
++{
++ int val_00, val_01;
++
++ /*check demod id*/
++ val_01 = m88ds3103_readreg(state, 0x01);
++ printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01);
++
++ if(val_01 == 0xD0)
++ state->demod_id = DS3103_ID;
++ else if(val_01 == 0xC0)
++ state->demod_id = DS3000_ID;
++ else
++ state->demod_id = UNKNOW_ID;
++
++ /*check tuner id*/
++ val_00 = m88ds3103_tuner_readreg(state, 0x00);
++ printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00);
++ val_00 &= 0x03;
++ if(val_00 == 0)
++ {
++ m88ds3103_tuner_writereg(state, 0x00, 0x01);
++ msleep(3);
++ }
++ m88ds3103_tuner_writereg(state, 0x00, 0x03);
++ msleep(5);
++
++ val_00 = m88ds3103_tuner_readreg(state, 0x00);
++ printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00);
++ val_00 &= 0xff;
++ if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
++ state->tuner_id = TS2020_ID;
++ else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83))
++ state->tuner_id = TS2022_ID;
++ else
++ state->tuner_id = UNKNOW_ID;
++
++ return state->demod_id;
++}
++
++static struct dvb_frontend_ops m88ds3103_ops;
++static int m88ds3103_initilaze(struct dvb_frontend *fe);
++
++struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
++ struct i2c_adapter *i2c)
++{
++ struct m88ds3103_state *state = NULL;
++
++ dprintk("%s\n", __func__);
++
++ /* allocate memory for the internal state */
++ state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
++ if (state == NULL) {
++ printk(KERN_ERR "Unable to kmalloc\n");
++ goto error2;
++ }
++
++ state->config = config;
++ state->i2c = i2c;
++ state->preBer = 0xffff;
++ state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
++
++ /* check demod id */
++ if(m88ds3103_check_id(state) == UNKNOW_ID){
++ printk(KERN_ERR "Unable to find Montage chip\n");
++ goto error3;
++ }
++
++ memcpy(&state->frontend.ops, &m88ds3103_ops,
++ sizeof(struct dvb_frontend_ops));
++ state->frontend.demodulator_priv = state;
++
++ m88ds3103_initilaze(&state->frontend);
++
++ return &state->frontend;
++
++error3:
++ kfree(state);
++error2:
++ return NULL;
++}
++EXPORT_SYMBOL(m88ds3103_attach);
++
++static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
++ s32 carrier_offset_khz)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ s32 tmp;
++
++ tmp = carrier_offset_khz;
++ tmp *= 65536;
++
++ tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
++
++ if (tmp < 0)
++ tmp += 65536;
++
++ m88ds3103_writereg(state, 0x5f, tmp >> 8);
++ m88ds3103_writereg(state, 0x5e, tmp & 0xff);
++
++ return 0;
++}
++
++static int m88ds3103_set_symrate(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ u16 value;
++
++ value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2);
++ m88ds3103_writereg(state, 0x61, value & 0x00ff);
++ m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
++
++ return 0;
++}
++
++static int m88ds3103_set_CCI(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 tmp;
++
++ tmp = m88ds3103_readreg(state, 0x56);
++ tmp &= ~0x01;
++ m88ds3103_writereg(state, 0x56, tmp);
++
++ tmp = m88ds3103_readreg(state, 0x76);
++ tmp &= ~0x80;
++ m88ds3103_writereg(state, 0x76, tmp);
++
++ return 0;
++}
++
++static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size)
++{
++ u32 i;
++
++ for(i = 0; i < size; i+=2)
++ m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
++
++ return 0;
++}
++
++static int m88ds3103_get_locked_sym_rate(struct m88ds3103_state *state, u32 *sym_rate_KSs)
++{
++ u16 tmp;
++ u32 sym_rate_tmp;
++ u8 val_0x6d, val_0x6e;
++
++ val_0x6d = m88ds3103_readreg(state, 0x6d);
++ val_0x6e = m88ds3103_readreg(state, 0x6e);
++
++ tmp = (u16)((val_0x6e<<8) | val_0x6d);
++
++ sym_rate_tmp = (u32)(tmp * MT_FE_MCLK_KHZ);
++ sym_rate_tmp = (u32)(sym_rate_tmp / (1<<16));
++ *sym_rate_KSs = sym_rate_tmp;
++
++ return 0;
++}
++
++static int m88ds3103_get_channel_info(struct m88ds3103_state *state, u8 *p_mode, u8 *p_coderate)
++{
++ u8 tmp, val_0x7E;
++
++ if(state->delivery_system == SYS_DVBS2){
++ val_0x7E = m88ds3103_readreg(state, 0x7e);
++ tmp = (u8)((val_0x7E&0xC0) >> 6);
++ *p_mode = tmp;
++ tmp = (u8)(val_0x7E & 0x0f);
++ *p_coderate = tmp;
++ } else {
++ *p_mode = 0;
++ tmp = m88ds3103_readreg(state, 0xe6);
++ tmp = (u8)(tmp >> 5);
++ *p_coderate = tmp;
++ }
++
++ return 0;
++}
++
++static int m88ds3103_set_clock_ratio(struct m88ds3103_state *state)
++{
++ u8 val, mod_fac, tmp1, tmp2;
++ u32 input_datarate, locked_sym_rate_KSs;
++ u32 MClk_KHz = 96000;
++ u8 mod_mode, code_rate, divid_ratio = 0;
++
++ locked_sym_rate_KSs = 0;
++ m88ds3103_get_locked_sym_rate(state, &locked_sym_rate_KSs);
++ if(locked_sym_rate_KSs == 0)
++ return 0;
++
++ m88ds3103_get_channel_info(state, &mod_mode, &code_rate);
++
++ if (state->delivery_system == SYS_DVBS2)
++ {
++ switch(mod_mode) {
++ case 1: mod_fac = 3; break;
++ case 2: mod_fac = 4; break;
++ case 3: mod_fac = 5; break;
++ default: mod_fac = 2; break;
++ }
++
++ switch(code_rate) {
++ case 0: input_datarate = locked_sym_rate_KSs*mod_fac/8/4; break;
++ case 1: input_datarate = locked_sym_rate_KSs*mod_fac/8/3; break;
++ case 2: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/5; break;
++ case 3: input_datarate = locked_sym_rate_KSs*mod_fac/8/2; break;
++ case 4: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/5; break;
++ case 5: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break;
++ case 6: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/4; break;
++ case 7: input_datarate = locked_sym_rate_KSs*mod_fac*4/8/5; break;
++ case 8: input_datarate = locked_sym_rate_KSs*mod_fac*5/8/6; break;
++ case 9: input_datarate = locked_sym_rate_KSs*mod_fac*8/8/9; break;
++ case 10: input_datarate = locked_sym_rate_KSs*mod_fac*9/8/10; break;
++ default: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break;
++ }
++
++ if(state->demod_id == DS3000_ID)
++ input_datarate = input_datarate * 115 / 100;
++
++ if(input_datarate < 4800) {tmp1 = 15;tmp2 = 15;} //4.8MHz TS clock
++ else if(input_datarate < 4966) {tmp1 = 14;tmp2 = 15;} //4.966MHz TS clock
++ else if(input_datarate < 5143) {tmp1 = 14;tmp2 = 14;} //5.143MHz TS clock
++ else if(input_datarate < 5333) {tmp1 = 13;tmp2 = 14;} //5.333MHz TS clock
++ else if(input_datarate < 5538) {tmp1 = 13;tmp2 = 13;} //5.538MHz TS clock
++ else if(input_datarate < 5760) {tmp1 = 12;tmp2 = 13;} //5.76MHz TS clock allan 0809
++ else if(input_datarate < 6000) {tmp1 = 12;tmp2 = 12;} //6MHz TS clock
++ else if(input_datarate < 6260) {tmp1 = 11;tmp2 = 12;} //6.26MHz TS clock
++ else if(input_datarate < 6545) {tmp1 = 11;tmp2 = 11;} //6.545MHz TS clock
++ else if(input_datarate < 6857) {tmp1 = 10;tmp2 = 11;} //6.857MHz TS clock
++ else if(input_datarate < 7200) {tmp1 = 10;tmp2 = 10;} //7.2MHz TS clock
++ else if(input_datarate < 7578) {tmp1 = 9;tmp2 = 10;} //7.578MHz TS clock
++ else if(input_datarate < 8000) {tmp1 = 9;tmp2 = 9;} //8MHz TS clock
++ else if(input_datarate < 8470) {tmp1 = 8;tmp2 = 9;} //8.47MHz TS clock
++ else if(input_datarate < 9000) {tmp1 = 8;tmp2 = 8;} //9MHz TS clock
++ else if(input_datarate < 9600) {tmp1 = 7;tmp2 = 8;} //9.6MHz TS clock
++ else if(input_datarate < 10285) {tmp1 = 7;tmp2 = 7;} //10.285MHz TS clock
++ else if(input_datarate < 12000) {tmp1 = 6;tmp2 = 6;} //12MHz TS clock
++ else if(input_datarate < 14400) {tmp1 = 5;tmp2 = 5;} //14.4MHz TS clock
++ else if(input_datarate < 18000) {tmp1 = 4;tmp2 = 4;} //18MHz TS clock
++ else {tmp1 = 3;tmp2 = 3;} //24MHz TS clock
++
++ if(state->demod_id == DS3000_ID) {
++ val = (u8)((tmp1<<4) + tmp2);
++ m88ds3103_writereg(state, 0xfe, val);
++ } else {
++ tmp1 = m88ds3103_readreg(state, 0x22);
++ tmp2 = m88ds3103_readreg(state, 0x24);
++
++ tmp1 >>= 6;
++ tmp1 &= 0x03;
++ tmp2 >>= 6;
++ tmp2 &= 0x03;
++
++ if((tmp1 == 0x00) && (tmp2 == 0x01))
++ MClk_KHz = 144000;
++ else if((tmp1 == 0x00) && (tmp2 == 0x03))
++ MClk_KHz = 72000;
++ else if((tmp1 == 0x01) && (tmp2 == 0x01))
++ MClk_KHz = 115200;
++ else if((tmp1 == 0x02) && (tmp2 == 0x01))
++ MClk_KHz = 96000;
++ else if((tmp1 == 0x03) && (tmp2 == 0x00))
++ MClk_KHz = 192000;
++ else
++ return 0;
++
++ if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/
++ input_datarate = 5200;
++
++ if(input_datarate != 0)
++ divid_ratio = (u8)(MClk_KHz / input_datarate);
++ else
++ divid_ratio = 0xFF;
++
++ if(divid_ratio > 128)
++ divid_ratio = 128;
++
++ if(divid_ratio < 2)
++ divid_ratio = 2;
++
++ tmp1 = (u8)(divid_ratio / 2);
++ tmp2 = (u8)(divid_ratio / 2);
++
++ if((divid_ratio % 2) != 0)
++ tmp2 += 1;
++
++ tmp1 -= 1;
++ tmp2 -= 1;
++
++ tmp1 &= 0x3f;
++ tmp2 &= 0x3f;
++
++ val = m88ds3103_readreg(state, 0xfe);
++ val &= 0xF0;
++ val |= (tmp2 >> 2) & 0x0f;
++ m88ds3103_writereg(state, 0xfe, val);
++
++ val = (u8)((tmp2 & 0x03) << 6);
++ val |= tmp1;
++ m88ds3103_writereg(state, 0xea, val);
++ }
++ } else {
++ mod_fac = 2;
++
++ switch(code_rate) {
++ case 4: input_datarate = locked_sym_rate_KSs*mod_fac/2/8; break;
++ case 3: input_datarate = locked_sym_rate_KSs*mod_fac*2/3/8; break;
++ case 2: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break;
++ case 1: input_datarate = locked_sym_rate_KSs*mod_fac*5/6/8; break;
++ case 0: input_datarate = locked_sym_rate_KSs*mod_fac*7/8/8; break;
++ default: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break;
++ }
++
++ if(state->demod_id == DS3000_ID)
++ input_datarate = input_datarate * 115 / 100;
++
++ if(input_datarate < 6857) {tmp1 = 7;tmp2 = 7;} //6.857MHz TS clock
++ else if(input_datarate < 7384) {tmp1 = 6;tmp2 = 7;} //7.384MHz TS clock
++ else if(input_datarate < 8000) {tmp1 = 6;tmp2 = 6;} //8MHz TS clock
++ else if(input_datarate < 8727) {tmp1 = 5;tmp2 = 6;} //8.727MHz TS clock
++ else if(input_datarate < 9600) {tmp1 = 5;tmp2 = 5;} //9.6MHz TS clock
++ else if(input_datarate < 10666) {tmp1 = 4;tmp2 = 5;} //10.666MHz TS clock
++ else if(input_datarate < 12000) {tmp1 = 4;tmp2 = 4;} //12MHz TS clock
++ else if(input_datarate < 13714) {tmp1 = 3;tmp2 = 4;} //13.714MHz TS clock
++ else if(input_datarate < 16000) {tmp1 = 3;tmp2 = 3;} //16MHz TS clock
++ else if(input_datarate < 19200) {tmp1 = 2;tmp2 = 3;} //19.2MHz TS clock
++ else {tmp1 = 2;tmp2 = 2;} //24MHz TS clock
++
++ if(state->demod_id == DS3000_ID) {
++ val = m88ds3103_readreg(state, 0xfe);
++ val &= 0xc0;
++ val |= ((u8)((tmp1<<3) + tmp2));
++ m88ds3103_writereg(state, 0xfe, val);
++ } else {
++ if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/
++ input_datarate = 5200;
++
++ if(input_datarate != 0)
++ divid_ratio = (u8)(MClk_KHz / input_datarate);
++ else
++ divid_ratio = 0xFF;
++
++ if(divid_ratio > 128)
++ divid_ratio = 128;
++
++ if(divid_ratio < 2)
++ divid_ratio = 2;
++
++ tmp1 = (u8)(divid_ratio / 2);
++ tmp2 = (u8)(divid_ratio / 2);
++
++ if((divid_ratio % 2) != 0)
++ tmp2 += 1;
++
++ tmp1 -= 1;
++ tmp2 -= 1;
++
++ tmp1 &= 0x3f;
++ tmp2 &= 0x3f;
++
++ val = m88ds3103_readreg(state, 0xfe);
++ val &= 0xF0;
++ val |= (tmp2 >> 2) & 0x0f;
++ m88ds3103_writereg(state, 0xfe, val);
++
++ val = (u8)((tmp2 & 0x03) << 6);
++ val |= tmp1;
++ m88ds3103_writereg(state, 0xea, val);
++ }
++ }
++ return 0;
++}
++
++static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ u16 value;
++ u8 val1,val2,data;
++
++ dprintk("connect delivery system = %d\n", state->delivery_system);
++
++ /* ds3000 global reset */
++ m88ds3103_writereg(state, 0x07, 0x80);
++ m88ds3103_writereg(state, 0x07, 0x00);
++ /* ds3000 build-in uC reset */
++ m88ds3103_writereg(state, 0xb2, 0x01);
++ /* ds3000 software reset */
++ m88ds3103_writereg(state, 0x00, 0x01);
++
++ switch (state->delivery_system) {
++ case SYS_DVBS:
++ /* initialise the demod in DVB-S mode */
++ if(state->demod_id == DS3000_ID){
++ m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab));
++
++ value = m88ds3103_readreg(state, 0xfe);
++ value &= 0xc0;
++ value |= 0x1b;
++ m88ds3103_writereg(state, 0xfe, value);
++
++ if(state->config->ci_mode)
++ val1 = 0x80;
++ else if(state->config->ts_mode)
++ val1 = 0x60;
++ else
++ val1 = 0x20;
++ m88ds3103_writereg(state, 0xfd, val1);
++
++ }else if(state->demod_id == DS3103_ID){
++ m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab));
++
++ /* set ts clock */
++ if(state->config->ci_mode == 2){
++ val1 = 6; val2 = 6;
++ }else if(state->config->ts_mode == 0) {
++ val1 = 3; val2 = 3;
++ }else{
++ val1 = 0; val2 = 0;
++ }
++ val1 -= 1; val2 -= 1;
++ val1 &= 0x3f; val2 &= 0x3f;
++ data = m88ds3103_readreg(state, 0xfe);
++ data &= 0xf0;
++ data |= (val2 >> 2) & 0x0f;
++ m88ds3103_writereg(state, 0xfe, data);
++ data = (val2 & 0x03) << 6;
++ data |= val1;
++ m88ds3103_writereg(state, 0xea, data);
++
++ m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
++ m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
++
++ /* set master clock */
++ val1 = m88ds3103_readreg(state, 0x22);
++ val2 = m88ds3103_readreg(state, 0x24);
++
++ val1 &= 0x3f;
++ val2 &= 0x3f;
++ val1 |= 0x80;
++ val2 |= 0x40;
++
++ m88ds3103_writereg(state, 0x22, val1);
++ m88ds3103_writereg(state, 0x24, val2);
++
++ if(state->config->ci_mode)
++ val1 = 0x03;
++ else if(state->config->ts_mode)
++ val1 = 0x06;
++ else
++ val1 = 0x42;
++ m88ds3103_writereg(state, 0xfd, val1);
++ }
++ break;
++ case SYS_DVBS2:
++ /* initialise the demod in DVB-S2 mode */
++ if(state->demod_id == DS3000_ID){
++ m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab));
++
++ if (c->symbol_rate >= 30000000)
++ m88ds3103_writereg(state, 0xfe, 0x54);
++ else
++ m88ds3103_writereg(state, 0xfe, 0x98);
++
++ }else if(state->demod_id == DS3103_ID){
++ m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab));
++
++ /* set ts clock */
++ if(state->config->ci_mode == 2){
++ val1 = 6; val2 = 6;
++ }else if(state->config->ts_mode == 0){
++ val1 = 5; val2 = 4;
++ }else{
++ val1 = 0; val2 = 0;
++ }
++ val1 -= 1; val2 -= 1;
++ val1 &= 0x3f; val2 &= 0x3f;
++ data = m88ds3103_readreg(state, 0xfe);
++ data &= 0xf0;
++ data |= (val2 >> 2) & 0x0f;
++ m88ds3103_writereg(state, 0xfe, data);
++ data = (val2 & 0x03) << 6;
++ data |= val1;
++ m88ds3103_writereg(state, 0xea, data);
++
++ m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
++ m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
++
++ /* set master clock */
++ val1 = m88ds3103_readreg(state, 0x22);
++ val2 = m88ds3103_readreg(state, 0x24);
++
++ val1 &= 0x3f;
++ val2 &= 0x3f;
++ if((state->config->ci_mode == 2) || (state->config->ts_mode == 1)){
++ val1 |= 0x80;
++ val2 |= 0x40;
++ }else{
++ if (c->symbol_rate >= 28000000){
++ val1 |= 0xc0;
++ }else if (c->symbol_rate >= 18000000){
++ val2 |= 0x40;
++ }else{
++ val1 |= 0x80;
++ val2 |= 0x40;
++ }
++ }
++ m88ds3103_writereg(state, 0x22, val1);
++ m88ds3103_writereg(state, 0x24, val2);
++ }
++
++ if(state->config->ci_mode)
++ val1 = 0x03;
++ else if(state->config->ts_mode)
++ val1 = 0x06;
++ else
++ val1 = 0x42;
++ m88ds3103_writereg(state, 0xfd, val1);
++
++ break;
++ default:
++ return 1;
++ }
++ /* disable 27MHz clock output */
++ m88ds3103_writereg(state, 0x29, 0x80);
++ /* enable ac coupling */
++ m88ds3103_writereg(state, 0x25, 0x8a);
++
++ if ((c->symbol_rate / 1000) <= 3000){
++ m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/
++ m88ds3103_writereg(state, 0xc8, 0x20);
++ m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
++ m88ds3103_writereg(state, 0xc7, 0x00);
++ }else if((c->symbol_rate / 1000) <= 10000){
++ m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/
++ m88ds3103_writereg(state, 0xc8, 0x10);
++ m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
++ m88ds3103_writereg(state, 0xc7, 0x00);
++ }else{
++ m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/
++ m88ds3103_writereg(state, 0xc8, 0x06);
++ m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
++ m88ds3103_writereg(state, 0xc7, 0x00);
++ }
++
++ m88ds3103_set_symrate(fe);
++
++ m88ds3103_set_CCI(fe);
++
++ m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
++
++ /* ds3000 out of software reset */
++ m88ds3103_writereg(state, 0x00, 0x00);
++ /* start ds3000 build-in uC */
++ m88ds3103_writereg(state, 0xb2, 0x00);
++
++ return 0;
++}
++
++static int m88ds3103_set_frontend(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++
++ int i;
++ fe_status_t status;
++ u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
++ s32 offset_khz, lpf_offset_KHz;
++ u16 value, ndiv, lpf_coeff;
++ u32 f3db, gdiv28, realFreq;
++ u8 RFgain;
++
++ dprintk("%s() ", __func__);
++ dprintk("c frequency = %d\n", c->frequency);
++ dprintk("symbol rate = %d\n", c->symbol_rate);
++ dprintk("delivery system = %d\n", c->delivery_system);
++
++ realFreq = c->frequency;
++ lpf_offset_KHz = 0;
++ if(c->symbol_rate < 5000000){
++ lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
++ realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
++ }
++
++ if (state->config->set_ts_params)
++ state->config->set_ts_params(fe, 0);
++
++ div4 = 0;
++ RFgain = 0;
++ if(state->tuner_id == TS2022_ID){
++ m88ds3103_tuner_writereg(state, 0x10, 0x0a);
++ m88ds3103_tuner_writereg(state, 0x11, 0x40);
++ if (realFreq < 1103000) {
++ m88ds3103_tuner_writereg(state, 0x10, 0x1b);
++ div4 = 1;
++ ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
++ }else {
++ ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ;
++ }
++ ndiv = ndiv + ndiv%2;
++ if(ndiv < 4095)
++ ndiv = ndiv - 1024;
++ else if (ndiv < 6143)
++ ndiv = ndiv + 1024;
++ else
++ ndiv = ndiv + 3072;
++
++ m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);
++ }else{
++ m88ds3103_tuner_writereg(state, 0x10, 0x00);
++ if (realFreq < 1146000){
++ m88ds3103_tuner_writereg(state, 0x10, 0x11);
++ div4 = 1;
++ ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
++ }else{
++ m88ds3103_tuner_writereg(state, 0x10, 0x01);
++ ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
++ }
++ ndiv = ndiv + ndiv%2;
++ ndiv = ndiv - 1024;
++ m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f);
++ }
++ /* set pll */
++ m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff);
++ m88ds3103_tuner_writereg(state, 0x03, 0x06);
++ m88ds3103_tuner_writereg(state, 0x51, 0x0f);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x10);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++
++ if(state->tuner_id == TS2022_ID){
++ if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){
++ msleep(5);
++ value = m88ds3103_tuner_readreg(state, 0x14);
++ value &= 0x7f;
++ if(value < 64){
++ m88ds3103_tuner_writereg(state, 0x10, 0x82);
++ m88ds3103_tuner_writereg(state, 0x11, 0x6f);
++
++ m88ds3103_tuner_writereg(state, 0x51, 0x0f);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x10);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ }
++ }
++ msleep(5);
++ value = m88ds3103_tuner_readreg(state, 0x14);
++ value &= 0x1f;
++
++ if(value > 19){
++ value = m88ds3103_tuner_readreg(state, 0x10);
++ value &= 0x1d;
++ m88ds3103_tuner_writereg(state, 0x10, value);
++ }
++ }else{
++ msleep(5);
++ value = m88ds3103_tuner_readreg(state, 0x66);
++ changePLL = (((value & 0x80) >> 7) != div4);
++
++ if(changePLL){
++ m88ds3103_tuner_writereg(state, 0x10, 0x11);
++ div4 = 1;
++ ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
++ ndiv = ndiv + ndiv%2;
++ ndiv = ndiv - 1024;
++
++ m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f);
++ m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff);
++
++ m88ds3103_tuner_writereg(state, 0x51, 0x0f);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x10);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ }
++ }
++ /*set the RF gain*/
++ if(state->tuner_id == TS2020_ID)
++ m88ds3103_tuner_writereg(state, 0x60, 0x79);
++
++ m88ds3103_tuner_writereg(state, 0x51, 0x17);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x08);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ msleep(5);
++
++ if(state->tuner_id == TS2020_ID){
++ RFgain = m88ds3103_tuner_readreg(state, 0x3d);
++ RFgain &= 0x0f;
++ if(RFgain < 15){
++ if(RFgain < 4)
++ RFgain = 0;
++ else
++ RFgain = RFgain -3;
++ value = ((RFgain << 3) | 0x01) & 0x79;
++ m88ds3103_tuner_writereg(state, 0x60, value);
++ m88ds3103_tuner_writereg(state, 0x51, 0x17);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x08);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ }
++ }
++
++ /* set the LPF */
++ if(state->tuner_id == TS2022_ID){
++ m88ds3103_tuner_writereg(state, 0x25, 0x00);
++ m88ds3103_tuner_writereg(state, 0x27, 0x70);
++ m88ds3103_tuner_writereg(state, 0x41, 0x09);
++ m88ds3103_tuner_writereg(state, 0x08, 0x0b);
++ }
++
++ f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000;
++ f3db += lpf_offset_KHz;
++ if (f3db < 7000)
++ f3db = 7000;
++ if (f3db > 40000)
++ f3db = 40000;
++
++ gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
++ m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1b);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x04);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ msleep(5);
++
++ value = m88ds3103_tuner_readreg(state, 0x26);
++ capCode = value & 0x3f;
++ if(state->tuner_id == TS2022_ID){
++ m88ds3103_tuner_writereg(state, 0x41, 0x0d);
++
++ m88ds3103_tuner_writereg(state, 0x51, 0x1b);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x04);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++
++ msleep(2);
++
++ value = m88ds3103_tuner_readreg(state, 0x26);
++ value &= 0x3f;
++ value = (capCode + value) / 2;
++ }
++ else
++ value = capCode;
++
++ gdiv28 = gdiv28 * 207 / (value * 2 + 151);
++ mlpf_max = gdiv28 * 135 / 100;
++ mlpf_min = gdiv28 * 78 / 100;
++ if (mlpf_max > 63)
++ mlpf_max = 63;
++
++ if(state->tuner_id == TS2022_ID)
++ lpf_coeff = 3200;
++ else
++ lpf_coeff = 2766;
++
++ nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000) + 1) / 2 ;
++ if (nlpf > 23) nlpf = 23;
++ if (nlpf < 1) nlpf = 1;
++
++ lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2;
++
++ if (lpf_mxdiv < mlpf_min){
++ nlpf++;
++ lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2;
++ }
++
++ if (lpf_mxdiv > mlpf_max)
++ lpf_mxdiv = mlpf_max;
++
++ m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv);
++ m88ds3103_tuner_writereg(state, 0x06, nlpf);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1b);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x04);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ msleep(5);
++
++ if(state->tuner_id == TS2022_ID){
++ msleep(2);
++ value = m88ds3103_tuner_readreg(state, 0x26);
++ capCode = value & 0x3f;
++
++ m88ds3103_tuner_writereg(state, 0x41, 0x09);
++
++ m88ds3103_tuner_writereg(state, 0x51, 0x1b);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x04);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++
++ msleep(2);
++ value = m88ds3103_tuner_readreg(state, 0x26);
++ value &= 0x3f;
++ value = (capCode + value) / 2;
++
++ value = value | 0x80;
++ m88ds3103_tuner_writereg(state, 0x25, value);
++ m88ds3103_tuner_writereg(state, 0x27, 0x30);
++
++ m88ds3103_tuner_writereg(state, 0x08, 0x09);
++ }
++
++ /* Set the BB gain */
++ m88ds3103_tuner_writereg(state, 0x51, 0x1e);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x01);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ if(state->tuner_id == TS2020_ID){
++ if(RFgain == 15){
++ msleep(40);
++ value = m88ds3103_tuner_readreg(state, 0x21);
++ value &= 0x0f;
++ if(value < 3){
++ m88ds3103_tuner_writereg(state, 0x60, 0x61);
++ m88ds3103_tuner_writereg(state, 0x51, 0x17);
++ m88ds3103_tuner_writereg(state, 0x51, 0x1f);
++ m88ds3103_tuner_writereg(state, 0x50, 0x08);
++ m88ds3103_tuner_writereg(state, 0x50, 0x00);
++ }
++ }
++ }
++ msleep(60);
++
++ offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
++ / (6 + 8) / (div4 + 1) / 2 - realFreq;
++
++ m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz);
++
++ for (i = 0; i < 30 ; i++) {
++ m88ds3103_read_status(fe, &status);
++ if (status & FE_HAS_LOCK){
++ break;
++ }
++ msleep(20);
++ }
++
++ if((status & FE_HAS_LOCK) == 0){
++ state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS;
++ m88ds3103_demod_connect(fe, offset_khz);
++
++ for (i = 0; i < 30 ; i++) {
++ m88ds3103_read_status(fe, &status);
++ if (status & FE_HAS_LOCK){
++ break;
++ }
++ msleep(20);
++ }
++ }
++
++ if (status & FE_HAS_LOCK){
++ if(state->config->ci_mode == 2)
++ m88ds3103_set_clock_ratio(state);
++ if(state->config->start_ctrl){
++ if(state->first_lock == 0){
++ state->config->start_ctrl(fe);
++ state->first_lock = 1;
++ }
++ }
++ }
++
++ return 0;
++}
++
++static int m88ds3103_tune(struct dvb_frontend *fe,
++ bool re_tune,
++ unsigned int mode_flags,
++ unsigned int *delay,
++ fe_status_t *status)
++{
++ *delay = HZ / 5;
++
++ dprintk("%s() ", __func__);
++ dprintk("re_tune = %d\n", re_tune);
++
++ if (re_tune) {
++ int ret = m88ds3103_set_frontend(fe);
++ if (ret)
++ return ret;
++ }
++
++ return m88ds3103_read_status(fe, status);
++}
++
++static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
++{
++ return DVBFE_ALGO_HW;
++}
++
++ /*
++ * Power config will reset and load initial firmware if required
++ */
++static int m88ds3103_initilaze(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ int ret;
++
++ dprintk("%s()\n", __func__);
++ /* hard reset */
++ m88ds3103_writereg(state, 0x07, 0x80);
++ m88ds3103_writereg(state, 0x07, 0x00);
++ msleep(1);
++
++ m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
++ msleep(1);
++
++ if(state->tuner_id == TS2020_ID){
++ /* TS2020 init */
++ m88ds3103_tuner_writereg(state, 0x42, 0x73);
++ msleep(2);
++ m88ds3103_tuner_writereg(state, 0x05, 0x01);
++ m88ds3103_tuner_writereg(state, 0x62, 0xb5);
++ m88ds3103_tuner_writereg(state, 0x07, 0x02);
++ m88ds3103_tuner_writereg(state, 0x08, 0x01);
++ }
++ else if(state->tuner_id == TS2022_ID){
++ /* TS2022 init */
++ m88ds3103_tuner_writereg(state, 0x62, 0x6c);
++ msleep(2);
++ m88ds3103_tuner_writereg(state, 0x42, 0x6c);
++ msleep(2);
++ m88ds3103_tuner_writereg(state, 0x7d, 0x9d);
++ m88ds3103_tuner_writereg(state, 0x7c, 0x9a);
++ m88ds3103_tuner_writereg(state, 0x7a, 0x76);
++
++ m88ds3103_tuner_writereg(state, 0x3b, 0x01);
++ m88ds3103_tuner_writereg(state, 0x63, 0x88);
++
++ m88ds3103_tuner_writereg(state, 0x61, 0x85);
++ m88ds3103_tuner_writereg(state, 0x22, 0x30);
++ m88ds3103_tuner_writereg(state, 0x30, 0x40);
++ m88ds3103_tuner_writereg(state, 0x20, 0x23);
++ m88ds3103_tuner_writereg(state, 0x24, 0x02);
++ m88ds3103_tuner_writereg(state, 0x12, 0xa0);
++ }
++
++ if(state->demod_id == DS3103_ID){
++ m88ds3103_writereg(state, 0x07, 0xe0);
++ m88ds3103_writereg(state, 0x07, 0x00);
++ msleep(1);
++ }
++ m88ds3103_writereg(state, 0xb2, 0x01);
++
++ /* Load the firmware if required */
++ ret = m88ds3103_load_firmware(fe);
++ if (ret != 0){
++ printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
++ return ret;
++ }
++ if(state->demod_id == DS3103_ID){
++ m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
++ m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
++ }
++
++ return 0;
++}
++
++/*
++ * Initialise or wake up device
++ */
++static int m88ds3103_initfe(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++ u8 val;
++
++ dprintk("%s()\n", __func__);
++
++ /* 1st step to wake up demod */
++ m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
++ m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
++ m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
++
++ /* 2nd step to wake up tuner */
++ val = m88ds3103_tuner_readreg(state, 0x00) & 0xff;
++ if((val & 0x01) == 0){
++ m88ds3103_tuner_writereg(state, 0x00, 0x01);
++ msleep(50);
++ }
++ m88ds3103_tuner_writereg(state, 0x00, 0x03);
++ msleep(50);
++
++ return 0;
++}
++
++/* Put device to sleep */
++static int m88ds3103_sleep(struct dvb_frontend *fe)
++{
++ struct m88ds3103_state *state = fe->demodulator_priv;
++
++ dprintk("%s()\n", __func__);
++
++ /* 1st step to sleep tuner */
++ m88ds3103_tuner_writereg(state, 0x00, 0x00);
++
++ /* 2nd step to sleep demod */
++ m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
++ m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
++ m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
++
++
++ return 0;
++}
++
++static struct dvb_frontend_ops m88ds3103_ops = {
++ .delsys = { SYS_DVBS, SYS_DVBS2},
++ .info = {
++ .name = "Montage DS3103/TS2022",
++ .type = FE_QPSK,
++ .frequency_min = 950000,
++ .frequency_max = 2150000,
++ .frequency_stepsize = 1011, /* kHz for QPSK frontends */
++ .frequency_tolerance = 5000,
++ .symbol_rate_min = 1000000,
++ .symbol_rate_max = 45000000,
++ .caps = FE_CAN_INVERSION_AUTO |
++ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
++ FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
++ FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
++ FE_CAN_2G_MODULATION |
++ FE_CAN_QPSK | FE_CAN_RECOVER
++ },
++
++ .release = m88ds3103_release,
++
++ .init = m88ds3103_initfe,
++ .sleep = m88ds3103_sleep,
++ .read_status = m88ds3103_read_status,
++ .read_ber = m88ds3103_read_ber,
++ .read_signal_strength = m88ds3103_read_signal_strength,
++ .read_snr = m88ds3103_read_snr,
++ .read_ucblocks = m88ds3103_read_ucblocks,
++ .set_tone = m88ds3103_set_tone,
++ .set_voltage = m88ds3103_set_voltage,
++ .diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
++ .diseqc_send_burst = m88ds3103_diseqc_send_burst,
++ .get_frontend_algo = m88ds3103_get_algo,
++ .tune = m88ds3103_tune,
++ .set_frontend = m88ds3103_set_frontend,
++};
++
++MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
++MODULE_AUTHOR("Max nibble");
++MODULE_LICENSE("GPL");
+diff -urN a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h
+--- a/drivers/media/dvb/frontends/m88ds3103.h 1970-01-01 08:00:00.000000000 +0800
++++ b/drivers/media/dvb/frontends/m88ds3103.h 2012-11-18 23:23:38.173155809 +0800
+@@ -0,0 +1,53 @@
++/*
++ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef M88DS3103_H
++#define M88DS3103_H
++
++#include
++
++struct m88ds3103_config {
++ /* the demodulator's i2c address */
++ u8 demod_address;
++ u8 ci_mode;
++ u8 pin_ctrl;
++ u8 ts_mode; /* 0: Parallel, 1: Serial */
++
++ /* Set device param to start dma */
++ int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
++ /* Start to transfer data */
++ int (*start_ctrl)(struct dvb_frontend *fe);
++ /* Set LNB voltage */
++ int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
++};
++
++#if defined(CONFIG_DVB_M88DS3103) || \
++ (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
++extern struct dvb_frontend *m88ds3103_attach(
++ const struct m88ds3103_config *config,
++ struct i2c_adapter *i2c);
++#else
++static inline struct dvb_frontend *m88ds3103_attach(
++ const struct m88ds3103_config *config,
++ struct i2c_adapter *i2c)
++{
++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif /* CONFIG_DVB_M88DS3103 */
++#endif /* M88DS3103_H */
+diff -urN a/drivers/media/dvb/frontends/m88ds3103_priv.h b/drivers/media/dvb/frontends/m88ds3103_priv.h
+--- a/drivers/media/dvb/frontends/m88ds3103_priv.h 1970-01-01 08:00:00.000000000 +0800
++++ b/drivers/media/dvb/frontends/m88ds3103_priv.h 2012-11-18 23:23:42.173155920 +0800
+@@ -0,0 +1,403 @@
++/*
++ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef M88DS3103_PRIV_H
++#define M88DS3103_PRIV_H
++
++#define FW_DOWN_SIZE 32
++#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
++#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
++#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
++#define MT_FE_MCLK_KHZ 96000 /* in kHz */
++#define MT_FE_CRYSTAL_KHZ 27000 /* in kHz */
++#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
++#define DS3000_ID 0x3000
++#define DS3103_ID 0x3103
++#define TS2020_ID 0x2020
++#define TS2022_ID 0x2022
++#define UNKNOW_ID 0x0000
++
++struct m88ds3103_state {
++ struct i2c_adapter *i2c;
++ const struct m88ds3103_config *config;
++
++ struct dvb_frontend frontend;
++
++ u32 preBer;
++ u8 skip_fw_load;
++ u8 first_lock; /* The first time of signal lock */
++ u16 demod_id; /* demod chip type */
++ u16 tuner_id; /* tuner chip type */
++ fe_delivery_system_t delivery_system;
++};
++
++/* For M88DS3103 demod dvbs mode.*/
++static u8 ds3103_dvbs_init_tab[] = {
++ 0x23, 0x07,
++ 0x08, 0x03,
++ 0x0c, 0x02,
++ 0x21, 0x54,
++ 0x25, 0x82,
++ 0x27, 0x31,
++ 0x30, 0x08,
++ 0x31, 0x40,
++ 0x32, 0x32,
++ 0x33, 0x35,
++ 0x35, 0xff,
++ 0x3a, 0x00,
++ 0x37, 0x10,
++ 0x38, 0x10,
++ 0x39, 0x02,
++ 0x42, 0x60,
++ 0x4a, 0x80,
++ 0x4b, 0x04,
++ 0x4d, 0x91,
++ 0x5d, 0xc8,
++ 0x50, 0x36,
++ 0x51, 0x36,
++ 0x52, 0x36,
++ 0x53, 0x36,
++ 0x63, 0x0f,
++ 0x64, 0x30,
++ 0x65, 0x40,
++ 0x68, 0x26,
++ 0x69, 0x4c,
++ 0x70, 0x20,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x40,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x60,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x80,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0xa0,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x1f,
++ 0x76, 0x38,
++ 0x77, 0xa6,
++ 0x78, 0x0c,
++ 0x79, 0x80,
++ 0x7f, 0x14,
++ 0x7c, 0x00,
++ 0xae, 0x82,
++ 0x80, 0x64,
++ 0x81, 0x66,
++ 0x82, 0x44,
++ 0x85, 0x04,
++ 0xcd, 0xf4,
++ 0x90, 0x33,
++ 0xa0, 0x44,
++ 0xc0, 0x08,
++ 0xc3, 0x10,
++ 0xc4, 0x08,
++ 0xc5, 0xf0,
++ 0xc6, 0xff,
++ 0xc7, 0x00,
++ 0xc8, 0x1a,
++ 0xc9, 0x80,
++ 0xe0, 0xf8,
++ 0xe6, 0x8b,
++ 0xd0, 0x40,
++ 0xf8, 0x20,
++ 0xfa, 0x0f,
++ 0x00, 0x00,
++ 0xbd, 0x01,
++ 0xb8, 0x00,
++};
++/* For M88DS3103 demod dvbs2 mode.*/
++static u8 ds3103_dvbs2_init_tab[] = {
++ 0x23, 0x07,
++ 0x08, 0x07,
++ 0x0c, 0x02,
++ 0x21, 0x54,
++ 0x25, 0x82,
++ 0x27, 0x31,
++ 0x30, 0x08,
++ 0x32, 0x32,
++ 0x33, 0x35,
++ 0x35, 0xff,
++ 0x3a, 0x00,
++ 0x37, 0x10,
++ 0x38, 0x10,
++ 0x39, 0x02,
++ 0x42, 0x60,
++ 0x4a, 0x80,
++ 0x4b, 0x04,
++ 0x4d, 0x91,
++ 0x5d, 0xc8,
++ 0x50, 0x36,
++ 0x51, 0x36,
++ 0x52, 0x36,
++ 0x53, 0x36,
++ 0x63, 0x0f,
++ 0x64, 0x10,
++ 0x65, 0x20,
++ 0x68, 0x46,
++ 0x69, 0xcd,
++ 0x70, 0x20,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x40,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x60,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x80,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0xa0,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x1f,
++ 0x76, 0x38,
++ 0x77, 0xa6,
++ 0x78, 0x0c,
++ 0x79, 0x80,
++ 0x7f, 0x14,
++ 0x85, 0x08,
++ 0xcd, 0xf4,
++ 0x90, 0x33,
++ 0x86, 0x00,
++ 0x87, 0x0f,
++ 0x89, 0x00,
++ 0x8b, 0x44,
++ 0x8c, 0x66,
++ 0x9d, 0xc1,
++ 0x8a, 0x10,
++ 0xad, 0x40,
++ 0xa0, 0x44,
++ 0xc0, 0x08,
++ 0xc1, 0x10,
++ 0xc2, 0x08,
++ 0xc3, 0x10,
++ 0xc4, 0x08,
++ 0xc5, 0xf0,
++ 0xc6, 0xff,
++ 0xc7, 0x00,
++ 0xc8, 0x1a,
++ 0xc9, 0x80,
++ 0xca, 0x23,
++ 0xcb, 0x24,
++ 0xcc, 0xf4,
++ 0xce, 0x74,
++ 0x00, 0x00,
++ 0xbd, 0x01,
++ 0xb8, 0x00,
++};
++
++/* For M88DS3000 demod dvbs mode.*/
++static u8 ds3000_dvbs_init_tab[] = {
++ 0x23, 0x05,
++ 0x08, 0x03,
++ 0x0c, 0x02,
++ 0x21, 0x54,
++ 0x25, 0x82,
++ 0x27, 0x31,
++ 0x30, 0x08,
++ 0x31, 0x40,
++ 0x32, 0x32,
++ 0x33, 0x35,
++ 0x35, 0xff,
++ 0x3a, 0x00,
++ 0x37, 0x10,
++ 0x38, 0x10,
++ 0x39, 0x02,
++ 0x42, 0x60,
++ 0x4a, 0x40,
++ 0x4b, 0x04,
++ 0x4d, 0x91,
++ 0x5d, 0xc8,
++ 0x50, 0x77,
++ 0x51, 0x77,
++ 0x52, 0x36,
++ 0x53, 0x36,
++ 0x56, 0x01,
++ 0x63, 0x47,
++ 0x64, 0x30,
++ 0x65, 0x40,
++ 0x68, 0x26,
++ 0x69, 0x4c,
++ 0x70, 0x20,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x40,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x60,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x80,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0xa0,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x1f,
++ 0x76, 0x00,
++ 0x77, 0xd1,
++ 0x78, 0x0c,
++ 0x79, 0x80,
++ 0x7f, 0x04,
++ 0x7c, 0x00,
++ 0x80, 0x86,
++ 0x81, 0xa6,
++ 0x85, 0x04,
++ 0xcd, 0xf4,
++ 0x90, 0x33,
++ 0xa0, 0x44,
++ 0xc0, 0x18,
++ 0xc3, 0x10,
++ 0xc4, 0x08,
++ 0xc5, 0x80,
++ 0xc6, 0x80,
++ 0xc7, 0x0a,
++ 0xc8, 0x1a,
++ 0xc9, 0x80,
++ 0xfe, 0xb6,
++ 0xe0, 0xf8,
++ 0xe6, 0x8b,
++ 0xd0, 0x40,
++ 0xf8, 0x20,
++ 0xfa, 0x0f,
++ 0xad, 0x20,
++ 0xae, 0x07,
++ 0xb8, 0x00,
++};
++
++/* For M88DS3000 demod dvbs2 mode.*/
++static u8 ds3000_dvbs2_init_tab[] = {
++ 0x23, 0x0f,
++ 0x08, 0x07,
++ 0x0c, 0x02,
++ 0x21, 0x54,
++ 0x25, 0x82,
++ 0x27, 0x31,
++ 0x30, 0x08,
++ 0x31, 0x32,
++ 0x32, 0x32,
++ 0x33, 0x35,
++ 0x35, 0xff,
++ 0x3a, 0x00,
++ 0x37, 0x10,
++ 0x38, 0x10,
++ 0x39, 0x02,
++ 0x42, 0x60,
++ 0x4a, 0x80,
++ 0x4b, 0x04,
++ 0x4d, 0x91,
++ 0x5d, 0x88,
++ 0x50, 0x36,
++ 0x51, 0x36,
++ 0x52, 0x36,
++ 0x53, 0x36,
++ 0x63, 0x60,
++ 0x64, 0x10,
++ 0x65, 0x10,
++ 0x68, 0x04,
++ 0x69, 0x29,
++ 0x70, 0x20,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x40,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x60,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x80,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0xa0,
++ 0x71, 0x70,
++ 0x72, 0x04,
++ 0x73, 0x00,
++ 0x70, 0x1f,
++ 0xa0, 0x44,
++ 0xc0, 0x08,
++ 0xc1, 0x10,
++ 0xc2, 0x08,
++ 0xc3, 0x10,
++ 0xc4, 0x08,
++ 0xc5, 0xf0,
++ 0xc6, 0xf0,
++ 0xc7, 0x0a,
++ 0xc8, 0x1a,
++ 0xc9, 0x80,
++ 0xca, 0x23,
++ 0xcb, 0x24,
++ 0xce, 0x74,
++ 0x56, 0x01,
++ 0x90, 0x03,
++ 0x76, 0x80,
++ 0x77, 0x42,
++ 0x78, 0x0a,
++ 0x79, 0x80,
++ 0xad, 0x40,
++ 0xae, 0x07,
++ 0x7f, 0xd4,
++ 0x7c, 0x00,
++ 0x80, 0xa8,
++ 0x81, 0xda,
++ 0x7c, 0x01,
++ 0x80, 0xda,
++ 0x81, 0xec,
++ 0x7c, 0x02,
++ 0x80, 0xca,
++ 0x81, 0xeb,
++ 0x7c, 0x03,
++ 0x80, 0xba,
++ 0x81, 0xdb,
++ 0x85, 0x08,
++ 0x86, 0x00,
++ 0x87, 0x02,
++ 0x89, 0x80,
++ 0x8b, 0x44,
++ 0x8c, 0xaa,
++ 0x8a, 0x10,
++ 0xba, 0x00,
++ 0xf5, 0x04,
++ 0xd2, 0x32,
++ 0xb8, 0x00,
++};
++
++#endif /* M88DS3103_PRIV_H */
+diff -urN a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
+--- a/drivers/media/dvb/frontends/Makefile 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/dvb/frontends/Makefile 2012-11-18 23:23:46.929156046 +0800
+@@ -102,4 +102,7 @@
+ obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
+ obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
+ obj-$(CONFIG_DVB_AF9033) += af9033.o
++obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
++obj-$(CONFIG_DVB_M88DC2800) += m88dc2800.o
++
+
+diff -urN a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
+--- a/drivers/media/rc/keymaps/Makefile 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/rc/keymaps/Makefile 2012-11-18 23:24:05.477156546 +0800
+@@ -27,6 +27,7 @@
+ rc-dm1105-nec.o \
+ rc-dntv-live-dvb-t.o \
+ rc-dntv-live-dvbt-pro.o \
++ rc-dvbsky.o \
+ rc-em-terratec.o \
+ rc-encore-enltv2.o \
+ rc-encore-enltv.o \
+diff -urN a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
+--- a/drivers/media/rc/keymaps/rc-dvbsky.c 1970-01-01 08:00:00.000000000 +0800
++++ b/drivers/media/rc/keymaps/rc-dvbsky.c 2012-11-18 23:24:09.673156652 +0800
+@@ -0,0 +1,78 @@
++/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers
++ *
++ * keymap imported from ir-keymaps.c
++ *
++ *
++ * Copyright (c) 2010-2011 by Mauro Carvalho Chehab
++ *
++ * 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.
++ */
++
++#include
++#include
++/*
++ * This table contains the complete RC5 code, instead of just the data part
++ */
++
++static struct rc_map_table rc5_dvbsky[] = {
++ { 0x0000, KEY_0 },
++ { 0x0001, KEY_1 },
++ { 0x0002, KEY_2 },
++ { 0x0003, KEY_3 },
++ { 0x0004, KEY_4 },
++ { 0x0005, KEY_5 },
++ { 0x0006, KEY_6 },
++ { 0x0007, KEY_7 },
++ { 0x0008, KEY_8 },
++ { 0x0009, KEY_9 },
++ { 0x000a, KEY_MUTE },
++ { 0x000d, KEY_OK },
++ { 0x000b, KEY_STOP },
++ { 0x000c, KEY_EXIT },
++ { 0x000e, KEY_CAMERA }, /*Snap shot*/
++ { 0x000f, KEY_SUBTITLE }, /*PIP*/
++ { 0x0010, KEY_VOLUMEUP },
++ { 0x0011, KEY_VOLUMEDOWN },
++ { 0x0012, KEY_FAVORITES },
++ { 0x0013, KEY_LIST }, /*Info*/
++ { 0x0016, KEY_PAUSE },
++ { 0x0017, KEY_PLAY },
++ { 0x001f, KEY_RECORD },
++ { 0x0020, KEY_CHANNELDOWN },
++ { 0x0021, KEY_CHANNELUP },
++ { 0x0025, KEY_POWER2 },
++ { 0x0026, KEY_REWIND },
++ { 0x0027, KEY_FASTFORWARD },
++ { 0x0029, KEY_LAST },
++ { 0x002b, KEY_MENU },
++ { 0x002c, KEY_EPG },
++ { 0x002d, KEY_ZOOM },
++};
++
++static struct rc_map_list rc5_dvbsky_map = {
++ .map = {
++ .scan = rc5_dvbsky,
++ .size = ARRAY_SIZE(rc5_dvbsky),
++ .rc_type = RC_TYPE_RC5,
++ .name = RC_MAP_DVBSKY,
++ }
++};
++
++static int __init init_rc_map_rc5_dvbsky(void)
++{
++ return rc_map_register(&rc5_dvbsky_map);
++}
++
++static void __exit exit_rc_map_rc5_dvbsky(void)
++{
++ rc_map_unregister(&rc5_dvbsky_map);
++}
++
++module_init(init_rc_map_rc5_dvbsky)
++module_exit(exit_rc_map_rc5_dvbsky)
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mauro Carvalho Chehab ");
+diff -urN a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
+--- a/drivers/media/video/cx23885/cimax2.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cimax2.c 2012-11-18 23:24:25.949157092 +0800
+@@ -412,7 +412,7 @@
+ return state->status;
+ }
+
+-int netup_ci_init(struct cx23885_tsport *port)
++int netup_ci_init(struct cx23885_tsport *port, bool isDVBSky)
+ {
+ struct netup_ci_state *state;
+ u8 cimax_init[34] = {
+@@ -461,6 +461,11 @@
+ goto err;
+ }
+
++ if(isDVBSky) {
++ cimax_init[32] = 0x22;
++ cimax_init[33] = 0x00;
++ }
++
+ port->port_priv = state;
+
+ switch (port->nr) {
+@@ -534,3 +539,19 @@
+ dvb_ca_en50221_release(&state->ca);
+ kfree(state);
+ }
++
++/* CI irq handler for DVBSky board*/
++int dvbsky_ci_slot_status(struct cx23885_dev *dev)
++{
++ struct cx23885_tsport *port = NULL;
++ struct netup_ci_state *state = NULL;
++
++ ci_dbg_print("%s:\n", __func__);
++
++ port = &dev->ts1;
++ state = port->port_priv;
++ schedule_work(&state->work);
++ ci_dbg_print("%s: Wakeup CI0\n", __func__);
++
++ return 1;
++}
+diff -urN a/drivers/media/video/cx23885/cimax2.h b/drivers/media/video/cx23885/cimax2.h
+--- a/drivers/media/video/cx23885/cimax2.h 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cimax2.h 2012-11-18 23:24:32.629157268 +0800
+@@ -41,7 +41,9 @@
+ extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status);
+ extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221,
+ int slot, int open);
+-extern int netup_ci_init(struct cx23885_tsport *port);
++extern int netup_ci_init(struct cx23885_tsport *port, bool isDVBSky);
+ extern void netup_ci_exit(struct cx23885_tsport *port);
+
++extern int dvbsky_ci_slot_status(struct cx23885_dev *dev);
++
+ #endif
+diff -urN a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
+--- a/drivers/media/video/cx23885/cx23885-cards.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cx23885-cards.c 2012-11-18 23:24:41.985157518 +0800
+@@ -564,7 +564,30 @@
+ [CX23885_BOARD_TEVII_S471] = {
+ .name = "TeVii S471",
+ .portb = CX23885_MPEG_DVB,
+- }
++ },
++ [CX23885_BOARD_BST_PS8512] = {
++ .name = "Bestunar PS8512",
++ .portb = CX23885_MPEG_DVB,
++ },
++ [CX23885_BOARD_DVBSKY_S950] = {
++ .name = "DVBSKY S950",
++ .portb = CX23885_MPEG_DVB,
++ },
++ [CX23885_BOARD_DVBSKY_S952] = {
++ .name = "DVBSKY S952",
++ .portb = CX23885_MPEG_DVB,
++ .portc = CX23885_MPEG_DVB,
++ },
++ [CX23885_BOARD_DVBSKY_S950_CI] = {
++ .ci_type = 3,
++ .name = "DVBSKY S950CI DVB-S2 CI",
++ .portb = CX23885_MPEG_DVB,
++ },
++ [CX23885_BOARD_DVBSKY_C2800E_CI] = {
++ .ci_type = 3,
++ .name = "DVBSKY C2800E DVB-C CI",
++ .portb = CX23885_MPEG_DVB,
++ },
+ };
+ const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+@@ -776,6 +799,26 @@
+ .subvendor = 0xd471,
+ .subdevice = 0x9022,
+ .card = CX23885_BOARD_TEVII_S471,
++ }, {
++ .subvendor = 0x14f1,
++ .subdevice = 0x8512,
++ .card = CX23885_BOARD_BST_PS8512,
++ }, {
++ .subvendor = 0x4254,
++ .subdevice = 0x0950,
++ .card = CX23885_BOARD_DVBSKY_S950,
++ }, {
++ .subvendor = 0x4254,
++ .subdevice = 0x0952,
++ .card = CX23885_BOARD_DVBSKY_S952,
++ }, {
++ .subvendor = 0x4254,
++ .subdevice = 0x950C,
++ .card = CX23885_BOARD_DVBSKY_S950_CI,
++ }, {
++ .subvendor = 0x4254,
++ .subdevice = 0x2800,
++ .card = CX23885_BOARD_DVBSKY_C2800E_CI,
+ },
+ };
+ const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+@@ -1288,9 +1331,83 @@
+ /* enable irq */
+ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+ break;
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_BST_PS8512:
++ cx23885_gpio_enable(dev, GPIO_2, 1);
++ cx23885_gpio_clear(dev, GPIO_2);
++ msleep(100);
++ cx23885_gpio_set(dev, GPIO_2);
++ break;
++ case CX23885_BOARD_DVBSKY_S952:
++ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
++
++ cx23885_gpio_enable(dev, GPIO_2, 1);
++ cx23885_gpio_enable(dev, GPIO_11, 1);
++
++ cx23885_gpio_clear(dev, GPIO_2);
++ cx23885_gpio_clear(dev, GPIO_11);
++ msleep(100);
++ cx23885_gpio_set(dev, GPIO_2);
++ cx23885_gpio_set(dev, GPIO_11);
++ break;
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
++ /* GPIO-0 INTA from CiMax, input
++ GPIO-1 reset CiMax, output, high active
++ GPIO-2 reset demod, output, low active
++ GPIO-3 to GPIO-10 data/addr for CAM
++ GPIO-11 ~CS0 to CiMax1
++ GPIO-12 ~CS1 to CiMax2
++ GPIO-13 ADL0 load LSB addr
++ GPIO-14 ADL1 load MSB addr
++ GPIO-15 ~RDY from CiMax
++ GPIO-17 ~RD to CiMax
++ GPIO-18 ~WR to CiMax
++ */
++ cx_set(GP0_IO, 0x00060002); /* GPIO 1/2 as output */
++ cx_clear(GP0_IO, 0x00010004); /*GPIO 0 as input*/
++ mdelay(100);/* reset delay */
++ cx_set(GP0_IO, 0x00060004); /* GPIO as out, reset high */
++ cx_clear(GP0_IO, 0x00010002);
++ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
++ /* GPIO-15 IN as ~ACK, rest as OUT */
++ cx_write(MC417_OEN, 0x00001000);
++ /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
++ cx_write(MC417_RWD, 0x0000c300);
++ /* enable irq */
++ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
++ break;
+ }
+ }
+
++static int cx23885_ir_patch(struct i2c_adapter *i2c, u8 reg, u8 mask)
++{
++ struct i2c_msg msgs[2];
++ u8 tx_buf[2], rx_buf[1];
++ /* Write register address */
++ tx_buf[0] = reg;
++ msgs[0].addr = 0x4c;
++ msgs[0].flags = 0;
++ msgs[0].len = 1;
++ msgs[0].buf = (char *) tx_buf;
++ /* Read data from register */
++ msgs[1].addr = 0x4c;
++ msgs[1].flags = I2C_M_RD;
++ msgs[1].len = 1;
++ msgs[1].buf = (char *) rx_buf;
++
++ i2c_transfer(i2c, msgs, 2);
++
++ tx_buf[0] = reg;
++ tx_buf[1] = rx_buf[0] | mask;
++ msgs[0].addr = 0x4c;
++ msgs[0].flags = 0;
++ msgs[0].len = 2;
++ msgs[0].buf = (char *) tx_buf;
++
++ return i2c_transfer(i2c, msgs, 1);
++}
++
+ int cx23885_ir_init(struct cx23885_dev *dev)
+ {
+ static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
+@@ -1374,6 +1491,22 @@
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+ break;
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
++ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
++ if (dev->sd_ir == NULL) {
++ ret = -ENODEV;
++ break;
++ }
++ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
++ ir_rx_pin_cfg_count, ir_rx_pin_cfg);
++
++ cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x1f,0x80);
++ cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x23,0x80);
++ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ if (!enable_885_ir)
+ break;
+@@ -1405,6 +1538,11 @@
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
+ /* sd_ir is a duplicate pointer to the AV Core, just clear it */
+ dev->sd_ir = NULL;
+@@ -1448,6 +1586,11 @@
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ if (dev->sd_ir)
+ cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
+ break;
+@@ -1533,6 +1676,10 @@
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_TEVII_S471:
+ case CX23885_BOARD_DVBWORLD_2005:
+@@ -1564,6 +1711,14 @@
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
++ case CX23885_BOARD_DVBSKY_S952:
++ ts1->gen_ctrl_val = 0x5; /* Parallel */
++ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
++ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
++ ts2->gen_ctrl_val = 0xe; /* Serial bus + punctured clock */
++ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
++ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
++ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+@@ -1619,6 +1774,11 @@
+ case CX23885_BOARD_MPX885:
+ case CX23885_BOARD_MYGICA_X8507:
+ case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_bus[2].i2c_adap,
+ "cx25840", 0x88 >> 1, NULL);
+diff -urN a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
+--- a/drivers/media/video/cx23885/cx23885-core.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cx23885-core.c 2012-11-18 23:24:52.437157796 +0800
+@@ -1911,6 +1911,10 @@
+ (pci_status & PCI_MSK_GPIO0))
+ handled += altera_ci_irq(dev);
+
++ if (cx23885_boards[dev->board].ci_type == 3 &&
++ (pci_status & PCI_MSK_GPIO0))
++ handled += dvbsky_ci_slot_status(dev);
++
+ if (ts1_status) {
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ handled += cx23885_irq_ts(ts1, ts1_status);
+@@ -2146,6 +2150,8 @@
+ cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0);
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ cx23885_irq_add_enable(dev, PCI_MSK_GPIO0);
+ break;
+ }
+diff -urN a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
+--- a/drivers/media/video/cx23885/cx23885-dvb.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cx23885-dvb.c 2012-11-18 23:24:57.401157930 +0800
+@@ -51,6 +51,8 @@
+ #include "stv6110.h"
+ #include "lnbh24.h"
+ #include "cx24116.h"
++#include "m88ds3103.h"
++#include "m88dc2800.h"
+ #include "cimax2.h"
+ #include "lgs8gxx.h"
+ #include "netup-eeprom.h"
+@@ -489,6 +491,42 @@
+ .if_khz = 5380,
+ };
+
++/* bestunar single dvb-s2 */
++static struct m88ds3103_config bst_ds3103_config = {
++ .demod_address = 0x68,
++ .ci_mode = 0,
++ .pin_ctrl = 0x82,
++ .ts_mode = 0,
++ .set_voltage = bst_set_voltage,
++};
++/* DVBSKY dual dvb-s2 */
++static struct m88ds3103_config dvbsky_ds3103_config_pri = {
++ .demod_address = 0x68,
++ .ci_mode = 0,
++ .pin_ctrl = 0x82,
++ .ts_mode = 0,
++ .set_voltage = bst_set_voltage,
++};
++static struct m88ds3103_config dvbsky_ds3103_config_sec = {
++ .demod_address = 0x68,
++ .ci_mode = 0,
++ .pin_ctrl = 0x82,
++ .ts_mode = 1,
++ .set_voltage = dvbsky_set_voltage_sec,
++};
++
++static struct m88ds3103_config dvbsky_ds3103_ci_config = {
++ .demod_address = 0x68,
++ .ci_mode = 2,
++ .pin_ctrl = 0x82,
++ .ts_mode = 0,
++};
++
++static struct m88dc2800_config dvbsky_dc2800_config = {
++ .demod_address = 0x1c,
++ .ts_mode = 3,
++};
++
+ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
+ {
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+@@ -1186,6 +1224,47 @@
+ &tevii_ds3000_config,
+ &i2c_bus->i2c_adap);
+ break;
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ i2c_bus = &dev->i2c_bus[1];
++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
++ &bst_ds3103_config,
++ &i2c_bus->i2c_adap);
++ break;
++
++ case CX23885_BOARD_DVBSKY_S952:
++ switch (port->nr) {
++ /* port B */
++ case 1:
++ i2c_bus = &dev->i2c_bus[1];
++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
++ &dvbsky_ds3103_config_pri,
++ &i2c_bus->i2c_adap);
++ break;
++ /* port C */
++ case 2:
++ i2c_bus = &dev->i2c_bus[0];
++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
++ &dvbsky_ds3103_config_sec,
++ &i2c_bus->i2c_adap);
++ break;
++ }
++ break;
++
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ i2c_bus = &dev->i2c_bus[1];
++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
++ &dvbsky_ds3103_ci_config,
++ &i2c_bus->i2c_adap);
++ break;
++
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
++ i2c_bus = &dev->i2c_bus[1];
++ fe0->dvb.frontend = dvb_attach(m88dc2800_attach,
++ &dvbsky_dc2800_config,
++ &i2c_bus->i2c_adap);
++ break;
++
+ default:
+ printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
+ " isn't supported yet\n",
+@@ -1234,7 +1313,7 @@
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
+ port->nr, port->frontends.adapter.proposed_mac);
+
+- netup_ci_init(port);
++ netup_ci_init(port, false);
+ break;
+ }
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+@@ -1261,6 +1340,40 @@
+ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
+ break;
+ }
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:{
++ u8 eeprom[256]; /* 24C02 i2c eeprom */
++
++ if(port->nr > 2)
++ break;
++
++ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
++ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
++ printk(KERN_INFO "DVBSKY PCIe MAC= %pM\n", eeprom + 0xc0+(port->nr-1)*8);
++ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
++ (port->nr-1)*8, 6);
++ break;
++ }
++ case CX23885_BOARD_DVBSKY_S950_CI: {
++ u8 eeprom[256]; /* 24C02 i2c eeprom */
++
++ if(port->nr > 2)
++ break;
++
++ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
++ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
++ printk(KERN_INFO "DVBSKY PCIe MAC= %pM\n", eeprom + 0xc0+(port->nr-1)*8);
++ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
++ (port->nr-1)*8, 6);
++
++ netup_ci_init(port, true);
++ break;
++ }
++ case CX23885_BOARD_DVBSKY_C2800E_CI: {
++ netup_ci_init(port, true);
++ break;
++ }
+ }
+
+ return ret;
+@@ -1343,6 +1456,8 @@
+
+ switch (port->dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ netup_ci_exit(port);
+ break;
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+diff -urN a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c
+--- a/drivers/media/video/cx23885/cx23885-f300.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cx23885-f300.c 2012-11-18 23:25:02.869158076 +0800
+@@ -175,3 +175,58 @@
+
+ return f300_xfer(fe, buf);
+ }
++
++/* bst control */
++int bst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++{
++ struct cx23885_tsport *port = fe->dvb->priv;
++ struct cx23885_dev *dev = port->dev;
++
++ cx23885_gpio_enable(dev, GPIO_1, 1);
++ cx23885_gpio_enable(dev, GPIO_0, 1);
++
++ switch (voltage) {
++ case SEC_VOLTAGE_13:
++ cx23885_gpio_set(dev, GPIO_1);
++ cx23885_gpio_clear(dev, GPIO_0);
++ break;
++ case SEC_VOLTAGE_18:
++ cx23885_gpio_set(dev, GPIO_1);
++ cx23885_gpio_set(dev, GPIO_0);
++ break;
++ case SEC_VOLTAGE_OFF:
++ cx23885_gpio_clear(dev, GPIO_1);
++ cx23885_gpio_clear(dev, GPIO_0);
++ break;
++ }
++
++
++ return 0;
++}
++
++int dvbsky_set_voltage_sec(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
++{
++ struct cx23885_tsport *port = fe->dvb->priv;
++ struct cx23885_dev *dev = port->dev;
++
++ cx23885_gpio_enable(dev, GPIO_12, 1);
++ cx23885_gpio_enable(dev, GPIO_13, 1);
++
++ switch (voltage) {
++ case SEC_VOLTAGE_13:
++ cx23885_gpio_set(dev, GPIO_13);
++ cx23885_gpio_clear(dev, GPIO_12);
++ break;
++ case SEC_VOLTAGE_18:
++ cx23885_gpio_set(dev, GPIO_13);
++ cx23885_gpio_set(dev, GPIO_12);
++ break;
++ case SEC_VOLTAGE_OFF:
++ cx23885_gpio_clear(dev, GPIO_13);
++ cx23885_gpio_clear(dev, GPIO_12);
++ break;
++ }
++
++
++ return 0;
++}
+\ No newline at end of file
+diff -urN a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h
+--- a/drivers/media/video/cx23885/cx23885-f300.h 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cx23885-f300.h 2012-11-18 23:25:22.493158602 +0800
+@@ -1,2 +1,8 @@
++extern int dvbsky_set_voltage_sec(struct dvb_frontend *fe,
++ fe_sec_voltage_t voltage);
++
++extern int bst_set_voltage(struct dvb_frontend *fe,
++ fe_sec_voltage_t voltage);
++
+ extern int f300_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage);
+diff -urN a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
+--- a/drivers/media/video/cx23885/cx23885.h 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cx23885.h 2012-11-18 23:24:37.021157384 +0800
+@@ -90,6 +90,11 @@
+ #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
+ #define CX23885_BOARD_TEVII_S471 35
+ #define CX23885_BOARD_HAUPPAUGE_HVR1255_22111 36
++#define CX23885_BOARD_BST_PS8512 37
++#define CX23885_BOARD_DVBSKY_S952 38
++#define CX23885_BOARD_DVBSKY_S950 39
++#define CX23885_BOARD_DVBSKY_S950_CI 40
++#define CX23885_BOARD_DVBSKY_C2800E_CI 41
+
+ #define GPIO_0 0x00000001
+ #define GPIO_1 0x00000002
+@@ -228,7 +233,7 @@
+ */
+ u32 clk_freq;
+ struct cx23885_input input[MAX_CX23885_INPUT];
+- int ci_type; /* for NetUP */
++ int ci_type; /* 1 and 2 for NetUP, 3 for DVBSky. */
+ /* Force bottom field first during DMA (888 workaround) */
+ u32 force_bff;
+ };
+diff -urN a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
+--- a/drivers/media/video/cx23885/cx23885-input.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/cx23885-input.c 2012-11-18 23:25:34.089158915 +0800
+@@ -87,6 +87,11 @@
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ /*
+ * The only boards we handle right now. However other boards
+ * using the CX2388x integrated IR controller should be similar
+@@ -138,6 +143,11 @@
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
+ /*
+ * The IR controller on this board only returns pulse widths.
+ * Any other mode setting will fail to set up the device.
+@@ -279,6 +289,17 @@
+ /* A guess at the remote */
+ rc_map = RC_MAP_TEVII_NEC;
+ break;
++ case CX23885_BOARD_BST_PS8512:
++ case CX23885_BOARD_DVBSKY_S950:
++ case CX23885_BOARD_DVBSKY_S952:
++ case CX23885_BOARD_DVBSKY_S950_CI:
++ case CX23885_BOARD_DVBSKY_C2800E_CI:
++ /* Integrated CX2388[58] IR controller */
++ driver_type = RC_DRIVER_IR_RAW;
++ allowed_protos = RC_TYPE_ALL;
++ /* A guess at the remote */
++ rc_map = RC_MAP_DVBSKY;
++ break;
+ default:
+ return -ENODEV;
+ }
+diff -urN a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
+--- a/drivers/media/video/cx23885/Kconfig 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx23885/Kconfig 2012-11-18 23:25:39.221159051 +0800
+@@ -20,6 +20,8 @@
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_STV6110 if !DVB_FE_CUSTOMISE
+ select DVB_CX24116 if !DVB_FE_CUSTOMISE
++ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
++ select DVB_M88DC2800 if !DVB_FE_CUSTOMISE
+ select DVB_STV0900 if !DVB_FE_CUSTOMISE
+ select DVB_DS3000 if !DVB_FE_CUSTOMISE
+ select DVB_STV0367 if !DVB_FE_CUSTOMISE
+diff -urN a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
+--- a/drivers/media/video/cx88/cx88-cards.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx88/cx88-cards.c 2012-11-18 23:26:46.493160850 +0800
+@@ -2309,6 +2309,18 @@
+ } },
+ .mpeg = CX88_MPEG_DVB,
+ },
++ [CX88_BOARD_BST_PS8312] = {
++ .name = "Bestunar PS8312 DVB-S/S2",
++ .tuner_type = UNSET,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .input = {{
++ .type = CX88_VMUX_DVB,
++ .vmux = 0,
++ } },
++ .mpeg = CX88_MPEG_DVB,
++ },
+ };
+
+ /* ------------------------------------------------------------------ */
+@@ -2813,6 +2825,10 @@
+ .subvendor = 0x1822,
+ .subdevice = 0x0023,
+ .card = CX88_BOARD_TWINHAN_VP1027_DVBS,
++ }, {
++ .subvendor = 0x14f1,
++ .subdevice = 0x8312,
++ .card = CX88_BOARD_BST_PS8312,
+ },
+ };
+
+@@ -3547,6 +3563,12 @@
+ cx_write(MO_SRST_IO, 1);
+ msleep(100);
+ break;
++ case CX88_BOARD_BST_PS8312:
++ cx_write(MO_GP1_IO, 0x808000);
++ msleep(100);
++ cx_write(MO_GP1_IO, 0x808080);
++ msleep(100);
++ break;
+ } /*end switch() */
+
+
+diff -urN a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
+--- a/drivers/media/video/cx88/cx88-dvb.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx88/cx88-dvb.c 2012-11-18 23:26:51.733160994 +0800
+@@ -54,6 +54,7 @@
+ #include "stv0288.h"
+ #include "stb6000.h"
+ #include "cx24116.h"
++#include "m88ds3103.h"
+ #include "stv0900.h"
+ #include "stb6100.h"
+ #include "stb6100_proc.h"
+@@ -458,6 +459,56 @@
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
+ }
++/*CX88_BOARD_BST_PS8312*/
++static int bst_dvbs_set_voltage(struct dvb_frontend *fe,
++ fe_sec_voltage_t voltage)
++{
++ struct cx8802_dev *dev= fe->dvb->priv;
++ struct cx88_core *core = dev->core;
++
++ cx_write(MO_GP1_IO, 0x111111);
++ switch (voltage) {
++ case SEC_VOLTAGE_13:
++ cx_write(MO_GP1_IO, 0x020200);
++ break;
++ case SEC_VOLTAGE_18:
++ cx_write(MO_GP1_IO, 0x020202);
++ break;
++ case SEC_VOLTAGE_OFF:
++ cx_write(MO_GP1_IO, 0x111100);
++ break;
++ }
++
++ if (core->prev_set_voltage)
++ return core->prev_set_voltage(fe, voltage);
++ return 0;
++}
++
++static int bst_dvbs_set_voltage_v2(struct dvb_frontend *fe,
++ fe_sec_voltage_t voltage)
++{
++ struct cx8802_dev *dev= fe->dvb->priv;
++ struct cx88_core *core = dev->core;
++
++ cx_write(MO_GP1_IO, 0x111101);
++ switch (voltage) {
++ case SEC_VOLTAGE_13:
++ cx_write(MO_GP1_IO, 0x020200);
++ break;
++ case SEC_VOLTAGE_18:
++
++ cx_write(MO_GP1_IO, 0x020202);
++ break;
++ case SEC_VOLTAGE_OFF:
++
++ cx_write(MO_GP1_IO, 0x111110);
++ break;
++ }
++
++ if (core->prev_set_voltage)
++ return core->prev_set_voltage(fe, voltage);
++ return 0;
++}
+
+ static int vp1027_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+@@ -700,6 +751,11 @@
+ .set_ts_params = ds3000_set_ts_param,
+ };
+
++static struct m88ds3103_config dvbsky_ds3103_config = {
++ .demod_address = 0x68,
++ .set_ts_params = ds3000_set_ts_param,
++};
++
+ static const struct stv0900_config prof_7301_stv0900_config = {
+ .demod_address = 0x6a,
+ /* demod_mode = 0,*/
+@@ -1470,6 +1526,35 @@
+ fe0->dvb.frontend->ops.set_voltage =
+ tevii_dvbs_set_voltage;
+ break;
++ case CX88_BOARD_BST_PS8312:
++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
++ &dvbsky_ds3103_config,
++ &core->i2c_adap);
++ if (fe0->dvb.frontend != NULL){
++ int ret;
++ u8 b0[] = { 0x60 };
++ u8 b1[2] = { 0 };
++ struct i2c_msg msg[] = {
++ {
++ .addr = 0x50,
++ .flags = 0,
++ .buf = b0,
++ .len = 1
++ }, {
++ .addr = 0x50,
++ .flags = I2C_M_RD,
++ .buf = b1,
++ .len = 2
++ }
++ };
++ ret = i2c_transfer(&core->i2c_adap, msg, 2);
++ printk("PS8312: config = %02x, %02x", b1[0],b1[1]);
++ if(b1[0] == 0xaa)
++ fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage_v2;
++ else
++ fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage;
++ }
++ break;
+ case CX88_BOARD_OMICOM_SS4_PCI:
+ case CX88_BOARD_TBS_8920:
+ case CX88_BOARD_PROF_7300:
+diff -urN a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
+--- a/drivers/media/video/cx88/cx88.h 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx88/cx88.h 2012-11-18 23:26:40.701160685 +0800
+@@ -238,6 +238,7 @@
+ #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
+ #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89
+ #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90
++#define CX88_BOARD_BST_PS8312 91
+
+ enum cx88_itype {
+ CX88_VMUX_COMPOSITE1 = 1,
+diff -urN a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
+--- a/drivers/media/video/cx88/cx88-input.c 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx88/cx88-input.c 2012-11-18 23:26:56.589161123 +0800
+@@ -419,6 +419,10 @@
+ rc_type = RC_TYPE_NEC;
+ ir->sampling = 0xff00; /* address */
+ break;
++ case CX88_BOARD_BST_PS8312:
++ ir_codes = RC_MAP_DVBSKY;
++ ir->sampling = 0xff00; /* address */
++ break;
+ }
+
+ if (!ir_codes) {
+diff -urN a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
+--- a/drivers/media/video/cx88/Kconfig 2012-11-05 16:57:06.000000000 +0800
++++ b/drivers/media/video/cx88/Kconfig 2012-11-18 23:27:01.261161247 +0800
+@@ -57,6 +57,7 @@
+ select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+ select DVB_CX24116 if !DVB_FE_CUSTOMISE
++ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_STV0288 if !DVB_FE_CUSTOMISE
+ select DVB_STB6000 if !DVB_FE_CUSTOMISE
+diff -urN a/include/media/rc-map.h b/include/media/rc-map.h
+--- a/include/media/rc-map.h 2012-11-05 16:57:06.000000000 +0800
++++ b/include/media/rc-map.h 2012-11-18 23:22:21.777153765 +0800
+@@ -86,6 +86,7 @@
+ #define RC_MAP_DM1105_NEC "rc-dm1105-nec"
+ #define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro"
+ #define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t"
++#define RC_MAP_DVBSKY "rc-dvbsky"
+ #define RC_MAP_EMPTY "rc-empty"
+ #define RC_MAP_EM_TERRATEC "rc-em-terratec"
+ #define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2"
diff --git a/packages/mediacenter/xbmc/patches/xbmc-4bf192d-457-fix_connection_check-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-4bf192d-457-fix_connection_check-0.1.patch
index 9488def289..f7c4f4a98f 100644
--- a/packages/mediacenter/xbmc/patches/xbmc-4bf192d-457-fix_connection_check-0.1.patch
+++ b/packages/mediacenter/xbmc/patches/xbmc-4bf192d-457-fix_connection_check-0.1.patch
@@ -6,10 +6,10 @@ diff -Naur a/xbmc/filesystem/CurlFile.cpp b/xbmc/filesystem/CurlFile.cpp
bool CFileCurl::IsInternet(bool checkDNS /* = true */)
{
- CStdString strURL = "http://www.google.com";
-+ CStdString strURL = "http://www.openelec.tv";
++ CStdString strURL = "http://openelec.tv";
if (!checkDNS)
- strURL = "http://74.125.19.103"; // www.google.com ip
-+ strURL = "http://212.101.13.10"; // www.openelec.tv ip
++ strURL = "http://212.101.13.10"; // openelec.tv ip
bool found = Exists(strURL);
Close();
diff --git a/packages/tools/syslinux/files/create_virtualimage b/packages/tools/syslinux/files/create_virtualimage
index 565b6266fb..bdb8feeee1 100755
--- a/packages/tools/syslinux/files/create_virtualimage
+++ b/packages/tools/syslinux/files/create_virtualimage
@@ -20,29 +20,55 @@
# http://www.gnu.org/copyleft/gpl.html
################################################################################
-# usage: sudo ./create_virtualmachine
-# example: sudo ./create_virtualmachine /home/test/VM
+# usage: sudo ./create_virtualmachine []
+# example: sudo ./create_virtualmachine /home/test/VM 512 [vdi]
if [ "$(id -u)" != "0" ]; then
+ clear
+ echo "###########################################################"
+ echo "# please execute with 'sudo' or -DANGEROUS!!!- as root #"
+ echo "# example: #"
+ echo "# sudo ./create_virtualmachine [] #"
+ echo "###########################################################"
+ exit 1
+fi
+
+if [ -z "$1" -o -z "$2" ]; then
+ clear
+ echo "###########################################################"
+ echo "# please execute as follows #"
+ echo "# example: #"
+ echo "# sudo ./create_virtualmachine [] #"
+ echo "###########################################################"
+ exit 1
+fi
+
+if [ "$2" -lt "200" -o "$2" -gt "2048" ]; then
clear
echo "#########################################################"
- echo "# please execute with 'sudo' or -DANGEROUS!!!- as root #"
- echo "# example: sudo ./create_virtualmachine #"
+ echo "# use a value between 200MB and 2048MB (2GB) #"
+ echo "# example: #"
+ echo "# sudo ./create_virtualmachine /home/test/VM 512 #"
echo "#########################################################"
exit 1
fi
-if [ -z "$1" ]; then
+if [ ! -z "$3" -a "$3" != "vdi" -a "$3" != "vmdk" ]; then
clear
echo "#########################################################"
- echo "# please execute with target folder drive as option #"
- echo "# example: sudo ./create_virtualmachine /home/test/VM/ #"
+ echo "# only vdi or vmdk types are supported #"
+ echo "# example: #"
+ echo "# sudo ./create_virtualmachine /home/test/VM 512 [vdi] #"
echo "#########################################################"
exit 1
+elif [ "$3" = "vdi" ]; then
+ TYPE="vdi"
+elif [ -z "$3" -o "$3" = "vmdk" ]; then
+ TYPE="vmdk"
fi
DISK="$1/OpenELEC.img"
-VMDK="$1/OpenELEC.vmdk"
+IMAGE="$1/OpenELEC.$TYPE"
LOOP=$(losetup -f)
clear
@@ -109,7 +135,7 @@ echo "#########################################################"
exit 1
fi
- # this is needed fo convert harddisk image to vmdk format
+ # this is needed fo convert harddisk image to vmdk or vdi format
which qemu-img > /dev/null
if [ "$?" = "1" ]; then
clear
@@ -159,7 +185,7 @@ echo "#########################################################"
# create an image
echo "creating new empty harddisk image: $DISK..."
- dd if=/dev/zero of="$DISK" bs=1M count=512
+ dd if=/dev/zero of="$DISK" bs=1M count=1024
# write a disklabel
echo "creating new partition table: $DISK..."
@@ -168,15 +194,27 @@ echo "#########################################################"
# create partition1
echo "creating partition1 on $DISK..."
- parted -s "$LOOP" -a min unit s mkpart primary ext4 64 262208
+ parted -s "$LOOP" unit cyl mkpart primary ext2 -- 0 16
# create partition2
echo "creating partition2 on $DISK..."
- parted -s "$LOOP" -a min unit s mkpart primary ext4 262209 100%
-
+ parted -s "$LOOP" unit cyl mkpart primary ext2 -- 16 -2
+
# make partition1 active (bootable)
echo "marking partition1 active..."
parted -s "$LOOP" set 1 boot on
+
+ echo "telling kernel we have a new partition table..."
+ partprobe "$LOOP"
+
+# create filesystem on partition1
+ echo "creating filesystem on partition1..."
+ mkfs.ext4 "${LOOP}p1" -L System
+
+# create filesystem on partition2
+ echo "creating filesystem on partition2..."
+ mkfs.ext4 "${LOOP}p2" -L Storage
+ sync
# write mbr
echo "writing mbr..."
@@ -192,18 +230,10 @@ echo "#########################################################"
cat "$MBR" > "$LOOP"
fi
-# create filesystem on partition1
- echo "creating filesystem on partition1..."
- losetup -d "$LOOP"
- losetup -o 32768 --sizelimit 134218240 "$LOOP" "$DISK"
- mke2fs -t ext4 -m 0 "$LOOP"
- tune2fs -U random -L "System" "$LOOP"
- sync
-
# mount partition
echo "mounting partition1 on /tmp/vmware_install..."
mkdir -p /tmp/vmware_install
- mount "$LOOP" /tmp/vmware_install
+ mount "${LOOP}p1" /tmp/vmware_install
# create bootloader configuration
echo "creating bootloader configuration..."
@@ -213,7 +243,7 @@ echo "#########################################################"
echo " " >> /tmp/vmware_install/syslinux.cfg
echo "LABEL linux" >> /tmp/vmware_install/syslinux.cfg
echo " KERNEL /KERNEL" >> /tmp/vmware_install/syslinux.cfg
- echo " APPEND boot=LABEL=System disk=LABEL=Storage quiet ssh" >> /tmp/vmware_install/syslinux.cfg
+ echo " APPEND boot=LABEL=System disk=LABEL=Storage ssh debugging nosplash" >> /tmp/vmware_install/syslinux.cfg
# install extlinux
echo "installing extlinux to partition1..."
@@ -230,15 +260,7 @@ echo "#########################################################"
# unmount partition1
echo "unmounting partition1..."
- umount "$LOOP"
- sync
-
-# create filesystem on partition2
- echo "creating filesystem on partition2..."
- losetup -d "$LOOP"
- losetup -o 134251008 "$LOOP" "$DISK"
- mke2fs -t ext4 -m 0 "$LOOP"
- tune2fs -U random -L "Storage" "$LOOP"
+ umount "${LOOP}p1"
sync
# detach loop0
@@ -248,9 +270,10 @@ echo "#########################################################"
echo "cleaning tempdir..."
rm -rf /tmp/vmware_install
-# convert image to vmdk
- echo "converting $DISK to vmdk format..."
- qemu-img convert -O vmdk "$DISK" "$VMDK"
+# convert image to vmdk or vdi
+ echo "converting $DISK to $TYPE format..."
+ qemu-img convert -O $TYPE "$DISK" "$IMAGE"
rm -f "$DISK"
echo "...installation finished"
+
diff --git a/projects/ATV/linux/linux.i386.conf b/projects/ATV/linux/linux.i386.conf
index 1cb2a75b2c..d2117f1446 100644
--- a/projects/ATV/linux/linux.i386.conf
+++ b/projects/ATV/linux/linux.i386.conf
@@ -1918,7 +1918,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Fusion/linux/linux.i386.conf b/projects/Fusion/linux/linux.i386.conf
index fb74675aad..260c4952b1 100644
--- a/projects/Fusion/linux/linux.i386.conf
+++ b/projects/Fusion/linux/linux.i386.conf
@@ -2188,7 +2188,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Fusion/linux/linux.x86_64.conf b/projects/Fusion/linux/linux.x86_64.conf
index b211f26395..233dac040c 100644
--- a/projects/Fusion/linux/linux.x86_64.conf
+++ b/projects/Fusion/linux/linux.x86_64.conf
@@ -2137,7 +2137,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Generic/linux/linux.i386.conf b/projects/Generic/linux/linux.i386.conf
index 0de62865f8..2f55758dc0 100644
--- a/projects/Generic/linux/linux.i386.conf
+++ b/projects/Generic/linux/linux.i386.conf
@@ -2272,7 +2272,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Generic_OSS/linux/linux.i386.conf b/projects/Generic_OSS/linux/linux.i386.conf
index 93fd89fbae..9e79ddd3ce 100644
--- a/projects/Generic_OSS/linux/linux.i386.conf
+++ b/projects/Generic_OSS/linux/linux.i386.conf
@@ -2270,7 +2270,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/ION/linux/linux.i386.conf b/projects/ION/linux/linux.i386.conf
index 3a163fe742..6793e06550 100644
--- a/projects/ION/linux/linux.i386.conf
+++ b/projects/ION/linux/linux.i386.conf
@@ -2160,7 +2160,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/ION/linux/linux.x86_64.conf b/projects/ION/linux/linux.x86_64.conf
index 8a90138b7e..8b7addf793 100644
--- a/projects/ION/linux/linux.x86_64.conf
+++ b/projects/ION/linux/linux.x86_64.conf
@@ -2095,7 +2095,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Intel/linux/linux.i386.conf b/projects/Intel/linux/linux.i386.conf
index 613b6429f5..6b5950ba21 100644
--- a/projects/Intel/linux/linux.i386.conf
+++ b/projects/Intel/linux/linux.i386.conf
@@ -2177,7 +2177,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Intel/linux/linux.x86_64.conf b/projects/Intel/linux/linux.x86_64.conf
index 35bc30b56e..a470fc5050 100644
--- a/projects/Intel/linux/linux.x86_64.conf
+++ b/projects/Intel/linux/linux.x86_64.conf
@@ -2113,7 +2113,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/RPi/linux/linux.arm.conf b/projects/RPi/linux/linux.arm.conf
index f3eebf43b7..694b16754f 100644
--- a/projects/RPi/linux/linux.arm.conf
+++ b/projects/RPi/linux/linux.arm.conf
@@ -1510,7 +1510,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Ultra/linux/linux.x86_64.conf b/projects/Ultra/linux/linux.x86_64.conf
index 71c87b3196..6735750e58 100644
--- a/projects/Ultra/linux/linux.x86_64.conf
+++ b/projects/Ultra/linux/linux.x86_64.conf
@@ -1978,7 +1978,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Virtual/linux/linux.i386.conf b/projects/Virtual/linux/linux.i386.conf
index 7d8e7f2c33..63981794c4 100644
--- a/projects/Virtual/linux/linux.i386.conf
+++ b/projects/Virtual/linux/linux.i386.conf
@@ -2179,7 +2179,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/projects/Virtual/linux/linux.x86_64.conf b/projects/Virtual/linux/linux.x86_64.conf
index 78ace58c76..be6a1cd359 100644
--- a/projects/Virtual/linux/linux.x86_64.conf
+++ b/projects/Virtual/linux/linux.x86_64.conf
@@ -2114,7 +2114,7 @@ CONFIG_DVB_USB_CE6230=m
# CONFIG_DVB_USB_FRIIO is not set
# CONFIG_DVB_USB_EC168 is not set
CONFIG_DVB_USB_AZ6007=m
-# CONFIG_DVB_USB_AZ6027 is not set
+CONFIG_DVB_USB_AZ6027=m
# CONFIG_DVB_USB_LME2510 is not set
CONFIG_DVB_USB_TECHNISAT_USB2=m
CONFIG_DVB_USB_IT913X=m
diff --git a/tools/mkpkg/mkpkg_vdr-plugin-vnsiserver b/tools/mkpkg/mkpkg_vdr-plugin-vnsiserver
new file mode 100755
index 0000000000..de9b3b6caf
--- /dev/null
+++ b/tools/mkpkg/mkpkg_vdr-plugin-vnsiserver
@@ -0,0 +1,43 @@
+#!/bin/sh
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv)
+#
+# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to
+# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA.
+# http://www.gnu.org/copyleft/gpl.html
+################################################################################
+
+echo "getting sources..."
+ if [ ! -d vdr-plugin-vnsiserver.git ]; then
+ git clone git://github.com/opdenkamp/xbmc-pvr-addons.git vdr-plugin-vnsiserver.git
+ fi
+
+ cd vdr-plugin-vnsiserver.git
+ git pull
+ GIT_REV=`git log -n1 --format=%h`
+ cd ..
+
+echo "copying sources..."
+ rm -rf vdr-plugin-vnsiserver-$GIT_REV
+ cp -R vdr-plugin-vnsiserver.git/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver vdr-plugin-vnsiserver-$GIT_REV
+
+echo "cleaning sources..."
+ rm -rf vdr-plugin-vnsiserver-$GIT_REV/.git
+
+echo "packing sources..."
+ tar cvJf vdr-plugin-vnsiserver-$GIT_REV.tar.xz vdr-plugin-vnsiserver-$GIT_REV
+
+echo "remove temporary sourcedir..."
+ rm -rf vdr-plugin-vnsiserver-$GIT_REV