public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
@ 2008-08-08  9:50 Timothy Lee
  2008-08-08 12:47 ` Michael Krufky
  0 siblings, 1 reply; 9+ messages in thread
From: Timothy Lee @ 2008-08-08  9:50 UTC (permalink / raw)
  To: linux-dvb

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

Dear all,

Attached is a patch against v4l-dvb repository to add support for 
Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used 
in Hong Kong and China.

Regards,
Timothy Lee

[-- Attachment #2: v4l-dvb-prohdtv-20080808.patch --]
[-- Type: text/x-patch, Size: 25512 bytes --]

diff -r fcf263987edf linux/drivers/media/dvb/dvb-usb/cxusb.c
--- a/linux/drivers/media/dvb/dvb-usb/cxusb.c	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c	Fri Aug 08 16:17:41 2008 +0800
@@ -36,6 +36,7 @@
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "mxl5005s.h"
+#include "lgs8gl5.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
@@ -107,6 +108,24 @@ static void cxusb_nano2_led(struct dvb_u
 static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
 {
 	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
+}
+
+static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
+				     u8 addr, int onoff)
+{
+	u8  o[2] = {addr, onoff};
+	u8  i;
+	int rc;
+
+	rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+
+	if (rc < 0)  return rc;
+	if (i == 0x01)  return 0;
+	else
+	{
+		deb_info("gpio_write failed.\n");
+		return -EIO;
+	}
 }
 
 /* I2C */
@@ -262,6 +281,19 @@ static int cxusb_nano2_power_ctrl(struct
 	return rc;
 }
 
+static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	u8  b;
+	ret = cxusb_power_ctrl(d, onoff);
+	if (!onoff)  return ret;
+
+	msleep(128);
+	cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
+	msleep(100);
+	return ret;
+}
+
 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	u8 buf[2] = { 0x03, 0x00 };
@@ -283,6 +315,65 @@ static int cxusb_aver_streaming_ctrl(str
 	return 0;
 }
 
+static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
+{
+	int       ep = d->props.generic_bulk_ctrl_endpoint;
+	const int timeout = 100;
+	const int junk_len = 32;
+	u8*       junk;
+	int       rd_count;
+
+	// Discard remaining data in video pipe
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)  return;
+	while (1)
+	{
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, ep),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)  break;
+	}
+	kfree(junk);
+}
+
+static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
+{
+	struct usb_data_stream_properties* p = &d->props.adapter[0].stream;
+	const int timeout = 100;
+	const int junk_len = p->u.bulk.buffersize;
+	u8*       junk;
+	int       rd_count;
+
+	// Discard remaining data in video pipe
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)  return;
+	while (1)
+	{
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, p->endpoint),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)  break;
+	}
+	kfree(junk);
+}
+
+static int cxusb_d680_dmb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	if (onoff) {
+		u8 buf[2] = { 0x03, 0x00 };
+		cxusb_d680_dmb_drain_video(adap->dev);
+		return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
+			buf, sizeof(buf), NULL, 0);
+	}
+	else {
+		int ret = cxusb_ctrl_msg(adap->dev,
+			CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+		return ret;
+	}
+}
+
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
@@ -325,6 +416,32 @@ static int cxusb_bluebird2_rc_query(stru
 	for (i = 0; i < d->props.rc_key_map_size; i++) {
 		if (keymap[i].custom == ircode[1] &&
 		    keymap[i].data == ircode[2]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
+				   int *state)
+{
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[2];
+	int i;
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
+		return 0;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[0] &&
+		    keymap[i].data == ircode[1]) {
 			*event = keymap[i].event;
 			*state = REMOTE_KEY_PRESSED;
 
@@ -422,6 +539,44 @@ static struct dvb_usb_rc_key dvico_porta
 	{ 0xfc, 0x00, KEY_UNKNOWN },    /* HD */
 };
 
+static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
+	{ 0x00, 0x38, KEY_UNKNOWN },	/* TV/AV */
+	{ 0x08, 0x0c, KEY_ZOOM },
+	{ 0x08, 0x00, KEY_0 },
+	{ 0x00, 0x01, KEY_1 },
+	{ 0x08, 0x02, KEY_2 },
+	{ 0x00, 0x03, KEY_3 },
+	{ 0x08, 0x04, KEY_4 },
+	{ 0x00, 0x05, KEY_5 },
+	{ 0x08, 0x06, KEY_6 },
+	{ 0x00, 0x07, KEY_7 },
+	{ 0x08, 0x08, KEY_8 },
+	{ 0x00, 0x09, KEY_9 },
+	{ 0x00, 0x0a, KEY_MUTE },
+	{ 0x08, 0x29, KEY_BACK },
+	{ 0x00, 0x12, KEY_CHANNELUP },
+	{ 0x08, 0x13, KEY_CHANNELDOWN },
+	{ 0x00, 0x2b, KEY_VOLUMEUP },
+	{ 0x08, 0x2c, KEY_VOLUMEDOWN },
+	{ 0x00, 0x20, KEY_UP },
+	{ 0x08, 0x21, KEY_DOWN },
+	{ 0x00, 0x11, KEY_LEFT },
+	{ 0x08, 0x10, KEY_RIGHT },
+	{ 0x00, 0x0d, KEY_OK },
+	{ 0x08, 0x1f, KEY_RECORD },
+	{ 0x00, 0x17, KEY_PLAYPAUSE },
+	{ 0x08, 0x16, KEY_PLAYPAUSE },
+	{ 0x00, 0x0b, KEY_STOP },
+	{ 0x08, 0x27, KEY_FASTFORWARD },
+	{ 0x00, 0x26, KEY_REWIND },
+	{ 0x08, 0x1e, KEY_UNKNOWN },    /* Time Shift */
+	{ 0x00, 0x0e, KEY_UNKNOWN },    /* Snapshot */
+	{ 0x08, 0x2d, KEY_UNKNOWN },    /* Mouse Cursor */
+	{ 0x00, 0x0f, KEY_UNKNOWN },    /* Minimize/Maximize */
+	{ 0x08, 0x14, KEY_UNKNOWN },    /* Shuffle */
+	{ 0x00, 0x25, KEY_POWER },
+};
+
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
 	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -527,6 +682,24 @@ static struct mxl5005s_config aver_a868r
 	.AgcMasterByte   = 0x00,
 };
 
+/* FIXME: needs tweaking */
+static struct mxl5005s_config d680_dmb_tuner = {
+	.i2c_address     = 0x63,
+	.if_freq         = 36125000UL,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -613,6 +786,14 @@ static int cxusb_mxl5003s_tuner_attach(s
 	dvb_attach(mxl5005s_attach, adap->fe,
 		   &adap->dev->i2c_adap, &aver_a868r_tuner);
 	return 0;
+}
+
+static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend* fe;
+	fe = dvb_attach(mxl5005s_attach, adap->fe,
+			&adap->dev->i2c_adap, &d680_dmb_tuner);
+	return (fe == NULL) ? -EIO : 0;
 }
 
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
@@ -751,6 +932,57 @@ static int cxusb_nano2_frontend_attach(s
 	return -EIO;
 }
 
+static struct lgs8gl5_config lgs8gl5_cfg = {
+	.demod_address = 0x19,
+};
+
+static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device* d = adap->dev;
+	int n;
+
+	/* Select required USB configuration */
+	if (usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	/* Unblock all USB pipes */
+	usb_clear_halt(d->udev,
+		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
+
+	/* Drain USB pipes to avoid hang after reboot */
+	for (n = 0;  n < 5;  n++)
+	{
+		cxusb_d680_dmb_drain_message(d);
+		cxusb_d680_dmb_drain_video(d);
+		msleep(200);
+	}
+
+	/* Reset the tuner */
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0)
+	{
+		err("clear tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0)
+	{
+		err("set tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+
+	/* Attach frontend */
+	if ((adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg,
+				   &d->i2c_adap)) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
 /*
  * DViCO has shipped two devices with the same USB ID, but only one of them
  * needs a firmware download.  Check the device class details to see if they
@@ -829,6 +1061,7 @@ static struct dvb_usb_device_properties 
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -852,6 +1085,8 @@ static int cxusb_probe(struct usb_interf
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
 				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
+	    			     THIS_MODULE, NULL, adapter_nr) ||
 	    0)
 		return 0;
 
@@ -876,6 +1111,7 @@ static struct usb_device_id cxusb_table 
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
 	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
+	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1321,6 +1557,54 @@ static struct dvb_usb_device_properties 
 	}
 };
 
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
+			.frontend_attach  = cxusb_d680_dmb_frontend_attach,
+			.tuner_attach     = cxusb_d680_dmb_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = d680_dmb_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(d680_dmb_rc_keys),
+	.rc_query         = cxusb_d680_dmb_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Conexant DMB-TH Stick",
+			{ NULL },
+			{ &cxusb_table[17], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
diff -r fcf263987edf linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Fri Aug 08 16:17:41 2008 +0800
@@ -22,6 +22,7 @@
 #define USB_VID_AVERMEDIA			0x07ca
 #define USB_VID_COMPRO				0x185b
 #define USB_VID_COMPRO_UNK			0x145f
+#define USB_VID_CONEXANT			0x0572
 #define USB_VID_CYPRESS				0x04b4
 #define USB_VID_DIBCOM				0x10b8
 #define USB_VID_DPOSH				0x1498
@@ -69,6 +70,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
+#define USB_PID_CONEXANT_D680_DMB			0x86d6
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
diff -r fcf263987edf linux/drivers/media/dvb/frontends/Kconfig
--- a/linux/drivers/media/dvb/frontends/Kconfig	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/frontends/Kconfig	Fri Aug 08 16:17:41 2008 +0800
@@ -385,4 +385,11 @@ config DVB_ISL6421
 	help
 	  An SEC control chip.
 
+config DVB_LGS8GL5
+	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DMB-TH tuner module. Say Y when you want to support this frontend.
+
 endmenu
diff -r fcf263987edf linux/drivers/media/dvb/frontends/Makefile
--- a/linux/drivers/media/dvb/frontends/Makefile	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/frontends/Makefile	Fri Aug 08 16:17:41 2008 +0800
@@ -48,3 +48,4 @@ obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
+obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
diff -r fcf263987edf linux/drivers/media/dvb/frontends/lgs8gl5.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/lgs8gl5.c	Fri Aug 08 16:17:41 2008 +0800
@@ -0,0 +1,472 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.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.
+
+    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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "lgs8gl5.h"
+
+
+#define REG_RESET		0x02
+#define REG_RESET_OFF			0x01
+#define REG_03			0x03
+#define REG_04			0x04
+#define REG_07			0x07
+#define REG_09			0x09
+#define REG_0A			0x0a
+#define REG_0B			0x0b
+#define REG_0C			0x0c
+#define REG_37			0x37
+#define REG_STRENGTH		0x4b
+#define REG_STRENGTH_MASK		0x7f
+#define REG_STRENGTH_CARRIER		0x80
+#define REG_INVERSION		0x7c
+#define REG_INVERSION_ON		0x80
+#define REG_7D			0x7d
+#define REG_7E			0x7e
+#define REG_A2			0xa2
+#define REG_STATUS		0xa4
+#define REG_STATUS_SYNC		0x04
+#define REG_STATUS_LOCK		0x01
+
+
+struct lgs8gl5_state
+{
+	struct i2c_adapter* i2c;
+	const struct lgs8gl5_config* config;
+	struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug)  printk(KERN_DEBUG "lgs8gl5: " args); \
+	} while (0)
+
+
+/* Writes into demod's register */
+static int
+lgs8gl5_write_reg(struct lgs8gl5_state* state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = {reg, data};
+	struct i2c_msg msg =
+	{
+		.addr  = state->config->demod_address,
+		.flags = 0,
+		.buf   = buf,
+		.len   = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1)
+		dprintk("%s: write_reg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			__FUNCTION__, reg, data, ret);
+	return (ret != 1) ? -1 : 0;
+}
+
+
+/* Reads from demod's register */
+static int
+lgs8gl5_read_reg(struct lgs8gl5_state* state, u8 reg)
+{
+	int ret, j;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	struct i2c_msg msg[2] =
+	{
+		{
+			.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) return -EIO;
+
+	return b1[0];
+}
+
+
+static int
+lgs8gl5_update_reg(struct lgs8gl5_state* state, u8 reg, u8 data)
+{
+	lgs8gl5_read_reg(state, reg);
+	lgs8gl5_write_reg(state, reg, data);
+	return 0;
+}
+
+
+/* Writes into alternate device's register */
+/* TODO:  Find out what that device is for! */
+static int
+lgs8gl5_update_alt_reg(struct lgs8gl5_state* state, u8 reg, u8 data)
+{
+	int ret, j;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	u8 b2[] = {reg, data};
+	struct i2c_msg msg[3] =
+	{
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b0,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = I2C_M_RD,
+			.buf   = b1,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b2,
+			.len   = 2
+		},
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 3);
+	return (ret != 3) ? -1 : 0;
+}
+
+
+static void
+lgs8gl5_soft_reset(struct lgs8gl5_state* state)
+{
+	u8 val;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	val =lgs8gl5_read_reg(state, REG_RESET);
+	lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
+	lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
+	msleep(5);
+}
+
+
+static int
+lgs8gl5_set_inversion(struct lgs8gl5_state* state, int inversion)
+{
+	u8 val;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch (inversion) {
+		case INVERSION_AUTO:
+			return -EOPNOTSUPP;
+		case INVERSION_ON:
+			val = lgs8gl5_read_reg(state, REG_INVERSION);
+			return lgs8gl5_write_reg(state, REG_INVERSION,
+				val | REG_INVERSION_ON);
+		case INVERSION_OFF:
+			val = lgs8gl5_read_reg(state, REG_INVERSION);
+			return lgs8gl5_write_reg(state, REG_INVERSION,
+				val & ~REG_INVERSION_ON);
+		default:
+			return -EINVAL;
+	}
+}
+
+
+/* Starts demodulation */
+static void
+lgs8gl5_start_demod(struct lgs8gl5_state* state)
+{
+	u8  val;
+	int n;
+
+	//dprintk ("%s\n", __FUNCTION__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+        lgs8gl5_soft_reset(state);
+        lgs8gl5_update_reg(state, REG_07, 0x10);
+        lgs8gl5_update_reg(state, REG_07, 0x10);
+        lgs8gl5_write_reg(state, REG_09, 0x0e);
+        lgs8gl5_write_reg(state, REG_0A, 0xe5);
+        lgs8gl5_write_reg(state, REG_0B, 0x35);
+        lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	lgs8gl5_update_reg(state, REG_03, 0x00);
+	lgs8gl5_update_reg(state, REG_7E, 0x01);
+	lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
+	lgs8gl5_update_reg(state, REG_04, 0x02);
+	lgs8gl5_update_reg(state, REG_37, 0x01);
+	lgs8gl5_soft_reset(state);
+
+	/* Wait for carrier */
+	for (n = 0;  n < 10;  n++)
+	{
+		val = lgs8gl5_read_reg(state, REG_STRENGTH);
+		dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
+		if (val & REG_STRENGTH_CARRIER)  break;
+		msleep(4);
+	}
+	if (!(val & REG_STRENGTH_CARRIER))  return;
+
+	/* Wait for lock */
+	for (n = 0;  n < 20;  n++)
+	{
+		val = lgs8gl5_read_reg(state, REG_STATUS);
+		dprintk("Wait for lock[%d] 0x%02X\n", n, val);
+		if (val & REG_STATUS_LOCK)  break;
+		msleep(12);
+	}
+	if (!(val & REG_STATUS_LOCK))  return;
+
+	lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
+	lgs8gl5_soft_reset(state);
+}
+
+
+static int
+lgs8gl5_init(struct dvb_frontend* fe)
+{	struct lgs8gl5_state* state = fe->demodulator_priv;
+
+	//dprintk ("%s\n", __FUNCTION__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+	lgs8gl5_soft_reset(state);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_write_reg(state, REG_09, 0x0e);
+	lgs8gl5_write_reg(state, REG_0A, 0xe5);
+	lgs8gl5_write_reg(state, REG_0B, 0x35);
+	lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
+
+	*status = 0;
+
+	if ((level & REG_STRENGTH_MASK) > 0)  *status |= FE_HAS_SIGNAL;
+	if (level & REG_STRENGTH_CARRIER)  *status |= FE_HAS_CARRIER;
+	if (flags & REG_STATUS_SYNC)  *status |= FE_HAS_SYNC;
+	if (flags & REG_STATUS_LOCK)  *status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+	*ber = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*signal_strength = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*snr = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+	*ucblocks = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ)  return -EINVAL;
+
+	if (fe->ops.tuner_ops.set_params)
+	{
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl)  fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* lgs8gl5_set_inversion(state, p->inversion); */
+
+	lgs8gl5_start_demod(state);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+	u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
+	struct dvb_ofdm_parameters *o = &p->u.ofdm;	
+
+	p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
+
+	o->code_rate_HP = FEC_1_2;
+	o->code_rate_LP = FEC_7_8;
+	o->guard_interval = GUARD_INTERVAL_1_32;
+	o->transmission_mode = TRANSMISSION_MODE_2K;
+	o->constellation = QAM_64;
+	o->hierarchy_information = HIERARCHY_NONE;
+	o->bandwidth = BANDWIDTH_8_MHZ;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 240;
+	fesettings->step_size    = 0;
+	fesettings->max_drift    = 0;
+	return 0;
+}
+
+
+static void
+lgs8gl5_release(struct dvb_frontend* fe)
+{
+	struct lgs8gl5_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+
+static struct dvb_frontend_ops lgs8gl5_ops;
+
+
+struct dvb_frontend*
+lgs8gl5_attach(const struct lgs8gl5_config* config, struct i2c_adapter* i2c)
+{
+	struct lgs8gl5_state* state = NULL;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	/* Allocate memory for the internal state */
+	state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
+	if (state == NULL)  goto error;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c    = i2c;
+
+	/* Check if the demod is there */
+	if (lgs8gl5_read_reg(state, REG_RESET) < 0)  goto error;
+
+	/* Create dvb_frontend */
+	memcpy(&state->frontend.ops, &lgs8gl5_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+
+static struct dvb_frontend_ops lgs8gl5_ops =
+{
+	.info =
+	{
+		.name			= "Legend Silicon LGS-8GL5 DMB-TH",
+		.type			= FE_OFDM,
+		.frequency_min		= 474000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 10000,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_AUTO |
+		        FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_BANDWIDTH_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+		        FE_CAN_RECOVER
+	},
+
+	.release = lgs8gl5_release,
+
+	.init = lgs8gl5_init,
+
+	.set_frontend = lgs8gl5_set_frontend,
+	.get_frontend = lgs8gl5_get_frontend,
+	.get_tune_settings = lgs8gl5_get_tune_settings,
+
+	.read_status = lgs8gl5_read_status,
+	.read_ber = lgs8gl5_read_ber,
+	.read_signal_strength = lgs8gl5_read_signal_strength,
+	.read_snr = lgs8gl5_read_snr,
+	.read_ucblocks = lgs8gl5_read_ucblocks,
+};
+
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
+MODULE_AUTHOR("Timothy Lee");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(lgs8gl5_attach);
diff -r fcf263987edf linux/drivers/media/dvb/frontends/lgs8gl5.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/lgs8gl5.h	Fri Aug 08 16:17:41 2008 +0800
@@ -0,0 +1,46 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.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.
+
+    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 LGS8GL5_H
+#define LGS8GL5_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgs8gl5_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_LGS8GL5) || (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
+extern struct dvb_frontend* lgs8gl5_attach(const struct lgs8gl5_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* lgs8gl5_attach(const struct lgs8gl5_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_LGS8GL5
+
+#endif // LGS8GL5_H

[-- Attachment #3: Type: text/plain, Size: 150 bytes --]

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-08  9:50 [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick Timothy Lee
@ 2008-08-08 12:47 ` Michael Krufky
  2008-08-09  1:20   ` hermann pitton
  2008-08-09  7:55   ` Timothy Lee
  0 siblings, 2 replies; 9+ messages in thread
From: Michael Krufky @ 2008-08-08 12:47 UTC (permalink / raw)
  To: Timothy Lee; +Cc: linux-dvb

Timothy Lee wrote:
> Dear all,
> 
> Attached is a patch against v4l-dvb repository to add support for
> Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used
> in Hong Kong and China.
> 
> Regards,
> Timothy Lee

Timothy,

In order for your patch to be applied to the kernel, a sign-off is required.

Please respond to this email with your sign-off, as described here:

http://linuxtv.org/hg/v4l-dvb/file/tip/README.patches

e) All patches shall have a Developers Certificate of Origin


Also, what software can people use with your device & driver to tune to DMB-TH services?

How do users scan for services?

Regards,

Mike

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-08 12:47 ` Michael Krufky
@ 2008-08-09  1:20   ` hermann pitton
  2008-08-09  7:55   ` Timothy Lee
  1 sibling, 0 replies; 9+ messages in thread
From: hermann pitton @ 2008-08-09  1:20 UTC (permalink / raw)
  To: Michael Krufky; +Cc: linux-dvb

Hi,

Am Freitag, den 08.08.2008, 08:47 -0400 schrieb Michael Krufky:
> Timothy Lee wrote:
> > Dear all,
> > 
> > Attached is a patch against v4l-dvb repository to add support for
> > Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used
> > in Hong Kong and China.
> > 
> > Regards,
> > Timothy Lee
> 
> Timothy,
> 
> In order for your patch to be applied to the kernel, a sign-off is required.
> 
> Please respond to this email with your sign-off, as described here:
> 
> http://linuxtv.org/hg/v4l-dvb/file/tip/README.patches
> 
> e) All patches shall have a Developers Certificate of Origin
> 
> 
> Also, what software can people use with your device & driver to tune to DMB-TH services?
> 
> How do users scan for services?
> 
> Regards,
> 
> Mike
> 

I can't see anything against the rules on it, except the yet missing
sign-off.

Acked-by: Hermann Pitton <hermann-pitton@arcor.de>

Cheers,
Hermann




_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-08 12:47 ` Michael Krufky
  2008-08-09  1:20   ` hermann pitton
@ 2008-08-09  7:55   ` Timothy Lee
  2008-08-10 17:58     ` Michael Krufky
  1 sibling, 1 reply; 9+ messages in thread
From: Timothy Lee @ 2008-08-09  7:55 UTC (permalink / raw)
  To: Michael Krufky; +Cc: linux-dvb

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

Michael Krufky wrote:
> Timothy Lee wrote:
>   
>> Attached is a patch against v4l-dvb repository to add support for
>> Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used
>> in Hong Kong and China.
>>
>> Regards,
>> Timothy Lee
>>     
>
> Timothy,
>
> In order for your patch to be applied to the kernel, a sign-off is required.
>
> Please respond to this email with your sign-off, as described here:
>
> http://linuxtv.org/hg/v4l-dvb/file/tip/README.patches
>
> e) All patches shall have a Developers Certificate of Origin
>
>
> Also, what software can people use with your device & driver to tune to DMB-TH services?
>
> How do users scan for services?
>   

Dear Michael,

Thanks for your hint on getting the patch accepted.  I've now cleaned up 
the patch to pass checkpatch.pl, and signed it off.

I've also attached a second patch against the dvb-apps repository which 
adds a DMB-TH scan file for Hong Kong.  Since the ProHDTV stick contains 
a DMB-TH decoder (lgs8gl5) onboard, it outputs MPEG-TS to the PC.

I've been using mplayer to test the driver.  But since I'm using 
dvb-usb's generic video streaming mechanism, I imagine the driver should 
be compatible with other DVB software.

Regards,
Timothy

[-- Attachment #2: v4l-dvb-prohdtv.patch --]
[-- Type: text/plain, Size: 25450 bytes --]

Signed-off-by: Timothy Lee <timothy.lee@siriushk.com>

diff -r fcf263987edf linux/drivers/media/dvb/dvb-usb/cxusb.c
--- a/linux/drivers/media/dvb/dvb-usb/cxusb.c	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c	Sat Aug 09 15:35:59 2008 +0800
@@ -36,6 +36,7 @@
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "mxl5005s.h"
+#include "lgs8gl5.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
@@ -107,6 +108,25 @@ static void cxusb_nano2_led(struct dvb_u
 static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
 {
 	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
+}
+
+static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
+		u8 addr, int onoff)
+{
+	u8  o[2] = {addr, onoff};
+	u8  i;
+	int rc;
+
+	rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+
+	if (rc < 0)
+		return rc;
+	if (i == 0x01)
+		return 0;
+	else {
+		deb_info("gpio_write failed.\n");
+		return -EIO;
+	}
 }
 
 /* I2C */
@@ -262,6 +282,20 @@ static int cxusb_nano2_power_ctrl(struct
 	return rc;
 }
 
+static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	u8  b;
+	ret = cxusb_power_ctrl(d, onoff);
+	if (!onoff)
+		return ret;
+
+	msleep(128);
+	cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
+	msleep(100);
+	return ret;
+}
+
 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	u8 buf[2] = { 0x03, 0x00 };
@@ -283,6 +317,67 @@ static int cxusb_aver_streaming_ctrl(str
 	return 0;
 }
 
+static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
+{
+	int       ep = d->props.generic_bulk_ctrl_endpoint;
+	const int timeout = 100;
+	const int junk_len = 32;
+	u8        *junk;
+	int       rd_count;
+
+	/* Discard remaining data in video pipe */
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)
+		return;
+	while (1) {
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, ep),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)
+			break;
+	}
+	kfree(junk);
+}
+
+static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
+{
+	struct usb_data_stream_properties *p = &d->props.adapter[0].stream;
+	const int timeout = 100;
+	const int junk_len = p->u.bulk.buffersize;
+	u8        *junk;
+	int       rd_count;
+
+	/* Discard remaining data in video pipe */
+	junk = kmalloc(junk_len, GFP_KERNEL);
+	if (!junk)
+		return;
+	while (1) {
+		if (usb_bulk_msg(d->udev,
+			usb_rcvbulkpipe(d->udev, p->endpoint),
+			junk, junk_len, &rd_count, timeout) < 0)
+			break;
+		if (!rd_count)
+			break;
+	}
+	kfree(junk);
+}
+
+static int cxusb_d680_dmb_streaming_ctrl(
+		struct dvb_usb_adapter *adap, int onoff)
+{
+	if (onoff) {
+		u8 buf[2] = { 0x03, 0x00 };
+		cxusb_d680_dmb_drain_video(adap->dev);
+		return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
+			buf, sizeof(buf), NULL, 0);
+	} else {
+		int ret = cxusb_ctrl_msg(adap->dev,
+			CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+		return ret;
+	}
+}
+
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
@@ -325,6 +420,32 @@ static int cxusb_bluebird2_rc_query(stru
 	for (i = 0; i < d->props.rc_key_map_size; i++) {
 		if (keymap[i].custom == ircode[1] &&
 		    keymap[i].data == ircode[2]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
+		int *state)
+{
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[2];
+	int i;
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
+		return 0;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[0] &&
+		    keymap[i].data == ircode[1]) {
 			*event = keymap[i].event;
 			*state = REMOTE_KEY_PRESSED;
 
@@ -422,6 +543,44 @@ static struct dvb_usb_rc_key dvico_porta
 	{ 0xfc, 0x00, KEY_UNKNOWN },    /* HD */
 };
 
+static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
+	{ 0x00, 0x38, KEY_UNKNOWN },	/* TV/AV */
+	{ 0x08, 0x0c, KEY_ZOOM },
+	{ 0x08, 0x00, KEY_0 },
+	{ 0x00, 0x01, KEY_1 },
+	{ 0x08, 0x02, KEY_2 },
+	{ 0x00, 0x03, KEY_3 },
+	{ 0x08, 0x04, KEY_4 },
+	{ 0x00, 0x05, KEY_5 },
+	{ 0x08, 0x06, KEY_6 },
+	{ 0x00, 0x07, KEY_7 },
+	{ 0x08, 0x08, KEY_8 },
+	{ 0x00, 0x09, KEY_9 },
+	{ 0x00, 0x0a, KEY_MUTE },
+	{ 0x08, 0x29, KEY_BACK },
+	{ 0x00, 0x12, KEY_CHANNELUP },
+	{ 0x08, 0x13, KEY_CHANNELDOWN },
+	{ 0x00, 0x2b, KEY_VOLUMEUP },
+	{ 0x08, 0x2c, KEY_VOLUMEDOWN },
+	{ 0x00, 0x20, KEY_UP },
+	{ 0x08, 0x21, KEY_DOWN },
+	{ 0x00, 0x11, KEY_LEFT },
+	{ 0x08, 0x10, KEY_RIGHT },
+	{ 0x00, 0x0d, KEY_OK },
+	{ 0x08, 0x1f, KEY_RECORD },
+	{ 0x00, 0x17, KEY_PLAYPAUSE },
+	{ 0x08, 0x16, KEY_PLAYPAUSE },
+	{ 0x00, 0x0b, KEY_STOP },
+	{ 0x08, 0x27, KEY_FASTFORWARD },
+	{ 0x00, 0x26, KEY_REWIND },
+	{ 0x08, 0x1e, KEY_UNKNOWN },    /* Time Shift */
+	{ 0x00, 0x0e, KEY_UNKNOWN },    /* Snapshot */
+	{ 0x08, 0x2d, KEY_UNKNOWN },    /* Mouse Cursor */
+	{ 0x00, 0x0f, KEY_UNKNOWN },    /* Minimize/Maximize */
+	{ 0x08, 0x14, KEY_UNKNOWN },    /* Shuffle */
+	{ 0x00, 0x25, KEY_POWER },
+};
+
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
 	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -527,6 +686,24 @@ static struct mxl5005s_config aver_a868r
 	.AgcMasterByte   = 0x00,
 };
 
+/* FIXME: needs tweaking */
+static struct mxl5005s_config d680_dmb_tuner = {
+	.i2c_address     = 0x63,
+	.if_freq         = 36125000UL,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -613,6 +790,14 @@ static int cxusb_mxl5003s_tuner_attach(s
 	dvb_attach(mxl5005s_attach, adap->fe,
 		   &adap->dev->i2c_adap, &aver_a868r_tuner);
 	return 0;
+}
+
+static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend *fe;
+	fe = dvb_attach(mxl5005s_attach, adap->fe,
+			&adap->dev->i2c_adap, &d680_dmb_tuner);
+	return (fe == NULL) ? -EIO : 0;
 }
 
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
@@ -751,6 +936,54 @@ static int cxusb_nano2_frontend_attach(s
 	return -EIO;
 }
 
+static struct lgs8gl5_config lgs8gl5_cfg = {
+	.demod_address = 0x19,
+};
+
+static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_usb_device *d = adap->dev;
+	int n;
+
+	/* Select required USB configuration */
+	if (usb_set_interface(d->udev, 0, 0) < 0)
+		err("set interface failed");
+
+	/* Unblock all USB pipes */
+	usb_clear_halt(d->udev,
+		usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+	usb_clear_halt(d->udev,
+		usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
+
+	/* Drain USB pipes to avoid hang after reboot */
+	for (n = 0;  n < 5;  n++) {
+		cxusb_d680_dmb_drain_message(d);
+		cxusb_d680_dmb_drain_video(d);
+		msleep(200);
+	}
+
+	/* Reset the tuner */
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
+		err("clear tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
+		err("set tuner gpio failed");
+		return -EIO;
+	}
+	msleep(100);
+
+	/* Attach frontend */
+	adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap);
+	if (adap->fe == NULL)
+		return -EIO;
+
+	return 0;
+}
+
 /*
  * DViCO has shipped two devices with the same USB ID, but only one of them
  * needs a firmware download.  Check the device class details to see if they
@@ -829,6 +1062,7 @@ static struct dvb_usb_device_properties 
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -852,6 +1086,8 @@ static int cxusb_probe(struct usb_interf
 				     THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
 				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
 	    0)
 		return 0;
 
@@ -876,6 +1112,7 @@ static struct usb_device_id cxusb_table 
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
 	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
+	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1321,6 +1558,55 @@ static struct dvb_usb_device_properties 
 	}
 };
 
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
+			.frontend_attach  = cxusb_d680_dmb_frontend_attach,
+			.tuner_attach     = cxusb_d680_dmb_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = d680_dmb_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(d680_dmb_rc_keys),
+	.rc_query         = cxusb_d680_dmb_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			"Conexant DMB-TH Stick",
+			{ NULL },
+			{ &cxusb_table[17], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
diff -r fcf263987edf linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Sat Aug 09 15:35:59 2008 +0800
@@ -22,6 +22,7 @@
 #define USB_VID_AVERMEDIA			0x07ca
 #define USB_VID_COMPRO				0x185b
 #define USB_VID_COMPRO_UNK			0x145f
+#define USB_VID_CONEXANT			0x0572
 #define USB_VID_CYPRESS				0x04b4
 #define USB_VID_DIBCOM				0x10b8
 #define USB_VID_DPOSH				0x1498
@@ -69,6 +70,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
+#define USB_PID_CONEXANT_D680_DMB			0x86d6
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
diff -r fcf263987edf linux/drivers/media/dvb/frontends/Kconfig
--- a/linux/drivers/media/dvb/frontends/Kconfig	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/frontends/Kconfig	Sat Aug 09 15:35:59 2008 +0800
@@ -385,4 +385,11 @@ config DVB_ISL6421
 	help
 	  An SEC control chip.
 
+config DVB_LGS8GL5
+	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DMB-TH tuner module. Say Y when you want to support this frontend.
+
 endmenu
diff -r fcf263987edf linux/drivers/media/dvb/frontends/Makefile
--- a/linux/drivers/media/dvb/frontends/Makefile	Tue Aug 05 10:14:13 2008 -0300
+++ b/linux/drivers/media/dvb/frontends/Makefile	Sat Aug 09 15:35:59 2008 +0800
@@ -48,3 +48,4 @@ obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
+obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
diff -r fcf263987edf linux/drivers/media/dvb/frontends/lgs8gl5.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/lgs8gl5.c	Sat Aug 09 15:35:59 2008 +0800
@@ -0,0 +1,480 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.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.
+
+    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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "lgs8gl5.h"
+
+
+#define REG_RESET		0x02
+#define REG_RESET_OFF			0x01
+#define REG_03			0x03
+#define REG_04			0x04
+#define REG_07			0x07
+#define REG_09			0x09
+#define REG_0A			0x0a
+#define REG_0B			0x0b
+#define REG_0C			0x0c
+#define REG_37			0x37
+#define REG_STRENGTH		0x4b
+#define REG_STRENGTH_MASK		0x7f
+#define REG_STRENGTH_CARRIER		0x80
+#define REG_INVERSION		0x7c
+#define REG_INVERSION_ON		0x80
+#define REG_7D			0x7d
+#define REG_7E			0x7e
+#define REG_A2			0xa2
+#define REG_STATUS		0xa4
+#define REG_STATUS_SYNC		0x04
+#define REG_STATUS_LOCK		0x01
+
+
+struct lgs8gl5_state {
+	struct i2c_adapter *i2c;
+	const struct lgs8gl5_config *config;
+	struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "lgs8gl5: " args); \
+	} while (0)
+
+
+/* Writes into demod's register */
+static int
+lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf[] = {reg, data};
+	struct i2c_msg msg = {
+		.addr  = state->config->demod_address,
+		.flags = 0,
+		.buf   = buf,
+		.len   = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1)
+		dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
+			__func__, reg, data, ret);
+	return (ret != 1) ? -1 : 0;
+}
+
+
+/* Reads from demod's register */
+static int
+lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
+{
+	int ret, j;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	struct i2c_msg msg[2] = {
+		{
+			.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)
+		return -EIO;
+
+	return b1[0];
+}
+
+
+static int
+lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	lgs8gl5_read_reg(state, reg);
+	lgs8gl5_write_reg(state, reg, data);
+	return 0;
+}
+
+
+/* Writes into alternate device's register */
+/* TODO:  Find out what that device is for! */
+static int
+lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
+{
+	int ret, j;
+	u8 b0[] = {reg};
+	u8 b1[] = {0};
+	u8 b2[] = {reg, data};
+	struct i2c_msg msg[3] = {
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b0,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = I2C_M_RD,
+			.buf   = b1,
+			.len   = 1
+		},
+		{
+			.addr  = state->config->demod_address + 2,
+			.flags = 0,
+			.buf   = b2,
+			.len   = 2
+		},
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 3);
+	return (ret != 3) ? -1 : 0;
+}
+
+
+static void
+lgs8gl5_soft_reset(struct lgs8gl5_state *state)
+{
+	u8 val;
+
+	dprintk("%s\n", __func__);
+
+	val = lgs8gl5_read_reg(state, REG_RESET);
+	lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
+	lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
+	msleep(5);
+}
+
+
+static int
+lgs8gl5_set_inversion(struct lgs8gl5_state *state, int inversion)
+{
+	u8 val;
+
+	dprintk("%s\n", __func__);
+
+	switch (inversion) {
+	case INVERSION_AUTO:
+		return -EOPNOTSUPP;
+	case INVERSION_ON:
+		val = lgs8gl5_read_reg(state, REG_INVERSION);
+		return lgs8gl5_write_reg(state, REG_INVERSION,
+			val | REG_INVERSION_ON);
+	case INVERSION_OFF:
+		val = lgs8gl5_read_reg(state, REG_INVERSION);
+		return lgs8gl5_write_reg(state, REG_INVERSION,
+			val & ~REG_INVERSION_ON);
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/* Starts demodulation */
+static void
+lgs8gl5_start_demod(struct lgs8gl5_state *state)
+{
+	u8  val;
+	int n;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+	lgs8gl5_soft_reset(state);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_write_reg(state, REG_09, 0x0e);
+	lgs8gl5_write_reg(state, REG_0A, 0xe5);
+	lgs8gl5_write_reg(state, REG_0B, 0x35);
+	lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	lgs8gl5_update_reg(state, REG_03, 0x00);
+	lgs8gl5_update_reg(state, REG_7E, 0x01);
+	lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
+	lgs8gl5_update_reg(state, REG_04, 0x02);
+	lgs8gl5_update_reg(state, REG_37, 0x01);
+	lgs8gl5_soft_reset(state);
+
+	/* Wait for carrier */
+	for (n = 0;  n < 10;  n++) {
+		val = lgs8gl5_read_reg(state, REG_STRENGTH);
+		dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
+		if (val & REG_STRENGTH_CARRIER)
+			break;
+		msleep(4);
+	}
+	if (!(val & REG_STRENGTH_CARRIER))
+		return;
+
+	/* Wait for lock */
+	for (n = 0;  n < 20;  n++) {
+		val = lgs8gl5_read_reg(state, REG_STATUS);
+		dprintk("Wait for lock[%d] 0x%02X\n", n, val);
+		if (val & REG_STATUS_LOCK)
+			break;
+		msleep(12);
+	}
+	if (!(val & REG_STATUS_LOCK))
+		return;
+
+	lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
+	lgs8gl5_soft_reset(state);
+}
+
+
+static int
+lgs8gl5_init(struct dvb_frontend *fe)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
+	lgs8gl5_soft_reset(state);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_update_reg(state, REG_07, 0x10);
+	lgs8gl5_write_reg(state, REG_09, 0x0e);
+	lgs8gl5_write_reg(state, REG_0A, 0xe5);
+	lgs8gl5_write_reg(state, REG_0B, 0x35);
+	lgs8gl5_write_reg(state, REG_0C, 0x30);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
+
+	*status = 0;
+
+	if ((level & REG_STRENGTH_MASK) > 0)
+		*status |= FE_HAS_SIGNAL;
+	if (level & REG_STRENGTH_CARRIER)
+		*status |= FE_HAS_CARRIER;
+	if (flags & REG_STATUS_SYNC)
+		*status |= FE_HAS_SYNC;
+	if (flags & REG_STATUS_LOCK)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	*ber = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*signal_strength = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
+	*snr = (level & REG_STRENGTH_MASK) << 8;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	*ucblocks = 0;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_set_frontend(struct dvb_frontend *fe,
+		struct dvb_frontend_parameters *p)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+
+	if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ)
+		return -EINVAL;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* lgs8gl5_set_inversion(state, p->inversion); */
+
+	lgs8gl5_start_demod(state);
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_frontend(struct dvb_frontend *fe,
+		struct dvb_frontend_parameters *p)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
+	struct dvb_ofdm_parameters *o = &p->u.ofdm;
+
+	p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
+
+	o->code_rate_HP = FEC_1_2;
+	o->code_rate_LP = FEC_7_8;
+	o->guard_interval = GUARD_INTERVAL_1_32;
+	o->transmission_mode = TRANSMISSION_MODE_2K;
+	o->constellation = QAM_64;
+	o->hierarchy_information = HIERARCHY_NONE;
+	o->bandwidth = BANDWIDTH_8_MHZ;
+
+	return 0;
+}
+
+
+static int
+lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 240;
+	fesettings->step_size    = 0;
+	fesettings->max_drift    = 0;
+	return 0;
+}
+
+
+static void
+lgs8gl5_release(struct dvb_frontend *fe)
+{
+	struct lgs8gl5_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+
+static struct dvb_frontend_ops lgs8gl5_ops;
+
+
+struct dvb_frontend*
+lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
+{
+	struct lgs8gl5_state *state = NULL;
+
+	dprintk("%s\n", __func__);
+
+	/* Allocate memory for the internal state */
+	state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* Setup the state */
+	state->config = config;
+	state->i2c    = i2c;
+
+	/* Check if the demod is there */
+	if (lgs8gl5_read_reg(state, REG_RESET) < 0)
+		goto error;
+
+	/* Create dvb_frontend */
+	memcpy(&state->frontend.ops, &lgs8gl5_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(lgs8gl5_attach);
+
+
+static struct dvb_frontend_ops lgs8gl5_ops = {
+	.info = {
+		.name			= "Legend Silicon LGS-8GL5 DMB-TH",
+		.type			= FE_OFDM,
+		.frequency_min		= 474000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 10000,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
+			FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_BANDWIDTH_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER
+	},
+
+	.release = lgs8gl5_release,
+
+	.init = lgs8gl5_init,
+
+	.set_frontend = lgs8gl5_set_frontend,
+	.get_frontend = lgs8gl5_get_frontend,
+	.get_tune_settings = lgs8gl5_get_tune_settings,
+
+	.read_status = lgs8gl5_read_status,
+	.read_ber = lgs8gl5_read_ber,
+	.read_signal_strength = lgs8gl5_read_signal_strength,
+	.read_snr = lgs8gl5_read_snr,
+	.read_ucblocks = lgs8gl5_read_ucblocks,
+};
+
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
+MODULE_AUTHOR("Timothy Lee");
+MODULE_LICENSE("GPL");
diff -r fcf263987edf linux/drivers/media/dvb/frontends/lgs8gl5.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/lgs8gl5.h	Sat Aug 09 15:35:59 2008 +0800
@@ -0,0 +1,45 @@
+/*
+    Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+    Copyright (C) 2008 Sirius International (Hong Kong) Limited
+	Timothy Lee <timothy.lee@siriushk.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.
+
+    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 LGS8GL5_H
+#define LGS8GL5_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgs8gl5_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_LGS8GL5) || \
+	(defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
+extern struct dvb_frontend *lgs8gl5_attach(
+	const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lgs8gl5_attach(
+	const struct lgs8gl5_config *config, struct i2c_adapter *i2c) {
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_LGS8GL5 */
+
+#endif /* LGS8GL5_H */

[-- Attachment #3: dvb-apps-dmbth.patch --]
[-- Type: text/plain, Size: 802 bytes --]

Signed-off-by: Timothy Lee <timothy.lee@siriushk.com>

diff -r 98b4f2928fd6 util/scan/dmb-th/hk-HongKong
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/scan/dmb-th/hk-HongKong	Sat Aug 09 15:30:44 2008 +0800
@@ -0,0 +1,18 @@
+# Hong Kong
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+
+# TVB (band 35)
+T 586000000 8MHz AUTO AUTO QAM64 8k 1/32 NONE
+# ATV (band 37)
+T 602000000 8MHz AUTO AUTO QAM64 8k 1/32 NONE
+
+# Simulcast (band 22)
+T 482000000 8MHz AUTO AUTO QAM64 8k 1/32 NONE
+# Simulcast (band 30)
+T 546000000 8MHz AUTO AUTO QAM64 8k 1/32 NONE
+# Simulcast (band 32)
+T 562000000 8MHz AUTO AUTO QAM64 8k 1/32 NONE
+# Simulcast (band 40)
+T 628000000 8MHz AUTO AUTO QAM64 8k 1/32 NONE
+# Simulcast (band 43)
+T 650000000 8MHz AUTO AUTO QAM64 8k 1/32 NONE

[-- Attachment #4: Type: text/plain, Size: 150 bytes --]

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-09  7:55   ` Timothy Lee
@ 2008-08-10 17:58     ` Michael Krufky
  2008-08-10 18:02       ` Michael Krufky
                         ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Michael Krufky @ 2008-08-10 17:58 UTC (permalink / raw)
  To: Timothy Lee; +Cc: linux-dvb

Timothy Lee wrote:
> Michael Krufky wrote:
>> Timothy Lee wrote:
>>  
>>> Attached is a patch against v4l-dvb repository to add support for
>>> Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used
>>> in Hong Kong and China.
>>>
>>> Regards,
>>> Timothy Lee
>>>     
>>
>> Timothy,
>>
>> In order for your patch to be applied to the kernel, a sign-off is
>> required.
>>
>> Please respond to this email with your sign-off, as described here:
>>
>> http://linuxtv.org/hg/v4l-dvb/file/tip/README.patches
>>
>> e) All patches shall have a Developers Certificate of Origin
>>
>>
>> Also, what software can people use with your device & driver to tune
>> to DMB-TH services?
>>
>> How do users scan for services?
>>   
>
> Dear Michael,
>
> Thanks for your hint on getting the patch accepted.  I've now cleaned
> up the patch to pass checkpatch.pl, and signed it off.
>
> I've also attached a second patch against the dvb-apps repository
> which adds a DMB-TH scan file for Hong Kong.  Since the ProHDTV stick
> contains a DMB-TH decoder (lgs8gl5) onboard, it outputs MPEG-TS to the
> PC.
>
> I've been using mplayer to test the driver.  But since I'm using
> dvb-usb's generic video streaming mechanism, I imagine the driver
> should be compatible with other DVB software. 
Timothy,

