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 <[EMAIL PROTECTED]>
+ Copyright (C) Christoph pfister <[EMAIL PROTECTED]>
+
+ 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
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb