Add support for TechniSat SkyStar S2 / CX24120-13Z frontend

Message ID 4F7BF437.4090206@kripserver.net (mailing list archive)
State Changes Requested, archived
Headers

Commit Message

Jannis April 4, 2012, 7:11 a.m. UTC
  Hi all,

some (longer) time ago, I posted to this list concerning the
CX24120-frontend
(http://www.spinics.net/lists/linux-media/msg33717.html). By now I
modified the patch to work with linux-3.4-r1 (after the DVB-interface
changes):

[    2.434181] b2c2-flexcop: B2C2 FlexcopII/II(b)/III digital TV
receiver chip loaded successfully
[    2.434240] flexcop-pci: will use the HW PID filter.
[    2.434242] flexcop-pci: card revision 2
[    2.438105] DVB: registering new adapter (FlexCop Digital TV device)
[    2.440018] b2c2-flexcop: MAC address = 00:08:c9:e0:87:57
[    2.440024] CX24120: cx24120_attach: -> Conexant cx24120/cx24118 -
DVBS/S2 Satellite demod/tuner
[    2.440025] CX24120: cx24120_attach: -> Driver version: 'SVT - 0.0.4a
       03.04.2012'
[    2.440149] CX24120: cx24120_attach: -> Demod CX24120 rev. 0x07 detected.
[    2.440150] CX24120: cx24120_attach: -> Conexant cx24120/cx24118 -
DVBS/S2 Satellite demod/tuner ATTACHED.
[    2.440440] b2c2-flexcop: ISL6421 successfully attached.
[    2.440440] b2c2-flexcop: found 'Conexant CX24120/CX24118' .
[    2.440442] DVB: registering adapter 0 frontend 0 (Conexant
CX24120/CX24118)...
[    2.440648] b2c2-flexcop: initialization of 'Sky2PC/SkyStar S2
DVB-S/S2 rev 3.3' at the 'PCI' bus controlled by a 'FlexCopIIb' complete

As stated in the original message, the patch is not written by me, the
author is Sergey Tyurin, I just modified it so it keeps working with
current kernels. Since I don't know an appropiate location for
publishing this, I thought this is best sent upstream.

This patch was tested with some channels (SDTV, HDTV and audio only
(radio)) from Astra-19.2E in Europe.

If you have any comments abouth things that stop the patch from going
upstream, please feel free to tell me and I'll see if I can change them.

Best regards,
	Jannis Achstetter
  

Comments

Mauro Carvalho Chehab April 11, 2012, 11:45 a.m. UTC | #1
Hi Jannis,

Em 04-04-2012 04:11, Jannis escreveu:
> Hi all,
> 
> some (longer) time ago, I posted to this list concerning the
> CX24120-frontend
> (http://www.spinics.net/lists/linux-media/msg33717.html). By now I
> modified the patch to work with linux-3.4-r1 (after the DVB-interface
> changes):
> 
> [    2.434181] b2c2-flexcop: B2C2 FlexcopII/II(b)/III digital TV
> receiver chip loaded successfully
> [    2.434240] flexcop-pci: will use the HW PID filter.
> [    2.434242] flexcop-pci: card revision 2
> [    2.438105] DVB: registering new adapter (FlexCop Digital TV device)
> [    2.440018] b2c2-flexcop: MAC address = 00:08:c9:e0:87:57
> [    2.440024] CX24120: cx24120_attach: -> Conexant cx24120/cx24118 -
> DVBS/S2 Satellite demod/tuner
> [    2.440025] CX24120: cx24120_attach: -> Driver version: 'SVT - 0.0.4a
>        03.04.2012'
> [    2.440149] CX24120: cx24120_attach: -> Demod CX24120 rev. 0x07 detected.
> [    2.440150] CX24120: cx24120_attach: -> Conexant cx24120/cx24118 -
> DVBS/S2 Satellite demod/tuner ATTACHED.
> [    2.440440] b2c2-flexcop: ISL6421 successfully attached.
> [    2.440440] b2c2-flexcop: found 'Conexant CX24120/CX24118' .
> [    2.440442] DVB: registering adapter 0 frontend 0 (Conexant
> CX24120/CX24118)...
> [    2.440648] b2c2-flexcop: initialization of 'Sky2PC/SkyStar S2
> DVB-S/S2 rev 3.3' at the 'PCI' bus controlled by a 'FlexCopIIb' complete
> 
> As stated in the original message, the patch is not written by me, the
> author is Sergey Tyurin, I just modified it so it keeps working with
> current kernels. Since I don't know an appropiate location for
> publishing this, I thought this is best sent upstream.

If the patch was made by Sergey, you should add, at the beginning of the
body of the email, a like like:

From: Sergey Tyurin <his@email>


and add your comments like:

[jannis-lists@kripserver.net: patch ported to the current DVB kernel ABI]

You should also add your Signed-off-by:. It is also highly recommended
that you would get Sergey's Signed-off-by on it.

Please see LinuxTV developer wiki pages, in order to check the proper ways
to submit the patch upstream.

In particular, please check the patch using scripts/checkpatch.pl. This
tool checks the patch CodingStyle. It also checks a few trivial mistakes.

It currently doesn't like this code very much:

ERROR: Missing Signed-off-by: line(s)

total: 515 errors, 394 warnings, 1522 lines checked

NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or
      scripts/cleanfile

As you're not the author of the original driver, the better procedure is
to submit Sergey's driver as-is (but without the Kconfig/Makefile changes,
in order to avoid it to break compilation), then a patch fixing it to the
current ABI from you, and patch/patch series from you fixing the CodingStyle 
issues.

Btw, scripts/Lindent in general solves most of those issues (although it
is not a perfect tool).

> This patch was tested with some channels (SDTV, HDTV and audio only
> (radio)) from Astra-19.2E in Europe.
> 
> If you have any comments abouth things that stop the patch from going
> upstream, please feel free to tell me and I'll see if I can change them.

I just did a quick look on it, as it is harder to analyze a code with a
different CodingStyle.

There are too many EXPORT_SYMBOL() there, several of them for static functions.
That's wrong. Only non-static functions used by other modules should use
EXPORT_SYMBOL. Probably, the only function that requires it is cx24120_attach().

Anyway, I'll do a deeper review after you fix the pointed issues.
> 
> Best regards,
> 	Jannis Achstetter

Regards,
Mauro
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
  

Patch

diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-common.h linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-common.h
--- linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-common.h	2012-04-03 15:23:44.824143495 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-common.h	2012-04-03 15:26:40.756140116 +0400
@@ -91,6 +91,8 @@ 
 	int feedcount;
 	int pid_filtering;
 	int fullts_streaming_state;
+	/* the stream will be activated by an externally (by the fe for example) */
+	int need_external_stream_control;
 
 	/* bus specific callbacks */
 	flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
@@ -177,6 +179,8 @@ 
 		struct dvb_demux_feed *dvbdmxfeed, int onoff);
 void flexcop_hw_filter_init(struct flexcop_device *fc);
 
+extern void flexcop_external_stream_control(struct dvb_frontend *fe, u8 onoff);
+
 void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
 
 void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-fe-tuner.c linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
--- linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-fe-tuner.c	2012-04-03 15:23:44.828143388 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-fe-tuner.c	2012-04-03 15:26:40.760141513 +0400
@@ -12,6 +12,7 @@ 
 #include "cx24113.h"
 #include "cx24123.h"
 #include "isl6421.h"
+#include "cx24120.h"
 #include "mt352.h"
 #include "bcm3510.h"
 #include "nxt200x.h"
@@ -26,6 +27,15 @@ 
 #define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
 	(defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
 
+#if FE_SUPPORTED(BCM3510) || FE_SUPPORTED(CX24120)
+static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
+	const struct firmware **fw, char* name)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	return request_firmware(fw, name, fc->dev);
+}
+#endif
+
 /* lnb control */
 #if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
 static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -445,13 +455,6 @@ 
 
 /* AirStar ATSC 1st generation */
 #if FE_SUPPORTED(BCM3510)
-static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
-	const struct firmware **fw, char* name)
-{
-	struct flexcop_device *fc = fe->dvb->priv;
-	return request_firmware(fw, name, fc->dev);
-}
-
 static struct bcm3510_config air2pc_atsc_first_gen_config = {
 	.demod_address    = 0x0f,
 	.request_firmware = flexcop_fe_request_firmware,
@@ -619,10 +622,40 @@ 
 #define cablestar2_attach NULL
 #endif
 
+/* SkyStar S2 PCI DVB-S/S2 card based on Conexant cx24120/cx24118 */
+#if FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421)
+static const struct cx24120_config skystar2_rev3_3_cx24120_config = {
+	.i2c_addr = 0x55,
+	.request_firmware = flexcop_fe_request_firmware,
+};
+
+static int skystarS2_rev33_attach(struct flexcop_device *fc, struct i2c_adapter *i2c)
+{
+//	struct dvb_frontend_ops *ops;
+	
+	fc->fe = dvb_attach(cx24120_attach,
+		&skystar2_rev3_3_cx24120_config, i2c);
+	if (fc->fe == NULL) return 0;
+	fc->dev_type = FC_SKYS2_REV33;
+	fc->fc_i2c_adap[2].no_base_addr = 1;
+	if ( (dvb_attach(isl6421_attach, fc->fe,
+		&fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL) ) {
+		err("ISL6421 could NOT be attached!");
+		return 0;
+	}
+	info("ISL6421 successfully attached.");
+//	ops = &fc->fe->ops;
+	return 1;
+}
+#else
+#define skystarS2_rev33_attach NULL
+#endif
+
 static struct {
 	flexcop_device_type_t type;
 	int (*attach)(struct flexcop_device *, struct i2c_adapter *);
 } flexcop_frontends[] = {
+	{ FC_SKYS2_REV33, skystarS2_rev33_attach },
 	{ FC_SKY_REV27, skystar2_rev27_attach },
 	{ FC_SKY_REV28, skystar2_rev28_attach },
 	{ FC_SKY_REV26, skystar2_rev26_attach },
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-hw-filter.c linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-hw-filter.c
--- linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-hw-filter.c	2012-04-03 15:23:44.828143388 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-hw-filter.c	2012-04-03 15:26:40.760141513 +0400
@@ -11,6 +11,12 @@ 
 	deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
 }
 
+void flexcop_external_stream_control(struct dvb_frontend *fe, u8 onoff)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	flexcop_rcv_data_ctrl(fc, onoff);
+}
+
 void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
 {
 	flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
@@ -199,6 +205,7 @@ 
 
 	/* if it was the first or last feed request change the stream-status */
 	if (fc->feedcount == onoff) {
+		if (!fc->need_external_stream_control)
 		flexcop_rcv_data_ctrl(fc, onoff);
 		if (fc->stream_control) /* device specific stream control */
 			fc->stream_control(fc, onoff);
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-misc.c linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-misc.c
--- linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-misc.c	2012-04-03 15:23:44.832143280 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-misc.c	2012-04-03 15:26:40.760141513 +0400
@@ -56,6 +56,7 @@ 
 	[FC_SKY_REV26]	= "Sky2PC/SkyStar 2 DVB-S rev 2.6",
 	[FC_SKY_REV27]	= "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
 	[FC_SKY_REV28]	= "Sky2PC/SkyStar 2 DVB-S rev 2.8",
+	[FC_SKYS2_REV33]= "Sky2PC/SkyStar S2 DVB-S/S2 rev 3.3",
 };
 
 static const char *flexcop_bus_names[] = {
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-reg.h linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-reg.h
--- linux-3.4-r1/drivers/media/dvb/b2c2/flexcop-reg.h	2012-04-03 15:23:44.832143280 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/b2c2/flexcop-reg.h	2012-04-03 15:26:40.760141513 +0400
@@ -24,6 +24,7 @@ 
 	FC_SKY_REV26,
 	FC_SKY_REV27,
 	FC_SKY_REV28,
+	FC_SKYS2_REV33,
 } flexcop_device_type_t;
 
 typedef enum {
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/b2c2/Kconfig linux-3.4-r1-S2/drivers/media/dvb/b2c2/Kconfig
--- linux-3.4-r1/drivers/media/dvb/b2c2/Kconfig	2012-04-03 15:23:44.824143495 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/b2c2/Kconfig	2012-04-03 15:26:40.760141513 +0400
@@ -1,6 +1,7 @@ 
 config DVB_B2C2_FLEXCOP
 	tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
 	depends on DVB_CORE && I2C
+	select DVB_CX24120 if !DVB_FE_CUSTOMISE
 	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/frontends/cx24120.c linux-3.4-r1-S2/drivers/media/dvb/frontends/cx24120.c
--- linux-3.4-r1/drivers/media/dvb/frontends/cx24120.c	1970-01-01 03:00:00.000000000 +0300
+++ linux-3.4-r1-S2/drivers/media/dvb/frontends/cx24120.c	2012-04-03 16:10:59.000000000 +0400
@@ -0,0 +1,1053 @@ 
+/*	
+    Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner driver
+	Version 0.0.4a	03.04.2012
+	
+	Copyright (C) 2009 Sergey Tyurin <forum.free-x.de>
+	Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#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 "cx24120.h"
+#include "cx24120_const.h"
+
+//==========================
+#define dbginfo(args...) do { if(cx24120_debug) { printk(KERN_DEBUG "CX24120: %s: >>> ", __func__); \
+			printk(args); }  } while (0)
+#define info(args...) do { printk(KERN_INFO "CX24120: %s: -> ", __func__); \
+			printk(args); } while (0)
+#define err(args...) do {  printk(KERN_ERR "CX24120: %s: ### ERROR: ", __func__); \
+			printk(args); } while (0)
+//==========================
+
+static int cx24120_debug=0;
+static int reg_debug=0;
+MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24120/CX24118 hardware");
+module_param(cx24120_debug, int, 0644);
+MODULE_PARM_DESC(cx24120_debug, "Activates frontend debugging (default:0)");
+
+// ##############################
+struct cx24120_state {
+	struct i2c_adapter *i2c;
+	const struct cx24120_config *config;
+	struct dvb_frontend frontend;
+	u8 need_set_mpeg_out;
+	u8 attached;
+	u8 dvb_s2_mode;
+	u8 cold_init;	
+}; 
+// #####################################
+// #### Command message to firmware ####
+struct cx24120_cmd {			// total size = 36
+	u8 id;						// [00] - message id
+	u8 arg[30];					// [04] - message first byte
+	u8 len;						// [34] - message lengh or first registers to read
+	u8 reg;						// [35] - number of registers to read
+};
+
+//===================================================================
+static int cx24120_readreg(struct cx24120_state *state, u8 reg) 
+{
+	int ret;
+	u8 buf = 0;
+	struct i2c_msg msg[] = {
+		{ 	.addr = state->config->i2c_addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg	},
+			
+		{ 	.addr = state->config->i2c_addr,
+			.flags = I2C_M_RD,
+			.len = 1,
+			.buf = &buf	}
+	};
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2) {
+		err("Read error: reg=0x%02x,  ret=0x%02x)\n", reg, ret);
+		return ret;
+	}
+	if (reg_debug) dbginfo("reg=0x%02x; data=0x%02x\n", reg, buf);
+	return buf;
+} // end cx24120_readreg
+//===================================================================
+static int cx24120_writereg(struct cx24120_state *state, u8 reg, u8 data) 
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = state->config->i2c_addr, 
+		.flags = 0, 
+		.buf = buf, 
+		.len = 2 };
+	int ret;
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1) {
+		err("Write error: i2c_write error(err == %i, 0x%02x: 0x%02x)\n", ret, reg, data);
+		return ret;
+	}
+	if (reg_debug) dbginfo("reg=0x%02x; data=0x%02x\n", reg, data);
+	return 0;
+} // end cx24120_writereg
+//===================================================================
+static int cx24120_writeregN(struct cx24120_state *state, u8 reg, const u8 *values, u16 len, u8 incr)
+{
+	u8 buf[5]; /* maximum 4 data bytes at once - flexcop limitation (very limited i2c-interface this one) */
+	struct i2c_msg msg = {
+		.addr = state->config->i2c_addr, 
+		.flags = 0, 
+		.buf = buf, 
+		.len = len };
+	int ret;
+
+	do {
+		buf[0] = reg;
+		msg.len = len > 4 ? 4 : len;
+		memcpy(&buf[1], values, msg.len);
+		len  -= msg.len;					// data length revers counter
+		values += msg.len;					// incr data pointer
+		if (incr) reg += msg.len; 			
+		msg.len++; 							/* don't forget the addr byte */
+		ret = i2c_transfer(state->i2c, &msg, 1);
+		if (ret != 1) {
+			err("i2c_write error(err == %i, 0x%02x)\n", ret, reg);
+			return ret;
+		}
+		if (reg_debug) {
+			if( !(reg == 0xFA) && !(reg == 0x20) && !(reg == 0x21)) {		// Exclude firmware upload & diseqc messages
+				dbginfo("reg=0x%02x; data=0x%02x,0x%02x,0x%02x,0x%02x\n",	// from debug
+						reg, 	buf[1], buf[2], buf[3], buf[4]);
+			}
+		}
+	} while (len);
+	return 0;
+} // end cx24120_writeregN
+//===================================================================
+static struct dvb_frontend_ops cx24120_ops;
+//===================================================================
+struct dvb_frontend *cx24120_attach(const struct cx24120_config *config, struct i2c_adapter *i2c)
+{
+	struct cx24120_state *state = NULL;
+	int demod_rev;
+
+	info("Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner\n");
+	info("Driver version: 'SVT - 0.0.4a	03.04.2012'\n");
+	state = kzalloc(sizeof(struct cx24120_state),
+						GFP_KERNEL);
+	if (state == NULL) {
+		err("### Unable to allocate memory for cx24120_state structure. :(\n");
+		goto error;
+	}
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	/* check if the demod is present and has proper type */
+	demod_rev = cx24120_readreg(state, CX24120_REG_REVISION);
+	switch (demod_rev) {
+	case 0x07:
+		info("Demod CX24120 rev. 0x07 detected.\n");
+		break;
+	case 0x05:
+		info("Demod CX24120 rev. 0x05 detected.\n");
+		break;
+	default:
+		err("### Unsupported demod revision: 0x%x detected. Exit.\n", demod_rev);
+		goto error;
+	}
+	/* create dvb_frontend */
+	state->attached = 0x10;			// set attached flag
+	state->cold_init=0;
+	memcpy(&state->frontend.ops, &cx24120_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	info("Conexant cx24120/cx24118 - DVBS/S2 Satellite demod/tuner ATTACHED.\n");
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+} 
+EXPORT_SYMBOL(cx24120_attach); // end cx24120_attach
+//===================================================================
+static int cx24120_test_rom(struct cx24120_state *state)
+{
+	int err, ret;
+	err = cx24120_readreg(state, 0xFD);
+	if (err & 4 )
+		{
+			ret = cx24120_readreg(state, 0xDF) & 0xFE;
+			err = cx24120_writereg(state, 0xDF, ret);
+		}
+	return err;
+} // end  cx24120_test_rom
+//===================================================================
+static int cx24120_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	
+	*snr = (cx24120_readreg(state, CX24120_REG_QUALITY_H)<<8) |
+				 (cx24120_readreg(state, CX24120_REG_QUALITY_L));
+	dbginfo("read SNR index = %d\n", *snr);
+	
+	return 0;
+}
+EXPORT_SYMBOL(cx24120_read_snr); // end cx24120_read_snr
+//===================================================================
+static int cx24120_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+
+	*ber =  (cx24120_readreg(state, CX24120_REG_BER_HH) << 24)	|	// BER high byte of high word
+		(cx24120_readreg(state, CX24120_REG_BER_HL) << 16)		|	// BER low byte of high word
+		(cx24120_readreg(state, CX24120_REG_BER_LH)  << 8)		|	// BER high byte of low word
+		 cx24120_readreg(state, CX24120_REG_BER_LL);				// BER low byte of low word
+		dbginfo("read BER index = %d\n", *ber);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx24120_read_ber); // end cx24120_read_ber
+//===================================================================
+static int cx24120_message_send(struct cx24120_state *state, struct cx24120_cmd *cmd);
+//===================================================================
+static int cx24120_msg_mpeg_output_global_config(struct cx24120_state *state, u8 flag)
+{
+	u8 tristate;
+	struct cx24120_cmd cmd;
+
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	
+	cmd.id = 0x13;						// (19) message Enable/Disable mpeg output ???
+	cmd.arg[0] = 1;
+	cmd.arg[1] = 0;
+	tristate = flag ? 0 : (u8)(-1);
+	cmd.arg[2] = tristate;
+	cmd.arg[3] = 1;						
+	cmd.len = 4;
+
+	if(flag) dbginfo("MPEG output DISABLED\n");
+	else dbginfo("MPEG output ENABLED\n");
+  
+	return cx24120_message_send(state, &cmd);
+}		// end	cx24120_msg_mpeg_output_global_config
+//===================================================================
+static int cx24120_message_send(struct cx24120_state *state, struct cx24120_cmd *cmd)
+{
+	u8 xxzz;
+	u32 msg_cmd_mask;
+	int ret, ficus;
+
+	if(state->dvb_s2_mode & 0x02) {		// is MPEG enabled?
+										// if yes:
+		xxzz = cmd->id - 0x11;			// look for specific message id
+		if ( xxzz <= 0x13 ) {
+			msg_cmd_mask = 1 << xxzz;
+			//0x0F8021 // if cmd_id 17 or 22 or 33-36, 42, 47, 57-61 etc. disable mpeg output
+			if ( msg_cmd_mask & 0x0F8021 ) {		// 000011111000000000100001b
+				cx24120_msg_mpeg_output_global_config(state, 0);
+				msleep(100);
+				state->dvb_s2_mode &=  0xFD;		// reset mpeg out enable flag
+			}
+		}
+	}
+	ret = cx24120_writereg(state, 0x00 /* reg id*/, cmd->id /* value */);			// message start & target
+	ret = cx24120_writeregN(state, 0x01 /* reg msg*/, &cmd->arg[0], cmd->len /* len*/, 1 /* incr */);		// message data
+	ret = cx24120_writereg(state, 0x1F /* reg msg_end */, 0x01 /* value */);		// message end
+
+	ficus = 1000;
+	while ( cx24120_readreg(state, 0x1F)) { 	// is command done???
+		msleep(1);
+		if( !(--ficus)) {
+			err("Too long waiting 'done' state from reg(0x1F). :(\n");
+			return -EREMOTEIO;
+		}
+	}
+	dbginfo("Successfully send message 0x%02x\n", cmd->id);
+
+	if ( cmd->reg > 30 ) {
+		err("Too much registers to read. cmd->reg = %d", cmd->reg);
+		return -EREMOTEIO;
+	}
+	ficus = 0;
+	if ( cmd->reg ) {					// cmd->reg - qty consecutive regs to read 
+		while ( ficus < cmd->reg ){		// starts from reg No cmd->len
+										// number of registers to read is cmd->reg
+										// and write results starts from cmd->arg[0].
+			cmd->arg[ficus] = cx24120_readreg(state, (cmd->len+ficus+1)); 		
+			++ficus;
+		}
+	}		
+	return 0;
+} // end cx24120_message_send
+//===================================================================
+static int cx24120_set_frontend(struct dvb_frontend *fe)
+{
+        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+	u32 srate, freq;
+	fe_code_rate_t fec;
+	fe_spectral_inversion_t inversion;
+	u8 smbr1, smbr2;
+	int ret;
+	
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	
+	cmd.id = CMD_TUNEREQUEST;		// 0x11 set tuner parametrs
+	cmd.len = 15;		
+	
+	freq = p->frequency;
+	srate = p->symbol_rate;
+	fec = p->fec_inner;
+	inversion = p->inversion;
+	
+	// check symbol rate
+	if ( srate  > 31000000 ) {      	// if symbol rate > 31 000
+		smbr1 = (-(srate < 31000001) & 3) + 2;		// ebp
+		smbr2 = (-(srate < 31000001) & 6) + 4;		// edi
+	} else {
+		smbr1 = 3;
+		smbr2 = 6;
+	}
+
+	ret = cx24120_writereg(state, 0xE6, smbr1);
+	ret = cx24120_readreg(state, 0xF0);
+	ret &= 0xFFFFFFF0;
+	ret |= smbr2;
+	ret = cx24120_writereg(state, 0xF0, ret);
+	
+	cmd.arg[0] = 0;		// CMD_TUNER_REQUEST
+	
+	// Frequency
+	cmd.arg[1] = (freq & 0xFF0000) >> 16;		/* intermediate frequency in kHz */
+	cmd.arg[2] = (freq & 0x00FF00) >> 8;
+	cmd.arg[3] = (freq & 0x0000FF);
+	
+	// Symbol Rate
+	cmd.arg[4] = ((srate/1000) & 0xFF00) >> 8;
+	cmd.arg[5] = ((srate/1000) & 0x00FF);
+	
+	// Inversion
+	if ( inversion ) {
+    	if ( inversion == 1 ) cmd.arg[6] = 4;
+		else cmd.arg[6] = 0x0C;
+	} else {
+		cmd.arg[6] = 0;
+	}
+
+	// FEC
+	switch ( fec )			// fec = p->u.qpsk.fec_inner
+	{
+		case 1:							// FEC_1_2
+			cmd.arg[7] = 0x2E; break;	// [11] = 0 by memset	
+		case 2:							// FEC_2_3
+			cmd.arg[7] = 0x2F; break;
+		case 3:							// FEC_3_4
+			cmd.arg[7] = 0x30; break;
+		case 5:							// FEC_5_6
+			cmd.arg[7] = 0x31; break;
+		case 7:							// FEC_7_8
+			cmd.arg[7] = 0x32; break;
+		default:								// FEC_NONE, FEC_4_5, FEC_6_7, FEC_8_9, 
+    											// FEC_AUTO, FEC_3_5, FEC_9_10
+			if ( state->dvb_s2_mode & 1 ) {	// if DVB-S2 mode	
+				cmd.arg[7] = 0;				
+				cmd.arg[11] = 0;
+			} else {
+				cmd.arg[7] = 0x2E;
+				cmd.arg[11] = 0xAC;
+			} 
+			break;
+	}
+	cmd.arg[8] = 0x13;
+	cmd.arg[9] = 0x88;
+	cmd.arg[10] = 0;
+	cmd.arg[12] = smbr2;
+	cmd.arg[13] = smbr1;
+	cmd.arg[14] = 0;
+
+	state->need_set_mpeg_out |= 0x01;		// after tune we need restart mpeg out ?????
+
+	return cx24120_message_send(state, &cmd);
+	
+} 
+EXPORT_SYMBOL(cx24120_set_frontend);		// end cx24120_set_frontend
+//===================================================================
+void cx24120_message_fill(struct cx24120_cmd *cmd,
+		u8 msg_id, 
+		u8 *msg_addr,
+		u8 msg_len,
+		u8 num_regs)
+{
+	cmd->id = msg_id;
+	memcpy(&cmd->arg[0], msg_addr, msg_len);
+	cmd->len = msg_len;
+	cmd->reg = num_regs;
+} // end cx24120_message_fill
+//===================================================================
+static int cx24120_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+	int result, sigstr_h, sigstr_l;
+
+	cx24120_message_fill(&cmd, 0x1A/*msg_id*/, &cx24120_msg_read_sigstr[0], 1/*msg_len*/, 0/*num_regs*/);
+
+	if( !(cx24120_message_send(state, &cmd)) ) {
+		sigstr_h = (cx24120_readreg(state, CX24120_REG_SIGSTR_H) >> 6) << 8;
+		sigstr_l = cx24120_readreg(state, CX24120_REG_SIGSTR_L );
+		dbginfo("Signal strength from firmware= 0x%x\n", (sigstr_h | sigstr_l));
+		*signal_strength = ((sigstr_h | sigstr_l)  << 5) & 0x0000FFFF;
+		dbginfo("Signal strength= 0x%x\n", *signal_strength);
+		result = 0;
+	} else {
+		err("error reading signal strength\n");
+		result = -EREMOTEIO;
+	}
+	return result;
+}
+EXPORT_SYMBOL(cx24120_read_signal_strength);		// end cx24120_read_signal_strength
+//===================================================================
+static int cx24120_msg_mpeg_output_config(struct cx24120_state *state, u8 num, 
+			struct cx24120_skystar2_mpeg_config *config_msg)
+{
+	struct cx24120_cmd cmd;
+	
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+  
+	cmd.id = CMD_MPEG_INIT;          // cmd->id=20 - message id
+	cmd.len = 7;            
+	cmd.arg[0] = num;     // sequental number - can be 0,1,2
+	cmd.arg[1] =  	((config_msg->x1 & 0x01) << 1) |
+					((config_msg->x1 >> 1) & 0x01);
+	cmd.arg[2] = 0x05;
+	cmd.arg[3] = 0x02;
+	cmd.arg[4] = ((config_msg->x2 >> 1) & 0x01);
+	cmd.arg[5] = (config_msg->x2 & 0xF0) | (config_msg->x3 & 0x0F);
+	cmd.arg[6] = state->attached; 	/* 0x10 if succesfully attached */
+  
+  return cx24120_message_send(state, &cmd);
+}	// end cx24120_msg_mpeg_output_config
+//===================================================================
+static int cx24120_diseqc_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+	
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	
+	cmd.id = CMD_DISEQC_BURST;
+	cmd.arg[0] = 0x00;
+	if (burst)
+		cmd.arg[1] = 0x01;
+	dbginfo("burst sent.\n");
+
+  return cx24120_message_send(state, &cmd);
+}
+EXPORT_SYMBOL(cx24120_diseqc_send_burst);		// end cx24120_diseqc_send_burst
+//===================================================================
+static int cx24120_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+
+	dbginfo("cmd(0x23,4) - tone = %d\n", tone);
+	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+		err("Invalid tone=%d\n", tone);
+		return -EINVAL;
+	}
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	cmd.id = CMD_SETTONE;	// 0x23
+	cmd.len = 4;
+	if (!tone)
+		cmd.arg[3] = 0x01;
+  return cx24120_message_send(state, &cmd);
+}
+EXPORT_SYMBOL(cx24120_set_tone);		// end cx24120_set_tone
+//===================================================================
+static int cx24120_set_voltage(struct dvb_frontend *fe,	fe_sec_voltage_t voltage)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	cmd.id = CMD_SETVOLTAGE;		//
+	cmd.len = 2;
+	if (!(voltage - 1))
+		cmd.arg[1] = 0x01;
+	return cx24120_message_send(state, &cmd);
+}
+EXPORT_SYMBOL(cx24120_set_voltage);		// end cx24120_set_voltage
+//===================================================================
+static int cx24120_send_diseqc_msg(struct dvb_frontend *fe,	struct dvb_diseqc_master_cmd *d)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+	int back_count;
+	
+	dbginfo("Start sending diseqc sequence===============\n");
+	
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	
+	cmd.id = CMD_DISEQC_MSG1;		// 0x20
+	cmd.len = 11;
+	cmd.arg[0] = 0x00;
+	cmd.arg[1] = 0x00;
+	cmd.arg[2] = 0x03;
+	cmd.arg[3] = 0x16;
+	cmd.arg[4] = 0x28;
+	cmd.arg[5] = 0x01;
+	cmd.arg[6] = 0x01;
+	cmd.arg[7] = 0x14;
+	cmd.arg[8] = 0x19;
+	cmd.arg[9] = 0x14;
+	cmd.arg[10] = 0x1E;
+	if ( cx24120_message_send(state, &cmd) ) {
+		err("send 1st message(0x%x) filed==========\n", cmd.id);
+		return -EREMOTEIO;
+	}
+	cmd.id = CMD_DISEQC_MSG2;		// 0x21
+	cmd.len = d->msg_len + 6;
+	cmd.arg[0] = 0x00;
+	cmd.arg[1] = 0x01;
+	cmd.arg[2] = 0x02;
+	cmd.arg[3] = 0x00;
+	cmd.arg[4] = 0x00;
+	cmd.arg[5] = d->msg_len;
+	
+	memcpy(&cmd.arg[6], &d->msg, d->msg_len);
+	
+	if ( cx24120_message_send(state, &cmd) ) {
+		err("send 2d message(0x%x) filed========\n", cmd.id);
+		return -EREMOTEIO;
+	}
+	back_count = 100;
+	do {
+		if ( !(cx24120_readreg(state, 0x93) & 0x01) ) {	
+			dbginfo("diseqc sequence sent success==========.\n");
+			return 0;
+		}
+		msleep(5);
+		--back_count;
+	} while ( back_count );
+	err("Too long waiting for diseqc.=============\n");
+	return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(cx24120_send_diseqc_msg);		// end cx24120_send_diseqc_msg
+//===================================================================
+static int cx24120_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+	int ret, clock_seq_num, GettedFEC;
+	u8 mode_code, mode_8PSK_flag, attached_flag, clock_id;
+	
+	ret = cx24120_readreg(state, CX24120_REG_STATUS);		//0x3A
+	dbginfo("status = 0x%x\n", ret);
+	*status = 0;
+	if ( ret & CX24120_HAS_SIGNAL ) *status = FE_HAS_SIGNAL;
+	if ( ret & CX24120_HAS_CARRIER) *status |= FE_HAS_CARRIER;
+	if ( ret & CX24120_HAS_VITERBI) *status |= (FE_HAS_VITERBI + FE_HAS_SYNC);
+	
+	if ( ret & CX24120_HAS_LOCK ) {		// 0x08
+		*status |= FE_HAS_LOCK;
+		if ( state->need_set_mpeg_out & 1 ) {			// just tuned???
+			memset(&cmd, 0, sizeof(struct cx24120_cmd));
+			cmd.id = CMD_CLOCK_READ;
+			cmd.arg[0] = 0x00;
+			cmd.len = 1;			// cmd.reg != 0, so it is first register to read 
+			cmd.reg = 6;			// number of registers to read (0x01-0x06)
+			if ( !cx24120_message_send(state, &cmd) ) {			// in cmd[0]-[5] - result
+																//      0x02-0x07
+				ret = cx24120_readreg(state, CX24120_REG_FECMODE) & 0x3F;		// ntv - 0x8E(142) & 3F = 14
+				GettedFEC = ret;												// 		 0x0d= 13
+				dbginfo("Get FEC: %d\n", ret);
+				if ( state->dvb_s2_mode & 0x01 ) {							// is DVB-S2?
+					switch (ret-4) {
+						case 0:
+							mode_code = 0x01; goto mode_QPSK;	// FEC_1_2 - qpsk only
+						case 1:
+						case 8:
+							mode_code = 0x64; goto mode_8PSK;	// FEC_3_5 (10)- 8PSK only
+						case 2:
+						case 9:
+							mode_code = 0x02; goto mode_8PSK;	// FEC_2_3
+						case 3:
+						case 10:
+							mode_code = 0x03; goto mode_8PSK;	// FEC_3_4	// 14-4=10 - ntv+
+						case 4:
+							mode_code = 0x04; goto mode_QPSK;	// FEC_4_5 - qpsk only
+						case 5:
+						case 11:
+							mode_code = 0x05; goto mode_8PSK;	// FEC_5_6
+						case 6:
+						case 12:
+							mode_code = 0x08; goto mode_8PSK;	// FEC_8_9
+						case 7:
+						case 13:
+							mode_code = 0x65; goto mode_8PSK;	// FEC_9_10 (11)- 8PSK only
+						default:
+							info("Unknown DVB-S2 modefec (not QPSK or 8PSK): %d\n", ret-4);
+							mode_code = 0x01; 						// set like for mode 0
+					mode_8PSK:
+						if ( ret > 11 ) {		// 14
+							mode_8PSK_flag = 0x63;			// DVB-S2-8PSK flag
+							dbginfo("DVB-S2: 8PSK mode: %d, mode_code= 0x%x\n", ret-4, mode_code);
+						} else {
+					mode_QPSK:
+							mode_8PSK_flag = 0x00;
+   		     	      		dbginfo("DVB-S2: QPSK mode: %d\n", ret-4);
+						}
+						break;
+					} // end switch
+				} // end if dvb_s2_mode // dvb-s2
+				else {								// state->dvb_s2_mode & 1 = 0 -> #### DVB-S
+					switch ( ret - 2 ) {
+						case 0:
+							mode_code = 2; break;	// FEC_2_3
+						case 1:
+							mode_code = 3; break;	// FEC_3_4
+						case 2:
+							mode_code = 4; break;	// FEC_4_5
+						case 3:
+							mode_code = 5; break;	// FEC_5_6
+						case 4:
+							mode_code = 6; break;	// FEC_6_7
+						case 5:
+							mode_code = 7; break;	// FEC_7_8
+						default: 
+							mode_code = 1;break;	// FEC_1_2
+					}
+					mode_8PSK_flag = 0;
+				} // end of switch for dvb-s
+				
+				attached_flag = 0x10;
+				if (state->attached == 0x10)  // must be 0x10 if successfully attached in flexcop_fe_tuner
+					attached_flag = 0;
+				ret = 0;
+				if ( state->dvb_s2_mode & 0x01 )		// if dvb-s2
+					ret = (cx24120_readreg(state, CX24120_REG_FECMODE) >> 7) & 0x01;  // QPSK or 8PSK ???
+						 // bit 4          bit 5			bit 0                 bit 3
+				clock_id = (ret << 3) | attached_flag | (state->dvb_s2_mode & 1) | 4;		// possible id: 4, 5, 13. 12-impossible, 
+				// ntv S2 = 0x8E -> 8 | 1 | 4 = 13											// because 7th bit of ret - is S2 flag
+				// 1/2 S2 = 0x0d -> 0 | 1 | 4 = 5
+				dbginfo("Check clock table for: clock_id=0x%x, 8PSK_mask=0x%x, mode_code=0x%x\n", 
+				 	clock_id, mode_8PSK_flag, mode_code);
+				
+				clock_seq_num = 0;
+				while ( (clock_ratios_table[clock_seq_num].ratio_id != clock_id) ||
+						(clock_ratios_table[clock_seq_num].mode_xPSK != mode_8PSK_flag) ||
+						(clock_ratios_table[clock_seq_num].fec_mode != mode_code) )
+				{
+				/*	dbginfo("Check table string(%d): clock_id=%d, 8PSK_flag=%d, mode_code=%d\n",	clock_seq_num, 
+				 *		clock_ratios_table[clock_seq_num].ratio_id,
+				 *		clock_ratios_table[clock_seq_num].mode_xPSK,
+				 *		clock_ratios_table[clock_seq_num].fec_mode);
+				 */
+					++clock_seq_num;
+					if ( clock_seq_num == ARRAY_SIZE(clock_ratios_table) ) {
+						info("Check in clock table filed: unsupported modulation tuned - data reception in danger. :(\n");
+						goto settings_end;
+					}
+				}
+	//###############################
+				dbginfo("Check succesful: GetFEC: %d; post lock: m=%d, n=%d; clock_seq_idx: %d m=%d, n=%d, rate=%d\n",
+					GettedFEC,
+					cmd.arg[2] | (cmd.arg[1] << 8) | (cmd.arg[0] << 16), 		// registers was readed early
+					cmd.arg[5] | (cmd.arg[4] << 8) | (cmd.arg[3] << 16),		// in message with id = 0x16
+					clock_seq_num,
+					clock_ratios_table[clock_seq_num].m_rat,
+					clock_ratios_table[clock_seq_num].n_rat,
+					clock_ratios_table[clock_seq_num].rate);
+ 	//###############################
+				cmd.id = CMD_CLOCK_SET;
+				cmd.len = 10;
+				cmd.reg = 0;
+				cmd.arg[0] = 0;
+				cmd.arg[1] = state->attached;		// must be 0x10 if successfully attached in flexcop_fe_tuner
+				
+				cmd.arg[2] = (clock_ratios_table[clock_seq_num].m_rat >> 16) & 0xFF;
+				cmd.arg[3] = (clock_ratios_table[clock_seq_num].m_rat >>  8) & 0xFF;
+				cmd.arg[4] = (clock_ratios_table[clock_seq_num].m_rat >>  0) & 0xFF;
+
+				cmd.arg[5] = (clock_ratios_table[clock_seq_num].n_rat >> 16) & 0xFF;
+				cmd.arg[6] = (clock_ratios_table[clock_seq_num].n_rat >>  8) & 0xFF;
+				cmd.arg[7] = (clock_ratios_table[clock_seq_num].n_rat >>  0) & 0xFF;
+
+				cmd.arg[8] = (clock_ratios_table[clock_seq_num].rate >> 8) & 0xFF;
+				cmd.arg[9] = (clock_ratios_table[clock_seq_num].rate >> 0) & 0xFF;
+				
+				cx24120_message_send(state, &cmd);
+				
+			settings_end:
+				msleep(200);
+				cx24120_msg_mpeg_output_global_config(state, 1);	
+				state->dvb_s2_mode |= 0x02;							// set mpeg flag
+				state->need_set_mpeg_out &= 0xFE;					// clocks set done -> clear flag
+			}
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cx24120_read_status);		// end cx24120_read_status
+//===================================================================
+int cx24120_init(struct dvb_frontend *fe)
+{
+	const struct firmware *fw;
+	struct cx24120_state *state = fe->demodulator_priv;
+	struct cx24120_cmd cmd;
+	u8 ret, ret_EA, reg1, fL, fH;
+	u32 vco, xtal_khz;
+	u64 inv_vco, res, xxyyzz;
+	int reset_result;
+
+	if( state->cold_init ) return 0;
+
+	ret = cx24120_writereg(state, 0xEA, 0x00);
+	ret = cx24120_test_rom(state);
+	ret = cx24120_readreg(state, 0xFB) & 0xFE;
+	ret = cx24120_writereg(state, 0xFB, ret);
+	ret = cx24120_readreg(state, 0xFC) & 0xFE;
+	ret = cx24120_writereg(state, 0xFC, ret);
+	ret = cx24120_writereg(state, 0xC3, 0x04);
+	ret = cx24120_writereg(state, 0xC4, 0x04);
+	ret = cx24120_writereg(state, 0xCE, 0x00);
+	ret = cx24120_writereg(state, 0xCF, 0x00);
+	ret_EA = cx24120_readreg(state, 0xEA) & 0xFE;
+	ret = cx24120_writereg(state, 0xEA, ret_EA);
+	ret = cx24120_writereg(state, 0xEB, 0x0C);
+	ret = cx24120_writereg(state, 0xEC, 0x06);
+	ret = cx24120_writereg(state, 0xED, 0x05);
+	ret = cx24120_writereg(state, 0xEE, 0x03);
+	ret = cx24120_writereg(state, 0xEF, 0x05);
+	ret = cx24120_writereg(state, 0xF3, 0x03);
+	ret = cx24120_writereg(state, 0xF4, 0x44);
+	
+	reg1 = 0xF0;
+	do {
+		cx24120_writereg(state, reg1, 0x04);
+		cx24120_writereg(state, reg1 - 10, 0x02);
+		++reg1;
+	} while ( reg1 != 0xF3 );
+
+	ret = cx24120_writereg(state, 0xEA, (ret_EA | 0x01));
+		reg1 = 0xC5;
+	do {
+		ret = cx24120_writereg(state, reg1, 0x00);
+		ret = cx24120_writereg(state, reg1 + 1, 0x00);
+		reg1 += 2;
+    } while ( reg1 != 0xCB );
+    
+    ret = cx24120_writereg(state, 0xE4, 0x03);
+    ret = cx24120_writereg(state, 0xEB, 0x0A);
+    
+    dbginfo("Requesting firmware (%s) to download...\n", CX24120_FIRMWARE);
+    ret = state->config->request_firmware(fe, &fw, CX24120_FIRMWARE);
+	if (ret) {
+		err("Could not load firmware (%s): %d\n", CX24120_FIRMWARE, ret);
+		return ret;
+	}
+	dbginfo("Firmware found and it size is %d bytes (%02x %02x .. %02x %02x)\n",
+        (int)fw->size,				// firmware_size in bytes u32*
+        fw->data[0],			// fw 1st byte
+        fw->data[1],			// fw 2d byte
+        fw->data[fw->size - 2],	// fw before last byte
+        fw->data[fw->size - 1]);	// fw last byte
+        
+    ret = cx24120_test_rom(state);
+	ret = cx24120_readreg(state, 0xFB) & 0xFE;
+	ret = cx24120_writereg(state, 0xFB, ret);
+	ret = cx24120_writereg(state, 0xE0, 0x76);
+	ret = cx24120_writereg(state, 0xF7, 0x81);
+	ret = cx24120_writereg(state, 0xF8, 0x00);
+	ret = cx24120_writereg(state, 0xF9, 0x00);
+	ret = cx24120_writeregN(state, 0xFA, fw->data, (fw->size - 1), 0x00);
+	ret = cx24120_writereg(state, 0xF7, 0xC0);
+	ret = cx24120_writereg(state, 0xE0, 0x00);
+	ret = (fw->size - 2) & 0x00FF;
+	ret = cx24120_writereg(state, 0xF8, ret);	// ret now is 0x7a
+	ret = ((fw->size - 2) >> 8) & 0x00FF;
+	ret = cx24120_writereg(state, 0xF9, ret);	// ret now is 0xaf
+	ret = cx24120_writereg(state, 0xF7, 0x00);
+	ret = cx24120_writereg(state, 0xDC, 0x00);
+	ret = cx24120_writereg(state, 0xDC, 0x07);
+	msleep(500);
+	
+	ret = cx24120_readreg(state, 0xE1);		// now is 0xd5 - last byte of the firmware
+    if ( ret == fw->data[fw->size - 1] ) {
+		dbginfo("Firmware uploaded successfully\n");
+		reset_result = 0;
+	} else {
+		err("Firmware upload failed. Last byte returned=0x%x\n", ret );
+		reset_result = -EREMOTEIO;
+	}
+	ret = cx24120_writereg(state, 0xDC, 0x00);		
+	release_firmware(fw);
+	if (reset_result) 
+		return reset_result;
+		
+	//================== Start tuner
+	cx24120_message_fill(&cmd, CMD_START_TUNER, &cx24120_msg_tuner_init[0], 3, 0);	// 0x1B
+	if(cx24120_message_send(state, &cmd)) {
+		err("Error tuner start! :(\n");
+		return -EREMOTEIO;
+	}
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	
+	cmd.id = CMD_VCO_SET;		// 0x10
+	cmd.len = 12;
+	
+	// ######################
+	// Calc VCO
+	xtal_khz = 10111;
+	xxyyzz = 0x400000000ULL;	// 17179869184
+	vco = xtal_khz * 10 * 4;	// 404440
+	inv_vco = xxyyzz / vco;		// 42478 = 0x00A5EE
+	res = xxyyzz % vco;			// 66864 = 0x010530	
+	
+	if( inv_vco > xtal_khz * 10 * 2) ++inv_vco;
+		
+	fH = (inv_vco >> 8) & 0xFF;
+	fL = (inv_vco) & 0xFF;
+    dbginfo("vco= %d, inv_vco= %lld, res= %lld, fL= 0x%x, fH= 0x%x\n", vco, inv_vco, res, fL, fH);
+    // ######################
+    
+	cmd.arg[0] = 0x06;
+	cmd.arg[1] = 0x2B;
+	cmd.arg[2] = 0xD8;
+	cmd.arg[3] = fH;		// 0xA5
+	cmd.arg[4] = fL;		// 0xEE
+	cmd.arg[5] = 0x03;
+	cmd.arg[6] = 0x9D;
+	cmd.arg[7] = 0xFC;
+	cmd.arg[8] = 0x06;
+	cmd.arg[9] = 0x03;
+	cmd.arg[10] = 0x27;
+	cmd.arg[11] = 0x7F;
+	
+	if(cx24120_message_send(state, &cmd)) {
+		err("Error set VCO! :(\n");
+		return -EREMOTEIO;
+	}
+	memset(&cmd, 0, sizeof(struct cx24120_cmd));
+	// set bandwidth
+	cmd.id = CMD_BANDWIDTH;		// 0x15
+	cmd.len = 12;
+	cmd.arg[0] = 0x00;
+	cmd.arg[1] = 0x00;
+	cmd.arg[2] = 0x00;
+	cmd.arg[3] = 0x00;
+	cmd.arg[4] = 0x05;
+	cmd.arg[5] = 0x02;
+	cmd.arg[6] = 0x02;
+	cmd.arg[7] = 0x00;
+	cmd.arg[8] = 0x05;
+	cmd.arg[9] = 0x02;
+	cmd.arg[10] = 0x02;
+	cmd.arg[11] = 0x00;
+	
+	if ( cx24120_message_send(state, &cmd) ) {
+		err("Error set bandwidth! :(\n");
+		return -EREMOTEIO;
+	}
+	ret = cx24120_readreg(state, 0xBA);
+	if ( ret > 3) {
+		dbginfo("Reset-readreg 0xBA: %x\n", ret);
+		err("Error intitilizing tuner! :(\n");
+		return -EREMOTEIO;
+	}
+	dbginfo("Tuner initialized correctly.\n");
+
+	ret = cx24120_writereg(state, 0xEB, 0x0A);
+	if (cx24120_msg_mpeg_output_global_config(state, 0) ||
+		cx24120_msg_mpeg_output_config(state, 0, &initial_mpeg_config) ||
+		cx24120_msg_mpeg_output_config(state, 1, &initial_mpeg_config) ||
+		cx24120_msg_mpeg_output_config(state, 2, &initial_mpeg_config) )
+	{
+		err("Error initilizing mpeg output. :(\n");
+        return -EREMOTEIO;
+	} else {
+		cmd.id = 0x3C;	// 60
+		cmd.len = 0x03;
+		cmd.arg[0] = 0x00;
+		cmd.arg[1] = 0x10;
+		cmd.arg[2] = 0x10;
+		if(cx24120_message_send(state, &cmd)) {
+			err("Error sending final init message. :(\n");
+			return -EREMOTEIO;
+		}	
+    }
+	state->cold_init=1;
+	return 0;
+} 
+EXPORT_SYMBOL(cx24120_init);		// end cx24120_reset
+//===================================================================
+static int cx24120_tune(struct dvb_frontend *fe, bool re_tune,
+        unsigned int mode_flags, unsigned int *delay, fe_status_t *p_status)
+{
+        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct cx24120_state *state = fe->demodulator_priv;
+	int delay_cnt, sd_idx = 0;
+	fe_status_t status;
+	
+	if (re_tune) {
+		
+//		dbginfo("Compare symrate with table: symrate= %d, in table= %d\n", 
+//				p->u.qpsk.symbol_rate, symrates_pairs[sd_idx].symrate);
+
+		while ( p->symbol_rate > symrates_pairs[sd_idx].symrate ) {
+			++sd_idx;
+		}
+		dbginfo("Found symrate delay = %d\n", symrates_pairs[sd_idx].delay);
+		state->dvb_s2_mode &= 0xFE;			// clear bit -> try not DVB-S2
+		dbginfo("trying DVB-S =================\n");
+		cx24120_set_frontend(fe);
+		
+		delay_cnt = symrates_pairs[sd_idx].delay;
+		dbginfo("Wait for LOCK for DVB-S =================\n");
+		while (delay_cnt >= 0) {
+			cx24120_read_status(fe, &status);
+			if (status & FE_HAS_LOCK) {
+				dbginfo("DVB-S LOCKED================\n");
+				break;
+			}
+			msleep(100);
+			delay_cnt -=100;
+		}
+		dbginfo("Waiting finished - NO lock for DVB-S =================\n");
+		
+		cx24120_read_status(fe, &status);
+		if ( !(status & FE_HAS_LOCK) ) {		// if no lock on S
+			dbginfo("trying DVB-S2 ++++++++++++++++++++++++++\n");
+			state->dvb_s2_mode |= 0x01;			// may be it locked on S2 ?
+			p->fec_inner = FEC_AUTO;
+			cx24120_set_frontend(fe);
+			delay_cnt = symrates_pairs[sd_idx].delay;
+			dbginfo("Wait for LOCK for DVB-S2 ++++++++++++++++\n");
+			while (delay_cnt >= 0) {
+				cx24120_read_status(fe, &status);
+				if (status & FE_HAS_LOCK) {
+					dbginfo("DVB-S2 LOCKED++++++++++++++++\n");
+					break;
+				}
+				msleep(100);
+				delay_cnt -=100;
+			}
+			dbginfo("Waiting finished - NO lock for DVB-S2 ++++++++++++++++\n");
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cx24120_tune);	// end of cx24120_tune
+//===================================================================
+static int cx24120_get_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+EXPORT_SYMBOL(cx24120_get_algo);
+//===================================================================
+static int cx24120_sleep(struct dvb_frontend *fe)
+{
+  return 0;
+}
+EXPORT_SYMBOL(cx24120_sleep);
+//===================================================================
+/*static int cx24120_wakeup(struct dvb_frontend *fe)
+ * {
+ *   return 0;
+ * }
+ * EXPORT_SYMBOL(cx24120_wakeup);
+ */
+//===================================================================
+static int cx24120_get_frontend(struct dvb_frontend *fe)
+{
+	return 0;
+}
+EXPORT_SYMBOL(cx24120_get_frontend);
+//===================================================================
+static void cx24120_release(struct dvb_frontend *fe)
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+	dbginfo("Clear state structure\n");
+	kfree(state);
+}
+EXPORT_SYMBOL(cx24120_release);
+//===================================================================
+static int cx24120_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)	// UNCORRECTED_BLOCKS
+{
+	struct cx24120_state *state = fe->demodulator_priv;
+
+	*ucblocks = (cx24120_readreg(state, CX24120_REG_UCB_H) << 8) |
+		cx24120_readreg(state, CX24120_REG_UCB_L);
+	dbginfo("Blocks = %d\n", *ucblocks);
+	return 0;
+}
+EXPORT_SYMBOL(cx24120_read_ucblocks);
+// ########################################################################################
+static struct dvb_frontend_ops cx24120_ops = {
+
+	.delsys = { SYS_DVBS2 },
+	.info = {
+		.name = "Conexant CX24120/CX24118",
+		.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 = 						// 0x500006ff
+			FE_CAN_INVERSION_AUTO |		//0x00 000 001
+			FE_CAN_FEC_1_2 | 			//0x00 000 002
+			FE_CAN_FEC_2_3 | 			//0x00 000 004
+			FE_CAN_FEC_3_4 |			//0x00 000 008
+			FE_CAN_FEC_4_5 | 			//0x00 000 010
+			FE_CAN_FEC_5_6 | 			//0x00 000 020
+			FE_CAN_FEC_6_7 |			//0x00 000 040
+			FE_CAN_FEC_7_8 | 			//0x00 000 080
+			FE_CAN_FEC_AUTO |			//0x00 000 200
+			FE_CAN_QPSK | 				//0x00 000 400
+//???		FE_HAS_EXTENDED_CAPS |		//0x00 800 000   	/* We need more bitspace for newer APIs, indicate this. */
+			FE_CAN_2G_MODULATION |		//0x10 000 000   	/* frontend supports "2nd generation modulation" (DVB-S2) */
+			FE_CAN_RECOVER				//0x40 000 000		/* frontend can recover from a cable unplug automatically */
+	},									//sum=50 000 6FF
+	.release = 					cx24120_release,
+	
+	.init = 					cx24120_init, 
+	.sleep = 					cx24120_sleep,
+	
+	.tune = 					cx24120_tune,
+	.get_frontend_algo = 		cx24120_get_algo,
+	.set_frontend = 			cx24120_set_frontend,
+
+	.get_frontend = 			cx24120_get_frontend,
+	.read_status = 				cx24120_read_status,
+	.read_ber = 				cx24120_read_ber,
+	.read_signal_strength = 	cx24120_read_signal_strength,
+	.read_snr = 				cx24120_read_snr,
+	.read_ucblocks = 			cx24120_read_ucblocks,
+	
+	.diseqc_send_master_cmd = 	cx24120_send_diseqc_msg,
+	
+	.diseqc_send_burst = 		cx24120_diseqc_send_burst,
+	.set_tone = 				cx24120_set_tone,
+	.set_voltage = 				cx24120_set_voltage,
+};
+//===================================================================
+MODULE_PARM_DESC(cx24120_debug, "prints some verbose debugging information (default:0)");
+MODULE_AUTHOR("Sergey Tyurin");
+MODULE_LICENSE("GPL");
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/frontends/cx24120_const.h linux-3.4-r1-S2/drivers/media/dvb/frontends/cx24120_const.h
--- linux-3.4-r1/drivers/media/dvb/frontends/cx24120_const.h	1970-01-01 03:00:00.000000000 +0300
+++ linux-3.4-r1-S2/drivers/media/dvb/frontends/cx24120_const.h	2012-04-03 16:37:20.684139905 +0400
@@ -0,0 +1,259 @@ 
+/*
+ * Conexant CX24120/CX24118 - DVB-S/S2 demod/tuner driver
+ * DVBS/S2 Satellite demod/tuner driver static definitins
+ *
+ * Copyright (C) 2009 Sergey Tyurin <forum.free-x.de>
+ * Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define CX24120_FIRMWARE "dvb-fe-cx24120-1.20.58.2.fw"
+
+// ##############################
+// ### cx24120 i2c registers ###
+#define CX24120_REG_CMD_START (0x00)	// write cmd_id, and then start write args to next register:
+#define CX24120_REG_CMD_ARGS (0x01)		// write command arguments, max 4 at once, then next 4, etc.
+#define CX24120_REG_CMD_END (0x1F)		// write 0x01 for end, and read it for command result
+
+#define CX24120_REG_FECMODE (0x39)		// FEC status
+#define CX24120_REG_STATUS (0x3A)		// Tuner status - signal, carrier, sync, lock ...
+#define CX24120_REG_QUALITY_H (0x40)	// SNR high byte
+#define CX24120_REG_QUALITY_L (0x41)	// SNR low byte
+
+#define CX24120_REG_BER_HH (0x47)		// BER high byte of high word
+#define CX24120_REG_BER_HL (0x48)		// BER low byte of high word
+#define CX24120_REG_BER_LH (0x49)		// BER high byte of low word
+#define CX24120_REG_BER_LL (0x4A)		// BER low byte of low word
+
+#define CX24120_REG_SIGSTR_H (0x3A)		// Signal strength high byte & ??? status register ???
+#define CX24120_REG_SIGSTR_L (0x3B)		// Signal strength low byte
+
+#define CX24120_REG_UCB_H (0x50)		// UCB high byte
+#define CX24120_REG_UCB_L (0x51)		// UCB low byte
+
+#define CX24120_REG_REVISION (0xFF)		// Chip revision (ro). Must be 0x7 or 0x5
+
+// ##############################
+/* Command messages */
+enum command_message_id {
+	CMD_VCO_SET			= 0x10,		// cmdlen = 12;
+	CMD_TUNEREQUEST		= 0x11,		// cmd.len = 15;
+	
+	CMD_MPEG_ONOFF		= 0x13,		// cmd.len = 4;
+	CMD_MPEG_INIT		= 0x14,		// cmd.len = 7;
+	CMD_BANDWIDTH		= 0x15,		// cmd.len = 12;
+	CMD_CLOCK_READ		= 0x16,		// read clock from registers 0x01-0x06
+	CMD_CLOCK_SET		= 0x17,		// cmd.len = 10;
+	
+	CMD_DISEQC_MSG1		= 0x20,		// cmd.len = 11;
+	CMD_DISEQC_MSG2		= 0x21,		// cmd.len = d->msg_len + 6;
+	CMD_SETVOLTAGE		= 0x22,		// cmd.len = 2;
+	CMD_SETTONE			= 0x23,		// cmd.len = 4;
+	CMD_DISEQC_BURST	= 0x24,		// cmd.len not used !!!
+	
+	CMD_READ_SNR		= 0x1A,		// Read signal strength
+	CMD_START_TUNER		= 0x1B,		// ???
+	
+	CMD_TUNER_INIT		= 0x3C,		// cmd.len = 0x03;
+};
+// ##############################
+/* signal status */
+#define CX24120_HAS_SIGNAL  (0x01)
+#define CX24120_HAS_CARRIER (0x02)
+#define CX24120_HAS_VITERBI	(0x04)
+#define CX24120_HAS_LOCK 	(0x08)
+#define CX24120_HAS_UNK1 	(0x10)
+#define CX24120_HAS_UNK2 	(0x20)
+#define CX24120_STATUS_MASK (0x0f)
+#define CX24120_SIGNAL_MASK (0xc0)
+
+static u8 cx24120_msg_tuner_init[] = { 0,0,0,0,0,0 };
+static u8 cx24120_msg_read_sigstr[] = {0,0};
+
+static struct cx24120_skystar2_mpeg_config {
+	u8 x1;
+	u8 x2;
+	u8 x3;
+} initial_mpeg_config = {	
+	0xA1, 	// 10100001
+	0x76, 	// 01110110
+	0x07,	// 00000111
+};
+
+static struct cx24120_symrate_delay {
+	u32 symrate;
+	u32 delay;
+} symrates_pairs[] = {
+	{    3000000, 15000 },
+	{    6000000, 10000 },
+	{    8000000,  5000 },
+	{   10000000,  2000 },
+	{0x0FFFFFFFF,   400 },
+};
+
+static struct cx24120_clock_ratios_table {
+	u32 ratio_id;
+	u32 mode_xPSK;
+	u32 fec_mode;
+	u32	m_rat;
+	u32 n_rat;
+	u32 rate;
+} clock_ratios_table[] = {
+{	21	,	0	,	1	,	770068	,	763515	,	258	},
+{	21	,	0	,	100	,	97409	,	80370	,	310	},
+{	21	,	0	,	2	,	137293	,	101802	,	345	},
+{	21	,	0	,	3	,	4633447	,	3054060	,	388	},
+{	21	,	0	,	4	,	2472041	,	1527030	,	414	},
+{	21	,	0	,	5	,	85904	,	50901	,	432	},
+{	21	,	0	,	8	,	2751229	,	1527030	,	461	},
+{	21	,	0	,	101	,	1392872	,	763515	,	467	},
+{	21	,	99	,	100	,	1850771	,	1019430	,	464	},
+{	21	,	99	,	2	,	137293	,	67962	,	517	},
+{	21	,	99	,	3	,	4633447	,	2038860	,	581	},	// was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{	21	,	99	,	5	,	85904	,	33981	,	647	},
+{	21	,	99	,	8	,	2751229	,	1019430	,	690	},
+{	21	,	99	,	101	,	1392872	,	509715	,	699	},
+{	29	,	0	,	1	,	770068	,	782127	,	252	},
+{	29	,	0	,	100	,	1850771	,	1564254	,	302	},
+{	29	,	0	,	2	,	686465	,	521418	,	337	},
+{	29	,	0	,	3	,	4633447	,	3128508	,	379	},
+{	29	,	0	,	4	,	2472041	,	1564254	,	404	},
+{	29	,	0	,	5	,	429520	,	260709	,	421	},
+{	29	,	0	,	8	,	2751229	,	1564254	,	450	},
+{	29	,	0	,	101	,	1392872	,	782127	,	455	},
+{	29	,	99	,	100	,	1850771	,	1043118	,	454	},
+{	29	,	99	,	2	,	686465	,	347706	,	505	},
+{	29	,	99	,	3	,	4633447	,	2086236	,	568	},	// was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{	29	,	99	,	5	,	429520	,	173853	,	632	},
+{	29	,	99	,	8	,	2751229	,	1043118	,	675	},
+{	29	,	99	,	101	,	1392872	,	521559	,	683	},
+{	17	,	0	,	1	,	766052	,	763515	,	256	},
+{	17	,	0	,	100	,	96901	,	80370	,	308	},
+{	17	,	0	,	2	,	136577	,	101802	,	343	},
+{	17	,	0	,	3	,	4609283	,	3054060	,	386	},
+{	17	,	0	,	4	,	2459149	,	1527030	,	412	},
+{	17	,	0	,	5	,	85456	,	50901	,	429	},
+{	17	,	0	,	8	,	2736881	,	1527030	,	458	},
+{	17	,	0	,	101	,	1385608	,	763515	,	464	},
+{	17	,	99	,	100	,	1841119	,	1019430	,	462	},
+{	17	,	99	,	2	,	136577	,	67962	,	514	},
+{	17	,	99	,	3	,	4609283	,	2038860	,	578	},	// was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{	17	,	99	,	5	,	85456	,	33981	,	643	},
+{	17	,	99	,	8	,	2736881	,	1019430	,	687	},
+{	17	,	99	,	101	,	1385608	,	509715	,	695	},
+{	25	,	0	,	1	,	766052	,	782127	,	250	},
+{	25	,	0	,	100	,	1841119	,	1564254	,	301	},
+{	25	,	0	,	2	,	682885	,	521418	,	335	},
+{	25	,	0	,	3	,	4609283	,	3128508	,	377	},
+{	25	,	0	,	4	,	2459149	,	1564254	,	402	},
+{	25	,	0	,	5	,	427280	,	260709	,	419	},
+{	25	,	0	,	8	,	2736881	,	1564254	,	447	},
+{	25	,	0	,	101	,	1385608	,	782127	,	453	},
+{	25	,	99	,	100	,	1841119	,	1043118	,	451	},
+{	25	,	99	,	2	,	682885	,	347706	,	502	},
+{	25	,	99	,	3	,	4609283	,	2086236	,	565	},	// was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{	25	,	99	,	5	,	427280	,	173853	,	629	},
+{	25	,	99	,	8	,	2736881	,	1043118	,	671	},
+{	25	,	99	,	101	,	1385608	,	521559	,	680	},
+{	5	,	0	,	1	,	273088	,	254505	,	274	},
+{	5	,	0	,	100	,	17272	,	13395	,	330	},
+{	5	,	0	,	2	,	24344	,	16967	,	367	},
+{	5	,	0	,	3	,	410788	,	254505	,	413	},
+{	5	,	0	,	4	,	438328	,	254505	,	440	},
+{	5	,	0	,	5	,	30464	,	16967	,	459	},
+{	5	,	0	,	8	,	487832	,	254505	,	490	},
+{	5	,	0	,	101	,	493952	,	254505	,	496	},
+{	5	,	99	,	100	,	328168	,	169905	,	494	},
+{	5	,	99	,	2	,	24344	,	11327	,	550	},	// work for 0x0d - 11278V - DVB-S2 - 8PSK MPEG-4/HD
+{	5	,	99	,	3	,	410788	,	169905	,	618	},	// 0x0e S2 8psk        // was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{	5	,	99	,	5	,	30464	,	11327	,	688	},
+{	5	,	99	,	8	,	487832	,	169905	,	735	},
+{	5	,	99	,	101	,	493952	,	169905	,	744	},
+{	13	,	0	,	1	,	273088	,	260709	,	268	},
+{	13	,	0	,	100	,	328168	,	260709	,	322	},
+{	13	,	0	,	2	,	121720	,	86903	,	358	},
+{	13	,	0	,	3	,	410788	,	260709	,	403	},
+{	13	,	0	,	4	,	438328	,	260709	,	430	},
+{	13	,	0	,	5	,	152320	,	86903	,	448	},
+{	13	,	0	,	8	,	487832	,	260709	,	479	},
+{	13	,	0	,	101	,	493952	,	260709	,	485	},
+{	13	,	99	,	100	,	328168	,	173853	,	483	},
+{	13	,	99	,	2	,	121720	,	57951	,	537	}, // work for 0x8d - dvb-s2 8psk
+{	13	,	99	,	3	,	410788	,	173853	,	604	},	// was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{	13	,	99	,	5	,	152320	,	57951	,	672	},
+{	13	,	99	,	8	,	487832	,	173853	,	718	},
+{	13	,	99	,	101	,	493952	,	173853	,	727	},
+{	1	,	0	,	1	,	815248	,	763515	,	273	},
+{	1	,	0	,	100	,	51562	,	40185	,	328	},
+{	1	,	0	,	2	,	72674	,	50901	,	365	},
+{	1	,	0	,	3	,	1226323	,	763515	,	411	},
+{	1	,	0	,	4	,	1308538	,	763515	,	438	},
+{	1	,	0	,	5	,	90944	,	50901	,	457	},
+{	1	,	0	,	8	,	1456322	,	763515	,	488	},
+{	1	,	0	,	101	,	1474592	,	763515	,	494	},
+{	1	,	99	,	100	,	979678	,	509715	,	492	},
+{	1	,	99	,	2	,	72674	,	33981	,	547	},
+{	1	,	99	,	3	,	1226323	,	509715	,	615	},	// was 4 - ERRORR!? FEC_4_5 not in DVB-S2
+{	1	,	99	,	5	,	90944	,	33981	,	685	},
+{	1	,	99	,	8	,	1456322	,	509715	,	731	},
+{	1	,	99	,	101	,	1474592	,	509715	,	740	},
+{	9	,	0	,	1	,	815248	,	782127	,	266	},
+{	9	,	0	,	100	,	979678	,	782127	,	320	},
+{	9	,	0	,	2	,	363370	,	260709	,	356	},
+{	9	,	0	,	3	,	1226323	,	782127	,	401	},
+{	9	,	0	,	4	,	1308538	,	782127	,	428	},
+{	9	,	0	,	5	,	454720	,	260709	,	446	},
+{	9	,	0	,	8	,	1456322	,	782127	,	476	},
+{	9	,	0	,	101	,	1474592	,	782127	,	482	},
+{	9	,	99	,	100	,	979678	,	521559	,	480	},
+{	9	,	99	,	2	,	363370	,	173853	,	535	},
+{	9	,	99	,	3	,	1226323	,	521559	,	601	},	// was 4 - ERRORR! FEC_4_5 not in DVB-S2
+{	9	,	99	,	5	,	454720	,	173853	,	669	},
+{	9	,	99	,	8	,	1456322	,	521559	,	714	},
+{	9	,	99	,	101	,	1474592	,	521559	,	723	},
+{	18	,	0	,	1	,	535	,	588	,	233	},
+{	18	,	0	,	2	,	1070	,	882	,	311	},
+{	18	,	0	,	6	,	3210	,	2058	,	399	},
+{	16	,	0	,	1	,	763	,	816	,	239	},
+{	16	,	0	,	2	,	1526	,	1224	,	319	},
+{	16	,	0	,	3	,	2289	,	1632	,	359	},
+{	16	,	0	,	5	,	3815	,	2448	,	399	},
+{	16	,	0	,	7	,	5341	,	3264	,	419	},
+{	22	,	0	,	1	,	535	,	588	,	233	},
+{	22	,	0	,	2	,	1070	,	882	,	311	},
+{	22	,	0	,	6	,	3210	,	2058	,	399	},
+{	20	,	0	,	1	,	143429	,	152592	,	241	},
+{	20	,	0	,	2	,	286858	,	228888	,	321	},
+{	20	,	0	,	3	,	430287	,	305184	,	361	},
+{	20	,	0	,	5	,	717145	,	457776	,	401	},
+{	20	,	0	,	7	,	1004003	,	610368	,	421	},
+{	2	,	0	,	1	,	584	,	588	,	254	},
+{	2	,	0	,	2	,	1169	,	882	,	339	},
+{	2	,	0	,	6	,	3507	,	2058	,	436	},
+{	0	,	0	,	1	,	812	,	816	,	255	},
+{	0	,	0	,	2	,	1624	,	1224	,	340	},
+{	0	,	0	,	3	,	2436	,	1632	,	382	},
+{	0	,	0	,	5	,	4060	,	2448	,	425	},
+{	0	,	0	,	7	,	5684	,	3264	,	446	},
+{	6	,	0	,	1	,	584	,	588	,	254	},
+{	6	,	0	,	2	,	1168	,	882	,	339	},
+{	6	,	0	,	6	,	3504	,	2058	,	436	},
+{	4	,	0	,	1	,	152592	,	152592	,	256	},
+{	4	,	0	,	2	,	305184	,	228888	,	341	},
+{	4	,	0	,	3	,	457776	,	305184	,	384	},
+{	4	,	0	,	5	,	762960	,	457776	,	427	},
+{	4	,	0	,	7	,	1068144	,	610368	,	448	},
+};
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/frontends/cx24120.h linux-3.4-r1-S2/drivers/media/dvb/frontends/cx24120.h
--- linux-3.4-r1/drivers/media/dvb/frontends/cx24120.h	1970-01-01 03:00:00.000000000 +0300
+++ linux-3.4-r1-S2/drivers/media/dvb/frontends/cx24120.h	2012-04-03 10:27:59.000000000 +0400
@@ -0,0 +1,59 @@ 
+/*
+ * Conexant CX24120/CX24118 - DVB-S/S2 demod/tuner driver
+ *
+ * Copyright (C) 2008 Patrick Boettcher <pb@linuxtv.org>
+ * Copyright (C) 2009 Sergey Tyurin <forum.free-x.de>
+ * Updated 2012 by Jannis Achstetter <jannis_achstetter@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CX24120_H
+#define CX24120_H
+
+#include <linux/dvb/frontend.h>
+
+struct firmware;
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct cx24120_config
+{
+	u8 i2c_addr;
+	int (*request_firmware)(struct dvb_frontend *fe, const struct firmware **fw, char *name);
+	void (*stream_control)(struct dvb_frontend *fe, u8 onoff);
+};
+
+#if defined(CONFIG_DVB_CX24120) || \
+	(defined(CONFIG_DVB_CX24120_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cx24120_attach(const struct cx24120_config *config,
+		struct i2c_adapter *i2c);
+extern int cx24120_reset(struct dvb_frontend *fe);
+#else
+static inline
+struct dvb_frontend *cx24120_attach(const struct cx24120_config *config,
+		struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static inline int cx24120_reset(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return -ENODEV;
+}
+#endif
+
+#endif
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/frontends/Kconfig linux-3.4-r1-S2/drivers/media/dvb/frontends/Kconfig
--- linux-3.4-r1/drivers/media/dvb/frontends/Kconfig	2012-04-03 15:23:44.976143444 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/frontends/Kconfig	2012-04-03 15:26:40.760141513 +0400
@@ -18,6 +18,13 @@ 
 comment "Multistandard (satellite) frontends"
 	depends on DVB_CORE
 
+config DVB_CX24120
+	tristate "Conexant CX24120 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/DVB-S2 tuner module. Say Y when you want to support this frontend.
+
 config DVB_STB0899
 	tristate "STB0899 based"
 	depends on DVB_CORE && I2C
diff -NurEbBw --strip-trailing-cr linux-3.4-r1/drivers/media/dvb/frontends/Makefile linux-3.4-r1-S2/drivers/media/dvb/frontends/Makefile
--- linux-3.4-r1/drivers/media/dvb/frontends/Makefile	2012-04-03 15:23:44.976143444 +0400
+++ linux-3.4-r1-S2/drivers/media/dvb/frontends/Makefile	2012-04-03 15:26:40.760141513 +0400
@@ -20,6 +20,7 @@ 
 obj-$(CONFIG_DVB_CX22700) += cx22700.o
 obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
+obj-$(CONFIG_DVB_CX24120) += cx24120.o
 obj-$(CONFIG_DVB_TDA8083) += tda8083.o
 obj-$(CONFIG_DVB_L64781) += l64781.o
 obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o