]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/commitdiff
v4l_dvb: add Bestunar US638x HD driver.
authorArne Fitzenreiter <arne_f@ipfire.org>
Sat, 24 Nov 2012 18:25:23 +0000 (19:25 +0100)
committerArne Fitzenreiter <arne_f@ipfire.org>
Sat, 24 Nov 2012 18:25:23 +0000 (19:25 +0100)
lfs/v4l-dvb
src/patches/v4l-dvb_bestunar_us638x.patch [new file with mode: 0644]

index 0256cc3e08d28f74f7aef05a7f197cd5702edfe3..ef0f383663007f5e3331107733b1cc92eb303e4f 100644 (file)
@@ -81,6 +81,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_rtl28xx_commented_usb_clear_halt.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_usbv2_dont_report_pidfilter_fail.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_fix_tua6034_pll.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_bestunar_us638x.patch
 
        cd $(DIR_APP) && make allyesconfig KERNELRELEASE=$(KVER)-$(VERSUFIX) VER=$(XVER)
 ifeq "$(KCFG)" "-omap"
diff --git a/src/patches/v4l-dvb_bestunar_us638x.patch b/src/patches/v4l-dvb_bestunar_us638x.patch
new file mode 100644 (file)
index 0000000..e3ac8d2
--- /dev/null
@@ -0,0 +1,2810 @@
+diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Kconfig v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Kconfig
+--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Kconfig     2012-08-22 05:45:23.000000000 +0200
++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Kconfig 2012-11-24 13:35:19.220030262 +0100
+@@ -200,6 +200,13 @@
+       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_SI21XX
+       tristate "Silicon Labs SI21XX based"
+       depends on DVB_CORE && I2C
+diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.c v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.c
+--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.c 1970-01-01 01:00:00.000000000 +0100
++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.c     2012-11-24 13:34:43.713346302 +0100
+@@ -0,0 +1,1710 @@
++/*
++    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
++
++    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
++    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
++    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 <linux/slab.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/firmware.h>
++
++#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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.h v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.h
+--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.h 1970-01-01 01:00:00.000000000 +0100
++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.h     2012-11-24 13:34:43.716679774 +0100
+@@ -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 <linux/dvb/frontend.h>
++
++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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103_priv.h v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103_priv.h
+--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103_priv.h    1970-01-01 01:00:00.000000000 +0100
++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103_priv.h        2012-11-24 13:34:43.716679774 +0100
+@@ -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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Makefile v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Makefile
+--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Makefile    2012-08-17 05:45:27.000000000 +0200
++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Makefile        2012-11-24 13:34:43.716679774 +0100
+@@ -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
++
++
+diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/Makefile v4l-dvb-20120916/linux/drivers/media/rc/keymaps/Makefile
+--- v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/Makefile       2012-05-21 05:45:41.000000000 +0200
++++ v4l-dvb-20120916/linux/drivers/media/rc/keymaps/Makefile   2012-11-24 13:34:43.716679774 +0100
+@@ -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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/rc-dvbsky.c v4l-dvb-20120916/linux/drivers/media/rc/keymaps/rc-dvbsky.c
+--- v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/rc-dvbsky.c    1970-01-01 01:00:00.000000000 +0100
++++ v4l-dvb-20120916/linux/drivers/media/rc/keymaps/rc-dvbsky.c        2012-11-24 13:34:43.716679774 +0100
+@@ -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 <mchehab@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <media/rc-map.h>
++#include <linux/module.h>
++/*
++ * 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 <mchehab@redhat.com>");
+diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/dw2102.c v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/dw2102.c
+--- v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/dw2102.c      2012-08-14 05:45:22.000000000 +0200
++++ v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/dw2102.c  2012-11-24 15:44:13.269971182 +0100
+@@ -3,6 +3,7 @@
+  *    TeVii S600, S630, S650, S660, S480,
+  *    Prof 1100, 7500,
+  *    Geniatech SU3000 Cards
++ *    Bestunar US683x HD, DVBsky S860, S960 USB
+  * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by)
+  *
+  *    This program is free software; you can redistribute it and/or modify it
+@@ -19,6 +20,7 @@
+ #include "stb6000.h"
+ #include "eds1547.h"
+ #include "cx24116.h"
++#include "m88ds3103.h"
+ #include "tda1002x.h"
+ #include "mt312.h"
+ #include "zl10039.h"
+@@ -786,7 +788,7 @@
+       struct su3000_state *state = (struct su3000_state *)d->priv;
+       u8 obuf[] = {0xde, 0};
+-      info("%s: %d, initialized %d\n", __func__, i, state->initialized);
++      info("%s: %d, initialized %d", __func__, i, state->initialized);
+       if (i && !state->initialized) {
+               state->initialized = 1;
+@@ -824,7 +826,40 @@
+               else
+                       mac[i] = ibuf[0];
+-              debug_dump(mac, 6, printk);
++              debug_dump(mac, 6, deb_xfer);
++      }
++
++      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, deb_xfer);
+       }
+       return 0;
+@@ -835,7 +870,7 @@
+                                struct dvb_usb_device_description **desc,
+                                int *cold)
+ {
+-      info("%s\n", __func__);
++      info("%s", __func__);
+       *cold = 0;
+       return 0;
+@@ -878,6 +913,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!", __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, 0, 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 +1055,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;
+@@ -1000,7 +1090,7 @@
+                               tuner_ops->set_bandwidth = stb6100_set_bandw;
+                               tuner_ops->get_bandwidth = stb6100_get_bandw;
+                               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-                              info("Attached STV0900+STB6100!\n");
++                              info("Attached STV0900+STB6100!");
+                               return 0;
+                       }
+               }
+@@ -1014,7 +1104,7 @@
+                                       &dw2104_stv6110_config,
+                                       &d->dev->i2c_adap)) {
+                               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-                              info("Attached STV0900+STV6110A!\n");
++                              info("Attached STV0900+STV6110A!");
+                               return 0;
+                       }
+               }
+@@ -1025,7 +1115,7 @@
+                               &d->dev->i2c_adap);
+               if (d->fe_adap[0].fe != NULL) {
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-                      info("Attached cx24116!\n");
++                      info("Attached cx24116!");
+                       return 0;
+               }
+       }
+@@ -1034,7 +1124,7 @@
+                       &d->dev->i2c_adap);
+       if (d->fe_adap[0].fe != NULL) {
+               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-              info("Attached DS3000!\n");
++              info("Attached DS3000!");
+               return 0;
+       }
+@@ -1053,7 +1143,7 @@
+                                       &d->dev->i2c_adap);
+               if (d->fe_adap[0].fe != NULL) {
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-                      info("Attached si21xx!\n");
++                      info("Attached si21xx!");
+                       return 0;
+               }
+       }
+@@ -1065,7 +1155,7 @@
+                       if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
+                                       &d->dev->i2c_adap)) {
+                               d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-                              info("Attached stv0288!\n");
++                              info("Attached stv0288!");
+                               return 0;
+                       }
+               }
+@@ -1077,7 +1167,7 @@
+                                       &d->dev->i2c_adap);
+               if (d->fe_adap[0].fe != NULL) {
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-                      info("Attached stv0299!\n");
++                      info("Attached stv0299!");
+                       return 0;
+               }
+       }
+@@ -1089,7 +1179,7 @@
+       d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
+                               &d->dev->i2c_adap, 0x48);
+       if (d->fe_adap[0].fe != NULL) {
+-              info("Attached tda10023!\n");
++              info("Attached tda10023!");
+               return 0;
+       }
+       return -EIO;
+@@ -1103,7 +1193,7 @@
+               if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60,
+                               &d->dev->i2c_adap)) {
+                       d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+-                      info("Attached zl100313+zl10039!\n");
++                      info("Attached zl100313+zl10039!");
+                       return 0;
+               }
+       }
+@@ -1128,7 +1218,7 @@
+       dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+-      info("Attached stv0288+stb6000!\n");
++      info("Attached stv0288+stb6000!");
+       return 0;
+@@ -1150,7 +1240,7 @@
+       dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+-      info("Attached ds3000+ds2020!\n");
++      info("Attached ds3000+ds2020!");
+       return 0;
+ }
+@@ -1168,7 +1258,7 @@
+       dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+-      info("Attached STV0900+STB6100A!\n");
++      info("Attached STV0900+STB6100A!");
+       return 0;
+ }
+@@ -1205,7 +1295,88 @@
+       if (d->fe_adap[0].fe == NULL)
+               return -EIO;
+-      info("Attached DS3000!\n");
++      info("Attached DS3000!");
++
++      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!");
++
++      return 0;
++}
++
++static int US6832_frontend_attach(struct dvb_usb_adapter *d)
++{
++      u8 obuf[3] = { 0xe, 0x04, 1 };
++      u8 ibuf[] = { 0 };
++
++      info("US6832: %s!", __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!");
+       return 0;
+ }
+@@ -1447,6 +1618,9 @@
+       TEVII_S480_1,
+       TEVII_S480_2,
+       X3M_SPC1400HD,
++      BST_US6830HD,
++      BST_US6831HD,
++      BST_US6832HD,
+ };
+ static struct usb_device_id dw2102_table[] = {
+@@ -1465,6 +1639,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 +2047,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 +2203,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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/Kconfig v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/Kconfig
+--- v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/Kconfig       2012-08-22 05:45:23.000000000 +0200
++++ v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/Kconfig   2012-11-24 13:34:43.716679774 +0100
+@@ -1,3 +1,4 @@
+++     select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
+ config DVB_USB
+       tristate "Support for various USB DVB devices"
+       depends on DVB_CORE && USB && I2C && RC_CORE
+@@ -261,6 +262,7 @@
+       select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
++      select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+diff -Naur v4l-dvb-20120916.ORG/linux/include/media/rc-map.h v4l-dvb-20120916/linux/include/media/rc-map.h
+--- v4l-dvb-20120916.ORG/linux/include/media/rc-map.h  2012-05-21 05:45:41.000000000 +0200
++++ v4l-dvb-20120916/linux/include/media/rc-map.h      2012-11-24 13:34:43.716679774 +0100
+@@ -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"