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