I've applied your patch to my cxusb tree, with slight modifications, in
order to coincide with another patch to the same code.  Please test the
tree and confirm proper operation before I request a merge into the
master branch.

http://linuxtv.org/hg/~mkrufky/cxusb

I'll push the Hong Kong scan file to dvb-apps after this tree is merged
into the master branch.

If you have any additional fixes / changes to make before this is merged
into master, please generate them against this cxusb tree.

Regards,

Mike



_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-10 17:58     ` Michael Krufky
@ 2008-08-10 18:02       ` Michael Krufky
  2008-08-11  1:41         ` Timothy Lee
  2008-08-11  2:03       ` Timothy Lee
  2008-08-11 10:52       ` Christoph Pfister
  2 siblings, 1 reply; 9+ messages in thread
From: Michael Krufky @ 2008-08-10 18:02 UTC (permalink / raw)
  To: Timothy Lee; +Cc: linux-dvb

Michael Krufky wrote:
> Timothy Lee wrote:
>> Michael Krufky wrote:
>>> Timothy Lee wrote:
>>>  
>>>> Attached is a patch against v4l-dvb repository to add support for
>>>> Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used
>>>> in Hong Kong and China.
>>>>
>>>> Regards,
>>>> Timothy Lee
>>>>     
>>> Timothy,
>>>
>>> In order for your patch to be applied to the kernel, a sign-off is
>>> required.
>>>
>>> Please respond to this email with your sign-off, as described here:
>>>
>>> http://linuxtv.org/hg/v4l-dvb/file/tip/README.patches
>>>
>>> e) All patches shall have a Developers Certificate of Origin
>>>
>>>
>>> Also, what software can people use with your device & driver to tune
>>> to DMB-TH services?
>>>
>>> How do users scan for services?
>>>   
>> Dear Michael,
>>
>> Thanks for your hint on getting the patch accepted.  I've now cleaned
>> up the patch to pass checkpatch.pl, and signed it off.
>>
>> I've also attached a second patch against the dvb-apps repository
>> which adds a DMB-TH scan file for Hong Kong.  Since the ProHDTV stick
>> contains a DMB-TH decoder (lgs8gl5) onboard, it outputs MPEG-TS to the
>> PC.
>>
>> I've been using mplayer to test the driver.  But since I'm using
>> dvb-usb's generic video streaming mechanism, I imagine the driver
>> should be compatible with other DVB software. 
> Timothy,
> 
> I've applied your patch to my cxusb tree, with slight modifications, in
> order to coincide with another patch to the same code.  Please test the
> tree and confirm proper operation before I request a merge into the
> master branch.
> 
> http://linuxtv.org/hg/~mkrufky/cxusb
> 
> I'll push the Hong Kong scan file to dvb-apps after this tree is merged
> into the master branch.
> 
> If you have any additional fixes / changes to make before this is merged
> into master, please generate them against this cxusb tree.

I also have a question--

If the device is called, "Magic-Pro DMB-TH usb stick" then I think that we
should change its name from "Conexant DMB-TH Stick" to "Magic-Pro DMB-TH usb stick"

Which is the correct name?

-Mike

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-10 18:02       ` Michael Krufky
@ 2008-08-11  1:41         ` Timothy Lee
  0 siblings, 0 replies; 9+ messages in thread
From: Timothy Lee @ 2008-08-11  1:41 UTC (permalink / raw)
  To: Michael Krufky; +Cc: linux-dvb


[-- Attachment #1.1: Type: text/plain, Size: 2482 bytes --]

Michael Krufky wrote:
> Michael Krufky wrote:
>    
>> Timothy Lee wrote:
>>      
>>> Michael Krufky wrote:
>>>        
>>>> Timothy Lee wrote:
>>>>
>>>>          
>>>>> Attached is a patch against v4l-dvb repository to add support for
>>>>> Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used
>>>>> in Hong Kong and China.
>>>>>
>>>>> Regards,
>>>>> Timothy Lee
>>>>>
>>>>>            
>>>> Timothy,
>>>>
>>>> In order for your patch to be applied to the kernel, a sign-off is
>>>> required.
>>>>
>>>> Please respond to this email with your sign-off, as described here:
>>>>
>>>> http://linuxtv.org/hg/v4l-dvb/file/tip/README.patches
>>>>
>>>> e) All patches shall have a Developers Certificate of Origin
>>>>
>>>>
>>>> Also, what software can people use with your device&  driver to tune
>>>> to DMB-TH services?
>>>>
>>>> How do users scan for services?
>>>>
>>>>          
>>> Dear Michael,
>>>
>>> Thanks for your hint on getting the patch accepted.  I've now cleaned
>>> up the patch to pass checkpatch.pl, and signed it off.
>>>
>>> I've also attached a second patch against the dvb-apps repository
>>> which adds a DMB-TH scan file for Hong Kong.  Since the ProHDTV stick
>>> contains a DMB-TH decoder (lgs8gl5) onboard, it outputs MPEG-TS to the
>>> PC.
>>>
>>> I've been using mplayer to test the driver.  But since I'm using
>>> dvb-usb's generic video streaming mechanism, I imagine the driver
>>> should be compatible with other DVB software.
>>>        
>> Timothy,
>>
>> I've applied your patch to my cxusb tree, with slight modifications, in
>> order to coincide with another patch to the same code.  Please test the
>> tree and confirm proper operation before I request a merge into the
>> master branch.
>>
>> http://linuxtv.org/hg/~mkrufky/cxusb
>>
>> I'll push the Hong Kong scan file to dvb-apps after this tree is merged
>> into the master branch.
>>
>> If you have any additional fixes / changes to make before this is merged
>> into master, please generate them against this cxusb tree.
>>      
>
> I also have a question--
>
> If the device is called, "Magic-Pro DMB-TH usb stick" then I think that we
> should change its name from "Conexant DMB-TH Stick" to "Magic-Pro DMB-TH usb stick"
>
> Which is the correct name?
>
> -Mike
>    
"Conexant..." is the name listed in the Windows INF file.  The circuit 
board appears to be a reference design branded by at least two companies 
(MagicPro and Mygica) in Hong Kong.

Regards,
Timohty

[-- Attachment #1.2: Type: text/html, Size: 3152 bytes --]

[-- Attachment #2: Type: text/plain, Size: 150 bytes --]

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-10 17:58     ` Michael Krufky
  2008-08-10 18:02       ` Michael Krufky
@ 2008-08-11  2:03       ` Timothy Lee
  2008-08-11 10:52       ` Christoph Pfister
  2 siblings, 0 replies; 9+ messages in thread
From: Timothy Lee @ 2008-08-11  2:03 UTC (permalink / raw)
  To: Michael Krufky; +Cc: linux-dvb

Michael Krufky wrote:
> Timothy Lee wrote:
>    
>> Michael Krufky wrote:
>>      
>>> Timothy Lee wrote:
>>>
>>>        
>>>> Attached is a patch against v4l-dvb repository to add support for
>>>> Magic-Pro DMB-TH usb stick.  DMB-TH is the HDTV broadcast standard used
>>>> in Hong Kong and China.
>>>>
>>>> Regards,
>>>> Timothy Lee
>>>>
>>>>          
>>> Timothy,
>>>
>>> In order for your patch to be applied to the kernel, a sign-off is
>>> required.
>>>
>>> Please respond to this email with your sign-off, as described here:
>>>
>>> http://linuxtv.org/hg/v4l-dvb/file/tip/README.patches
>>>
>>> e) All patches shall have a Developers Certificate of Origin
>>>
>>>
>>> Also, what software can people use with your device&  driver to tune
>>> to DMB-TH services?
>>>
>>> How do users scan for services?
>>>
>>>        
>> Dear Michael,
>>
>> Thanks for your hint on getting the patch accepted.  I've now cleaned
>> up the patch to pass checkpatch.pl, and signed it off.
>>
>> I've also attached a second patch against the dvb-apps repository
>> which adds a DMB-TH scan file for Hong Kong.  Since the ProHDTV stick
>> contains a DMB-TH decoder (lgs8gl5) onboard, it outputs MPEG-TS to the
>> PC.
>>
>> I've been using mplayer to test the driver.  But since I'm using
>> dvb-usb's generic video streaming mechanism, I imagine the driver
>> should be compatible with other DVB software.
>>      
> Timothy,
>
> I've applied your patch to my cxusb tree, with slight modifications, in
> order to coincide with another patch to the same code.  Please test the
> tree and confirm proper operation before I request a merge into the
> master branch.
>
> http://linuxtv.org/hg/~mkrufky/cxusb
>
> I'll push the Hong Kong scan file to dvb-apps after this tree is merged
> into the master branch.
>
> If you have any additional fixes / changes to make before this is merged
> into master, please generate them against this cxusb tree.
>    
I've tested your cxusb tree, and the newly added code is working fine.  
Thanks!

Regards,
Timothy

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

* Re: [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick
  2008-08-10 17:58     ` Michael Krufky
  2008-08-10 18:02       ` Michael Krufky
  2008-08-11  2:03       ` Timothy Lee
@ 2008-08-11 10:52       ` Christoph Pfister
  2 siblings, 0 replies; 9+ messages in thread
From: Christoph Pfister @ 2008-08-11 10:52 UTC (permalink / raw)
  To: linux-dvb; +Cc: Michael Krufky

Hi Mike,

Am Sonntag 10 August 2008 19:58:34 schrieb Michael Krufky:
<snip>
> Timothy,
>
> I've applied your patch to my cxusb tree, with slight modifications, in
> order to coincide with another patch to the same code.  Please test the
> tree and confirm proper operation before I request a merge into the
> master branch.
>
> http://linuxtv.org/hg/~mkrufky/cxusb
>
> I'll push the Hong Kong scan file to dvb-apps after this tree is merged
> into the master branch.

I didn't really follow the discussion (sorry), but I think if the device 
presents itself as a dvb-t device and is usable as a (pseudo-)dvb-t device 
(tune / scan / watch), the scan file should be in the dvb-t. And in this case 
please change "fec_lo" to "NONE" when you're committing.

> If you have any additional fixes / changes to make before this is merged
> into master, please generate them against this cxusb tree.
>
> Regards,
>
> Mike

Thanks,

Christoph

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

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

end of thread, other threads:[~2008-08-11 10:52 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-08  9:50 [linux-dvb] [PATCH] Support for Magic-Pro DMB-TH usb stick Timothy Lee
2008-08-08 12:47 ` Michael Krufky
2008-08-09  1:20   ` hermann pitton
2008-08-09  7:55   ` Timothy Lee
2008-08-10 17:58     ` Michael Krufky
2008-08-10 18:02       ` Michael Krufky
2008-08-11  1:41         ` Timothy Lee
2008-08-11  2:03       ` Timothy Lee
2008-08-11 10:52       ` Christoph Pfister

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox