Re: [RFC] multi std silicon tuners and analog tuners

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Manu Abraham wrote:
> Hi All,
> 
> Currently, we have silicon tuners loading FIR filter specific DSP boot
> codes for tuners as well, of course Silicon tuners. While working with
> the STB6100 silicon tuner which had been a rogue for that matter, found
> that the same could be extended for tuners as well.
> 
> Some tuners as what i see, loads delivery system specific firmware to
> optimize the FIR filter characteristics on the teeny DSP of the silicon
> tuner. In some cases the DSP boot code is as well included in the
> firmware which needs a reset of the DSP, but in many cases doesn't need so
> 
> The approach can be used for *all* hybrid tuners how complex it might be
> since it leaves room for future expansion as well.
> 
> My thoughts go like this.
> 
> currently the existing infrastructure is assumed to be thus ...
> 
> DVB API is modified with the multiproto API update which thus has the
> enhanced Silicon tuner changes already for the STB6100.
> 
> with regards to the DVB API , the userspace sets a delivery system for
> the demodulator, which can be a cached parameter at the bridge(ie, the
> card config to be precise, which is also known as the glue logic)
> 
> so when subsystem A acquires control, a lock is acquired by the bridge
> (the bridge can be imagined as a fulcrum for switching between systems)
> This locking would be a FSM for handling different switches.
> 
> now the bridge can acquire/release locks, needs some code additions to
> the bridge to have this, for old devices it doesn't matter at all.
> 
> now when subsystem B request control, it makes a request to the control
> manager on the bridge, the control is passed all the way down from the
> frontend(DVB)/ tuner(V4L) so it still remains quite independent the
> tuner/frontend part from the bridge
> 

[..]

> with regards to TUNER (V4L) the same can be achieved using set standard
> or similar.
> Will have additionally one more callback (a new one)
> 

A possible implementation patch i have attached to this post. The base
tree is at http://jusst.de/manu/stb0899-v4l-dvb.tar.bz2

The bridge specific locking code also i have included in the tuner
driver. In reality it should go all the way down to the bridge driver.
The driver doesn't actually do any real read/writes, but just provides
the placeholders for the same. All delivery systems(DVB)/standards(V4L)
are used in it. In real life one wouldn't have so many standards and
delivery systems (for illustrational purposes)


Awaiting comments

Manu

diff -Naurp stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/dvb-core/dvb_frontend.h stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
--- stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/dvb-core/dvb_frontend.h	2007-02-24 14:57:15.000000000 +0400
+++ stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/dvb-core/dvb_frontend.h	2007-04-09 19:34:31.000000000 +0400
@@ -209,6 +209,12 @@ struct dvb_tuner_ops {
 	 */
 	int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
 	int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+
+	/* These are specifically meant for hybrid tuners	*/
+	int (*state_lock)(struct dvb_frontend *fe, int lock);
+	int (*get_info)(struct dvb_frontend *fe, struct dvbfe_info *tuner_info);
+	void (*get_delsys)(struct dvb_frontend *fe, enum dvbfe_delsys *tuner_delsys);
+	int (*set_delsys)(struct dvb_frontend *fe, struct dvbfe_params *params);
 };
 
 struct dvb_frontend_ops {
diff -Naurp stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.c stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.c
--- stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.c	1970-01-01 04:00:00.000000000 +0400
+++ stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.c	2007-04-09 20:34:15.000000000 +0400
@@ -0,0 +1,788 @@
+/*
+	Dummy Hybrid Tuner driver for illustrational purposes
+
+	Copyright (C) Manu Abraham <abraham.manu@xxxxxxxxx>
+	Copyright (C) Christoph pfister <christophpfister@xxxxxxxxx>
+
+	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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/dvb/frontend.h>
+#include <media/tuner.h>
+#include "dvb_frontend.h"
+
+#include "dummy_hybrid_tuner.h"
+
+#define dprintk(args...)						\
+	do								\
+		if (debug)						\
+			printk(KERN_DEBUG "%s: \n", __func__, ##args);	\
+	while(0)
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+
+/* previously used params	*/
+struct dvb_tuner_params {
+	enum dvbfe_delsys 		delsys;
+	enum dvbfe_modulation		modulation;
+	enum dvbfe_bandwidth		bandwidth;
+	u32				frequency;
+};
+
+struct dummy_tuner {
+	struct dummy_tuner_config	*config;
+	struct i2c_adapter		*i2c;
+	struct dvb_frontend		*frontend;
+
+	struct dvb_tuner_params		dvb_params;
+
+	struct tuner			*v4l_tuner;
+	struct i2c_client		client;
+};
+
+/* NOTE! This probably needs to go out to an independant
+ * header, viz, hybrid_tuner.h
+ */
+enum fsm_state {
+	TUNER_MODE_NONE	= 0,
+	TUNER_MODE_DVB,
+	TUNER_MODE_V4L
+};
+
+/* bus_mode: will have the last subsystem that held the lock
+ * Helpful, to minimize one operation in a system's
+ * sub mode switch, in most cases.
+ * bus_lock: holds the bus locked state
+ */
+struct tuner_fsm_state {
+//	struct mutex	bus_lock;
+	spinlock_t	bus_lock;
+	u8		bus_mode;
+	int		lock_count;
+};
+
+/* NOTE! This goes in to the bridge driver
+ * This data structure holds the bridge specific info
+ */
+struct dummy_bridge {
+	struct i2c_adapter	i2c;
+	struct tuner_fsm_state	tuner_state;
+};
+
+/* NOTE! All locking to be done at the bridge level	*/
+static int tuner_dvb_state_lock(struct dummy_bridge *bridge)
+{
+	int ret;
+	unsigned long flags;
+	struct tuner_fsm_state *tuner_state = &bridge->tuner_state;
+
+	spin_lock_irqsave(&tuner_state->bus_lock, flags);
+	switch (tuner_state->bus_mode) {
+	case TUNER_MODE_NONE:
+		tuner_state->bus_mode = TUNER_MODE_DVB;
+		/* fall through	*/
+	case TUNER_MODE_DVB:
+		tuner_state->lock_count++;
+		ret = 0;
+		break;
+	default:
+		ret = -EBUSY;
+	}
+	spin_unlock_irqrestore(&tuner_state->bus_lock, flags);
+	
+	return ret;
+}
+
+static void tuner_dvb_state_unlock(struct dummy_bridge *bridge)
+{
+	unsigned long flags;
+	struct tuner_fsm_state *tuner_state = &bridge->tuner_state;
+
+	spin_lock_irqsave(&tuner_state->bus_lock, flags);
+	BUG_ON(tuner_state->bus_mode != TUNER_MODE_DVB);
+
+	if (--tuner_state->lock_count == 0)
+		tuner_state->bus_mode = TUNER_MODE_NONE;
+
+	spin_unlock_irqrestore(&tuner_state->bus_lock, flags);
+}
+
+static int tuner_dvb_state_ctl(struct dvb_frontend *fe, int control)
+{
+	int ret = 0;
+
+	struct dummy_bridge *bridge = fe->dvb->priv;
+
+	if (control)
+		ret = tuner_dvb_state_lock(bridge);
+	else
+		tuner_dvb_state_unlock(bridge);
+
+	return ret;
+}
+
+static int tuner_v4l_state_lock(struct dummy_bridge *bridge)
+{
+	int ret;
+	unsigned long flags;
+	struct tuner_fsm_state *tuner_state = &bridge->tuner_state;
+
+	spin_lock_irqsave(&tuner_state->bus_lock, flags);
+	switch (tuner_state->bus_mode) {
+	case TUNER_MODE_NONE:
+		tuner_state->bus_mode = TUNER_MODE_V4L;
+		/* fall through	*/
+	case TUNER_MODE_V4L:
+		tuner_state->lock_count++;
+		ret = 0;
+		break;
+	default:
+		ret = -EBUSY;
+	}
+	spin_unlock_irqrestore(&tuner_state->bus_lock, flags);
+	
+	return ret;
+}
+
+static void tuner_v4l_state_unlock(struct dummy_bridge *bridge)
+{
+	unsigned long flags;
+	struct tuner_fsm_state *tuner_state = &bridge->tuner_state;
+	
+	spin_lock_irqsave(&tuner_state->bus_lock, flags);
+	BUG_ON(tuner_state->bus_mode != TUNER_MODE_V4L);
+
+	if (--tuner_state->lock_count == 0)
+		tuner_state->bus_mode = TUNER_MODE_NONE;
+
+	spin_unlock_irqrestore(&tuner_state->bus_lock, flags);
+}
+
+static int tuner_v4l_state_ctl(struct i2c_client *client, int control)
+{
+	int ret = 0;
+	
+	struct i2c_adapter *adapter = client->adapter;
+	struct dummy_bridge *bridge = i2c_get_adapdata(adapter);
+	
+	if (control)
+		ret = tuner_v4l_state_lock(bridge);
+	else
+		tuner_v4l_state_unlock(bridge);
+
+	return ret;
+}
+
+#define UNLOCK	0
+#define LOCK	1
+
+/* This should go in as a callback to dvb_frontend.h	*/
+/* Currently all DVB delivery syatems are used for easier understanding
+ * Individual drivers needs to just use the modes that which they
+ * need to support. ie, this list is a complete list of all the
+ * supported DVB delivery systems.
+ */
+static int tuner_set_digital_delivery(struct dvb_frontend *fe,
+					struct dvbfe_params *params)
+{
+	enum dvbfe_delsys delivery;
+	struct dummy_tuner *state = fe->tuner_priv;
+	delivery = state->dvb_params.delsys;
+
+	if (!tuner_dvb_state_ctl(fe, LOCK)) {
+		state->dvb_params.frequency = params->frequency;
+		switch (delivery) {
+		case DVBFE_DELSYS_DVBS:
+			state->dvb_params.modulation = params->delsys.dvbs.modulation;
+			switch (params->delsys.dvbs.modulation) {
+			case DVBFE_MOD_BPSK:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QPSK:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			break;
+		case DVBFE_DELSYS_DSS:
+			state->dvb_params.modulation = params->delsys.dss.modulation;
+			switch (params->delsys.dss.modulation) {
+			case DVBFE_MOD_BPSK:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QPSK:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			break;
+		case DVBFE_DELSYS_DVBS2:
+			state->dvb_params.modulation = params->delsys.dvbs2.modulation;
+			switch (params->delsys.dvbs2.modulation) {
+			case DVBFE_MOD_QPSK:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_8PSK:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_16APSK:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_32APSK:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			break;
+		case DVBFE_DELSYS_DVBC:
+			state->dvb_params.modulation = params->delsys.dvbc.modulation;
+			switch (params->delsys.dvbc.modulation) {
+			case DVBFE_MOD_QAM4:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM16:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM32:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM64:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM128:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM256:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			break;
+		case DVBFE_DELSYS_DVBT:
+			state->dvb_params.modulation = params->delsys.dvbt.constellation;
+			switch (params->delsys.dvbt.constellation) {
+			case DVBFE_MOD_QPSK:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM16:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM64:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_OFDM:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			state->dvb_params.bandwidth = params->delsys.dvbt.bandwidth;
+			switch (params->delsys.dvbt.bandwidth) {
+			case DVBFE_BANDWIDTH_6_MHZ:
+				/* do something here	*/
+				break;
+			case DVBFE_BANDWIDTH_7_MHZ:
+				/* do something here	*/
+				break;
+			case DVBFE_BANDWIDTH_8_MHZ:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			break;
+		case DVBFE_DELSYS_DVBH:
+			state->dvb_params.modulation = params->delsys.dvbh.constellation;
+			switch (params->delsys.dvbh.constellation) {
+			case DVBFE_MOD_QPSK:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM16:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM64:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_OFDM:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			state->dvb_params.bandwidth = params->delsys.dvbh.bandwidth;
+			switch (params->delsys.dvbh.bandwidth) {
+			case DVBFE_BANDWIDTH_5_MHZ:
+				/* do something here	*/
+				break;
+			case DVBFE_BANDWIDTH_6_MHZ:
+				/* do something here	*/
+				break;
+			case DVBFE_BANDWIDTH_7_MHZ:
+				/* do something here	*/
+				break;
+			case DVBFE_BANDWIDTH_8_MHZ:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			break;
+		case DVBFE_DELSYS_ATSC:
+			state->dvb_params.modulation = params->delsys.atsc.modulation;
+			switch (params->delsys.atsc.modulation) {
+			case DVBFE_MOD_VSB8:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_VSB16:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM64:
+				/* do something here	*/
+				break;
+			case DVBFE_MOD_QAM256:
+				/* do something here	*/
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			printk("%s: Unsupported delivery system\n", __func__);
+			tuner_dvb_state_ctl(fe, UNLOCK);
+			return -EINVAL;
+		}
+
+		/* Dummy tuner accesses DVB params
+		 * through the i2c bus over here
+		 */
+		tuner_dvb_state_ctl(fe, UNLOCK);
+	} else {
+		printk("%s: Switch to Digital MODE FAILED! \n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* Currently all V4L2 standard are used for easier understanding
+ * Individual drivers needs to just use the modes that which they
+ * need to support. ie, this list is a complete list of all the
+ * supported V4L2 standards.
+ */
+static void tuner_v4l_set_tv_freq(struct i2c_client *client, unsigned int freq)
+{
+	struct tuner *v4l_tuner = i2c_get_clientdata(client);
+
+	if (!tuner_v4l_state_ctl(client, LOCK)) {
+		switch (v4l_tuner->std) {
+		case V4L2_STD_PAL:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_BG:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_DK:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_B:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_B1:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_G:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_H:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_I:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_D:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_D1:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_K:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_M:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_N:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_Nc:
+			/* do something here	*/
+			break;
+		case V4L2_STD_PAL_60:
+			/* do something here	*/
+			break;
+		case V4L2_STD_NTSC:
+			/* do something here	*/
+			break;
+		case V4L2_STD_NTSC_M:
+			/* do something here	*/
+			break;
+		case V4L2_STD_NTSC_M_JP:
+			/* do something here	*/
+			break;
+		case V4L2_STD_NTSC_443:
+			/* do something here	*/
+			break;
+		case V4L2_STD_NTSC_M_KR:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_DK:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_B:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_D:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_G:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_H:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_K:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_K1:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_L:
+			/* do something here	*/
+			break;
+		case V4L2_STD_SECAM_LC:
+			/* do something here	*/
+			break;
+		default:
+			printk("%s: Unsupported V4L2 Standard\n", __func__);
+			tuner_v4l_state_ctl(client, UNLOCK);
+			/* This comment should go away, for this all tuners
+			 * will need to have an int * instead of a void *
+			 * "temporarily only". This should be fixed to avoid
+			 * "double unlocking".
+			 */
+//			return -EINVAL;
+			return;
+		}
+		/* Dummy tuner accesses Analog TV frequency
+		 * through the i2c bus over here
+		 */
+		tuner_v4l_state_ctl(client, UNLOCK);
+	} else {
+		printk("%s: Switch to Analog TV MODE FAILED! \n", __func__);
+//		return -EIO;
+	}
+
+//	return 0;
+}
+
+static void tuner_v4l_set_radio_freq(struct i2c_client *client, unsigned int freq)
+{
+//	struct tuner *v4l_tuner = i2c_get_clientdata(client);
+//	struct i2c_adapter *adapter = client->adapter;
+
+	if (tuner_v4l_state_ctl(client, LOCK)) {
+		/* Dummy tuner accesses Analog Radio frequency
+		 * through the i2c bus over here
+		 */
+		tuner_v4l_state_ctl(client, UNLOCK);
+	} else {
+		printk("%s: Switch to Analog Radio MODE FAILED! \n", __func__);
+//		return -EIO;
+	}
+
+//	return 0;
+}
+
+static const struct dvbfe_info dvbs_info	= {
+	.name			= "Dummy Hybrid Tuner DVB-S",
+	.delivery		= DVBFE_DELSYS_DVBS,
+	.delsys			= {
+		.dvbs.modulation	= DVBFE_MOD_BPSK | DVBFE_MOD_QPSK,
+		.dvbs.fec		= DVBFE_FEC_NONE
+	},
+	.frequency_min		= 950000,
+	.frequency_max		= 2150000,
+	.frequency_step		= 0,
+	.symbol_rate_min	= 0,
+	.symbol_rate_max	= 45000000,
+	.symbol_rate_tolerance	= 0
+};
+
+static const struct dvbfe_info dss_info		= {
+	.name			= "Dummy Hybrid Tuner DSS",
+	.delivery		= DVBFE_DELSYS_DSS,
+	.delsys			= {
+		.dss.modulation		= DVBFE_MOD_BPSK | DVBFE_MOD_QPSK,
+		.dss.fec		= DVBFE_FEC_NONE
+	},
+	.frequency_min		= 950000,
+	.frequency_max		= 2150000,
+	.frequency_step		= 0,
+	.symbol_rate_min	= 0,
+	.symbol_rate_max	= 45000000,
+	.symbol_rate_tolerance	= 0
+};
+
+static const struct dvbfe_info dvbs2_info	= {
+	.name			= "Dummy Hybrid Tuner DVB-S2",
+	.delivery		= DVBFE_DELSYS_DVBS2,
+	.delsys			= {
+		.dvbs2.modulation	= DVBFE_MOD_QPSK | DVBFE_MOD_8PSK |
+					  DVBFE_MOD_16APSK | DVBFE_MOD_32APSK,
+		.dvbs2.fec		= DVBFE_FEC_NONE
+	},
+	.frequency_min		= 950000,
+	.frequency_max		= 2150000,
+	.frequency_step		= 0,
+	.symbol_rate_min	= 0,
+	.symbol_rate_max	= 45000000,
+	.symbol_rate_tolerance	= 0
+};
+
+static const struct dvbfe_info dvbc_info	= {
+	.name			= "Dummy Hybrid Tuner DVB-C",
+	.delivery		= DVBFE_DELSYS_DVBC,
+	.delsys			= {
+		.dvbc.modulation	= DVBFE_MOD_QAM4 | DVBFE_MOD_QAM16 |
+					  DVBFE_MOD_QAM32 | DVBFE_MOD_QAM64 |
+					  DVBFE_MOD_QAM128 | DVBFE_MOD_QAM256
+	},
+	.frequency_min		= 51000000,
+	.frequency_max		= 858000000,
+	.frequency_step		= 0,
+	.symbol_rate_min	= 0,
+	.symbol_rate_max	= 0,
+	.symbol_rate_tolerance	= 0
+};
+
+static const struct dvbfe_info dvbt_info	= {
+	.name			= "Dummy Hybrid Tuner DVB-T",
+	.delivery		= DVBFE_DELSYS_DVBT,
+	.delsys			= {
+		.dvbt.modulation	= DVBFE_MOD_QPSK | DVBFE_MOD_QAM16 |
+					  DVBFE_MOD_QAM64
+	},
+	.frequency_min		= 51000000,
+	.frequency_max		= 858000000,
+	.frequency_step		= 0,
+	.symbol_rate_min	= 0,
+	.symbol_rate_max	= 0,
+	.symbol_rate_tolerance	= 0
+};
+
+static const struct dvbfe_info dvbh_info	= {
+	.name			= "Dummy Hybrid Tuner DVB-H",
+	.delivery		= DVBFE_DELSYS_DVBT,
+	.delsys			= {
+		.dvbt.modulation	= DVBFE_MOD_QPSK | DVBFE_MOD_QAM16 |
+					  DVBFE_MOD_QAM64
+	},
+	.frequency_min		= 51000000,
+	.frequency_max		= 858000000,
+	.frequency_step		= 0,
+	.symbol_rate_min	= 0,
+	.symbol_rate_max	= 0,
+	.symbol_rate_tolerance	= 0
+};
+
+static const struct dvbfe_info atsc_info	= {
+	.name			= "Dummy Hybrid Tuner ATSC",
+	.delivery		= DVBFE_DELSYS_ATSC,
+	.delsys			= {
+		.atsc.modulation	= DVBFE_MOD_VSB8 | DVBFE_MOD_VSB16 |
+					  DVBFE_MOD_QAM64 | DVBFE_MOD_QAM256
+	},
+	.frequency_min		= 44000000,
+	.frequency_max		= 958000000,
+	.frequency_step		= 0,
+	.symbol_rate_min	= 0,
+	.symbol_rate_max	= 0,
+	.symbol_rate_tolerance	= 0
+};
+
+/* The relevant system needs to know what capabilities a multistandard device
+ * has in each mode. Initially, a system needs to request the tuner to provide
+ * the capabilities for a specific mode of operation. This request is also seen
+ * as a preliminary round for switching the mode of operation in the DVB mode
+ */
+static int tuner_dvb_get_info(struct dvb_frontend *fe, struct dvbfe_info *tuner_info)
+{
+	enum dvbfe_delsys delsys;
+	struct dummy_tuner *state = fe->tuner_priv;
+
+	delsys = tuner_info->delivery;
+	state->dvb_params.delsys = delsys;
+
+	switch (delsys) {
+	case DVBFE_DELSYS_DVBS:
+		memcpy(tuner_info, &dvbs_info, sizeof (struct dvbfe_info));
+		break;
+	case DVBFE_DELSYS_DSS:
+		memcpy(tuner_info, &dss_info, sizeof (struct dvbfe_info));
+		break;
+	case DVBFE_DELSYS_DVBS2:
+		memcpy(tuner_info, &dvbs2_info, sizeof (struct dvbfe_info));
+		break;
+	case DVBFE_DELSYS_DVBC:
+		memcpy(tuner_info, &dvbc_info, sizeof (struct dvbfe_info));
+		break;
+	case DVBFE_DELSYS_DVBT:
+		memcpy(tuner_info, &dvbt_info, sizeof (struct dvbfe_info));
+		break;
+	case DVBFE_DELSYS_DVBH:
+		memcpy(tuner_info, &dvbh_info, sizeof (struct dvbfe_info));
+		break;
+	case DVBFE_DELSYS_ATSC:
+		memcpy(tuner_info, &atsc_info, sizeof (struct dvbfe_info));
+		break;
+	default:
+		printk("%s: Unsupported delivery system\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void tuner_dvb_get_delsys(struct dvb_frontend *fe, enum dvbfe_delsys *tuner_delsys)
+{
+	*tuner_delsys = DVBFE_DELSYS_DVBS | DVBFE_DELSYS_DSS |
+			DVBFE_DELSYS_DVBS2 | DVBFE_DELSYS_DVBC |
+			DVBFE_DELSYS_DVBT | DVBFE_DELSYS_DVBH |
+			DVBFE_DELSYS_ATSC;
+}
+
+static struct dvb_tuner_ops dummy_dvb_tuner_ops = {
+	.info = {
+		.name		= "Dummy Hybrid Tuner",
+		.frequency_min	= 0,
+		.frequency_max	= 0,
+		.frequency_step	= 0,
+	},
+//	.init		= tuner_dvb_init,
+//	.sleep		= tuner_dvb_sleep,
+	.get_info	= tuner_dvb_get_info,
+	.get_delsys	= tuner_dvb_get_delsys,
+	.set_delsys	= tuner_set_digital_delivery,
+//	.get_status	= tuner_dvb_get_status,
+	.state_lock	= tuner_dvb_state_ctl, /* Hybrid control */
+//	.release	= tuner_dvb_release
+};
+
+#define DRIVER_NAME			"Dummy hybrid tuner"
+#define I2C_DRIVERID_DUMMY_HYBRID	0xff
+
+static struct i2c_driver dummy_driver = {
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+	.id		= I2C_DRIVERID_DUMMY_HYBRID
+};
+
+/* Attach and detach should be handled by the same entity
+ * for safety and consistency sake
+ */
+static struct i2c_client client_template = {
+	.name		= DRIVER_NAME,
+	.driver		= &dummy_driver,
+};
+
+/* NOTE!
+ * Almost all tuners are behind a secondary bus behind a digital demodulator.
+ * Access to this bus is controlled by the demodulator itself by the means of a
+ * control with the demodulator. viz, i2c_gate_ctrl. A hybrid device (in Analog
+ * mode) should never try to enable/disable the i2c_gate_ctrl, ie the gate
+ * control is private to the demodulator. Since the demodulator only has access
+ * to this secondary bus, initialization is handled in a better manner by the
+ * digital mode. ie, dvb-core
+ */
+struct dvb_tuner_ops *dummy_tuner_attach(struct dvb_frontend *fe,
+						struct dvb_tuner_ops *tuner_ops,
+						struct dummy_tuner_config *config,
+						struct i2c_adapter *i2c)
+{
+	int err = 0;
+
+	struct dummy_tuner *state;
+	struct tuner *v4l_tuner;
+	struct i2c_client *client;
+
+	if ((state = kzalloc(sizeof (struct dummy_tuner), GFP_KERNEL)) == NULL)
+		goto err1;
+
+	client = &state->client;
+	memcpy(client, &client_template, sizeof (struct i2c_client));
+	client->adapter = i2c;
+	client->addr = config->tuner_addr;
+
+	if ((err = i2c_attach_client(client)) != 0) {
+		kfree(client);
+		return NULL;
+	}
+
+	v4l_tuner = i2c_get_clientdata(client);
+
+	v4l_tuner->set_tv_freq		= tuner_v4l_set_tv_freq;
+ 	v4l_tuner->set_radio_freq	= tuner_v4l_set_radio_freq;
+// 	v4l_tuner->has_signal		= tuner_v4l_has_signal;
+// 	v4l_tuner->is_stereo		= tuner_v4l_is_stereo;
+// 	v4l_tuner->get_afc		= tuner_v4l_get_afc;
+// 	v4l_tuner->tuner_status		= tuner_v4l_status;
+// 	v4l_tuner->standby		= tuner_v4l_standby;
+ 	v4l_tuner->state_lock		= tuner_v4l_state_ctl; /* Hybrid control */
+	state->v4l_tuner		= v4l_tuner;
+	state->config 			= config;
+	state->i2c			= i2c;
+	state->frontend			= fe;
+	fe->tuner_priv			= state;
+	fe->ops.tuner_ops		= dummy_dvb_tuner_ops;
+
+	printk("%s: Attaching .. \n", __func__);
+	return &fe->ops.tuner_ops;
+
+err1:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(dummy_tuner_attach);
+
+MODULE_PARM_DESC(verbose, "Debug");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("dummy hybrid tuner");
+MODULE_LICENSE("GPL");
diff -Naurp stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.h stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.h
--- stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.h	1970-01-01 04:00:00.000000000 +0400
+++ stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/dummy_hybrid_tuner.h	2007-04-09 02:18:03.000000000 +0400
@@ -0,0 +1,9 @@
+#ifndef __DUMMY_HYBRID_TUNER_H
+#define __DUMMY_HYBRID_TUNER_H
+
+struct dummy_tuner_config {
+	u8 tuner_addr;
+};
+
+#endif
+
diff -Naurp stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig
--- stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig	2007-02-24 15:29:21.000000000 +0400
+++ stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig	2007-04-09 20:30:03.000000000 +0400
@@ -353,4 +353,12 @@ config DVB_TUA6100
 	help
 	  A DVBS PLL chip.
 
+config DVB_TUNER_HYBRID_DUMMY
+	tristate "DUMMY HYBRID"
+	depends on DVB_CORE && I2C
+	select VIDEO_TUNER
+	default m
+	help
+	    A hybrid dummy DVB tuner module for illustrational purposes
+
 endmenu
diff -Naurp stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/Makefile stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/Makefile
--- stb0899-v4l-dvb.orig/v4l-dvb/linux/drivers/media/dvb/frontends/Makefile	2007-02-24 15:29:43.000000000 +0400
+++ stb0899-v4l-dvb/v4l-dvb/linux/drivers/media/dvb/frontends/Makefile	2007-04-09 00:13:44.000000000 +0400
@@ -44,3 +44,4 @@ obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060
 obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
+obj-$(CONFIG_DVB_TUNER_HYBRID_DUMMY) += dummy_hybrid_tuner.o
diff -Naurp stb0899-v4l-dvb.orig/v4l-dvb/linux/include/media/tuner.h stb0899-v4l-dvb/v4l-dvb/linux/include/media/tuner.h
--- stb0899-v4l-dvb.orig/v4l-dvb/linux/include/media/tuner.h	2007-02-22 17:20:10.000000000 +0400
+++ stb0899-v4l-dvb/v4l-dvb/linux/include/media/tuner.h	2007-04-09 19:34:53.000000000 +0400
@@ -219,6 +219,8 @@ struct tuner {
 	int  (*get_afc)(struct i2c_client *c);
 	void (*tuner_status)(struct i2c_client *c);
 	void (*standby)(struct i2c_client *c);
+	
+	int (*state_lock)(struct i2c_client *c, int lock);
 };
 
 extern unsigned const int tuner_count;
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux