Commit 363c35fc authored by Steven Toth's avatar Steven Toth Committed by Mauro Carvalho Chehab

V4L/DVB (9222): S2API: Add Multiple-frontend on a single adapter support.

A detailed description from the original patches 2 years ago:

"The WinTV-HVR3000 has a single transport bus which is shared between
a DVB-T and DVB-S modulator. These patches build on the bus acquisition
cx88 work from a few weeks ago to add support for this.

So to applications the HVR3000 looks like this:
/dev/dvb/adapter0/fe0 (cx24123 DVB-S demod)
/dev/dvb/adapter0/fe1 (cx22702 DVB-T demod)

Additional boards continue as before, eg:
/dev/dvb/adapter1/fe0 (lgdt3302 ATSC demod)

The basic change is removing the single instance of the videobuf_dvb in
cx8802_dev and saa7134_dev(?) and replacing it with a list and some
supporting functions.

*NOTE* This branch was taken before v4l-dvb was closed for 2.6.19 so
two or three current cx88 patches appear to be reversed by this tree,
this will be cleaned up in the near future. The patches missing change
the mutex handing to core->lock, fix an enumeration problem."

It should be recognised that a number of people have been maintaining
this patchset. Significant levels of Kudos to everyone one involved,
including but not limited to:

Darron Broad
Fabio M. Di Nitto
Carlo Scarfoglio
Hans Werner

Without the work of these people, and countless others, my two year old
patches would of died on the Mercurial linuxtv.org vine a long time
ago.

TODO: Revise these patches a little further so that the need for
demux1 and dvr0 is optional, not mandatory on the HVR3000.

HISTORY (darron):
This is the last update to MFE prepared by Hans which is based
upon the `scratchpad' diff created by Carlo.
All MFE work prior to that point must be attributed to Fabio
who ported and maintained Steve's original patch up to that
time.
Signed-off-by: default avatarSteven Toth <stoth@linuxtv.org>
Signed-off-by: default avatarDarron Broad <darron@kewl.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 548da762
......@@ -212,8 +212,9 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
static void dvb_frontend_init(struct dvb_frontend *fe)
{
dprintk ("DVB: initialising frontend %i (%s)...\n",
dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
fe->dvb->num,
fe->id,
fe->ops.info.name);
if (fe->ops.init)
......@@ -686,7 +687,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
mb();
fe_thread = kthread_run(dvb_frontend_thread, fe,
"kdvb-fe-%i", fe->dvb->num);
"kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
if (IS_ERR(fe_thread)) {
ret = PTR_ERR(fe_thread);
printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
......@@ -710,8 +711,8 @@ static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
if (*freq_min == 0 || *freq_max == 0)
printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
fe->dvb->num);
printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
fe->dvb->num,fe->id);
}
static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
......@@ -724,8 +725,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
if ((freq_min && parms->frequency < freq_min) ||
(freq_max && parms->frequency > freq_max)) {
printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
fe->dvb->num, parms->frequency, freq_min, freq_max);
printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
return -EINVAL;
}
......@@ -735,8 +736,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
(fe->ops.info.symbol_rate_max &&
parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
fe->dvb->num, parms->u.qpsk.symbol_rate,
printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
return -EINVAL;
}
......@@ -746,8 +747,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
(fe->ops.info.symbol_rate_max &&
parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
fe->dvb->num, parms->u.qam.symbol_rate,
printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
return -EINVAL;
}
......@@ -1807,8 +1808,9 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
printk ("DVB: registering frontend %i (%s)...\n",
printk ("DVB: registering adapter %i frontend %i (%s)...\n",
fe->dvb->num,
fe->id,
fe->ops.info.name);
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
......
......@@ -222,6 +222,7 @@ struct dvb_frontend {
struct dtv_frontend_properties dtv_property_cache;
#define DVB_FRONTEND_COMPONENT_TUNER 0
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id;
};
extern int dvb_register_frontend(struct dvb_adapter *dvb,
......
......@@ -312,48 +312,53 @@ static int dvb_register(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
struct cx23885_i2c *i2c_bus = NULL;
struct videobuf_dvb_frontend *fe0;
fe0 = videobuf_dvb_get_frontend(&port->frontends, 0);
if (!fe0)
return -EINVAL;
/* init struct videobuf_dvb */
port->dvb.name = dev->name;
fe0->dvb.name = dev->name;
/* init frontend */
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1250:
i2c_bus = &dev->i2c_bus[0];
port->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_generic_config,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
dvb_attach(mt2131_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
dvb_attach(mt2131_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_generic_tunerconfig, 0);
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1800:
i2c_bus = &dev->i2c_bus[0];
switch (alt_tuner) {
switch (alt_tuner) { // XXXXXX multifrontend?
case 1:
port->dvb.frontend =
fe0->dvb.frontend =
dvb_attach(s5h1409_attach,
&hauppauge_ezqam_config,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
dvb_attach(tda829x_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
dvb_attach(tda829x_attach, fe0->dvb.frontend,
&dev->i2c_bus[1].i2c_adap, 0x42,
&tda829x_no_probe);
dvb_attach(tda18271_attach, port->dvb.frontend,
dvb_attach(tda18271_attach, fe0->dvb.frontend,
0x60, &dev->i2c_bus[1].i2c_adap,
&hauppauge_tda18271_config);
}
break;
case 0:
default:
port->dvb.frontend =
fe0->dvb.frontend =
dvb_attach(s5h1409_attach,
&hauppauge_generic_config,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL)
dvb_attach(mt2131_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL)
dvb_attach(mt2131_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_generic_tunerconfig, 0);
break;
......@@ -361,42 +366,42 @@ static int dvb_register(struct cx23885_tsport *port)
break;
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
i2c_bus = &dev->i2c_bus[0];
port->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1800lp_config,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
dvb_attach(mt2131_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
dvb_attach(mt2131_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_generic_tunerconfig, 0);
}
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
i2c_bus = &dev->i2c_bus[0];
port->dvb.frontend = dvb_attach(lgdt330x_attach,
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_5_express,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
dvb_attach(simple_tuner_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap, 0x61,
TUNER_LG_TDVS_H06XF);
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
i2c_bus = &dev->i2c_bus[1];
port->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1500q_config,
&dev->i2c_bus[0].i2c_adap);
if (port->dvb.frontend != NULL)
dvb_attach(xc5000_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL)
dvb_attach(xc5000_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&hauppauge_hvr1500q_tunerconfig);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500:
i2c_bus = &dev->i2c_bus[1];
port->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1500_config,
&dev->i2c_bus[0].i2c_adap);
if (port->dvb.frontend != NULL) {
if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &i2c_bus->i2c_adap,
......@@ -409,7 +414,7 @@ static int dvb_register(struct cx23885_tsport *port)
};
fe = dvb_attach(xc2028_attach,
port->dvb.frontend, &cfg);
fe0->dvb.frontend, &cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
......@@ -417,24 +422,24 @@ static int dvb_register(struct cx23885_tsport *port)
case CX23885_BOARD_HAUPPAUGE_HVR1200:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
i2c_bus = &dev->i2c_bus[0];
port->dvb.frontend = dvb_attach(tda10048_attach,
fe0->dvb.frontend = dvb_attach(tda10048_attach,
&hauppauge_hvr1200_config,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
dvb_attach(tda829x_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
dvb_attach(tda829x_attach, fe0->dvb.frontend,
&dev->i2c_bus[1].i2c_adap, 0x42,
&tda829x_no_probe);
dvb_attach(tda18271_attach, port->dvb.frontend,
dvb_attach(tda18271_attach, fe0->dvb.frontend,
0x60, &dev->i2c_bus[1].i2c_adap,
&hauppauge_hvr1200_tuner_config);
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1400:
i2c_bus = &dev->i2c_bus[0];
port->dvb.frontend = dvb_attach(dib7000p_attach,
fe0->dvb.frontend = dvb_attach(dib7000p_attach,
&i2c_bus->i2c_adap,
0x12, &hauppauge_hvr1400_dib7000_config);
if (port->dvb.frontend != NULL) {
if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &dev->i2c_bus[1].i2c_adap,
......@@ -449,7 +454,7 @@ static int dvb_register(struct cx23885_tsport *port)
};
fe = dvb_attach(xc2028_attach,
port->dvb.frontend, &cfg);
fe0->dvb.frontend, &cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
......@@ -457,25 +462,25 @@ static int dvb_register(struct cx23885_tsport *port)
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
i2c_bus = &dev->i2c_bus[port->nr - 1];
port->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&dvico_s5h1409_config,
&i2c_bus->i2c_adap);
if (port->dvb.frontend == NULL)
port->dvb.frontend = dvb_attach(s5h1411_attach,
if (fe0->dvb.frontend == NULL)
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&dvico_s5h1411_config,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL)
dvb_attach(xc5000_attach, port->dvb.frontend,
if (fe0->dvb.frontend != NULL)
dvb_attach(xc5000_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&dvico_xc5000_tunerconfig);
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
i2c_bus = &dev->i2c_bus[port->nr - 1];
port->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &i2c_bus->i2c_adap,
......@@ -487,7 +492,7 @@ static int dvb_register(struct cx23885_tsport *port)
.demod = XC3028_FE_ZARLINK456,
};
fe = dvb_attach(xc2028_attach, port->dvb.frontend,
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
&cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
......@@ -497,10 +502,10 @@ static int dvb_register(struct cx23885_tsport *port)
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
i2c_bus = &dev->i2c_bus[0];
port->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &dev->i2c_bus[1].i2c_adap,
......@@ -512,7 +517,7 @@ static int dvb_register(struct cx23885_tsport *port)
.demod = XC3028_FE_ZARLINK456,
};
fe = dvb_attach(xc2028_attach, port->dvb.frontend,
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
&cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
......@@ -523,29 +528,36 @@ static int dvb_register(struct cx23885_tsport *port)
dev->name);
break;
}
if (NULL == port->dvb.frontend) {
if (NULL == fe0->dvb.frontend) {
printk("%s: frontend initialization failed\n", dev->name);
return -1;
}
/* define general-purpose callback pointer */
port->dvb.frontend->callback = cx23885_tuner_callback;
fe0->dvb.frontend->callback = cx23885_tuner_callback;
/* Put the analog decoder in standby to keep it quiet */
cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
if (port->dvb.frontend->ops.analog_ops.standby)
port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
if (fe0->dvb.frontend->ops.analog_ops.standby)
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
/* register everything */
return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr);
}
int cx23885_dvb_register(struct cx23885_tsport *port)
{
struct videobuf_dvb_frontend *fe0;
struct cx23885_dev *dev = port->dev;
int err;
fe0 = videobuf_dvb_get_frontend(&port->frontends, 0);
if (!fe0)
err = -EINVAL;
dprintk(1, "%s\n", __func__);
dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
dev->board,
......@@ -557,7 +569,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
/* dvb stuff */
printk("%s: cx23885 based dvb card\n", dev->name);
videobuf_queue_sg_init(&port->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock,
videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
sizeof(struct cx23885_buffer), port);
err = dvb_register(port);
......@@ -569,9 +581,12 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
int cx23885_dvb_unregister(struct cx23885_tsport *port)
{
struct videobuf_dvb_frontend *fe0;
fe0 = videobuf_dvb_get_frontend(&port->frontends, 0);
/* dvb */
if(port->dvb.frontend)
videobuf_dvb_unregister(&port->dvb);
if(fe0->dvb.frontend)
videobuf_dvb_unregister_bus(&port->frontends);
return 0;
}
......
......@@ -225,7 +225,7 @@ struct cx23885_tsport {
int nr;
int sram_chno;
struct videobuf_dvb dvb;
struct videobuf_dvb_frontends frontends;
/* dma queues */
struct cx23885_dmaqueue mpegq;
......
......@@ -1291,6 +1291,7 @@ static const struct cx88_board cx88_boards[] = {
.gpio0 = 0x84bf,
}},
.mpeg = CX88_MPEG_DVB,
.num_frontends = 2,
},
[CX88_BOARD_NORWOOD_MICRO] = {
.name = "Norwood Micro TV Tuner",
......@@ -1761,6 +1762,7 @@ static const struct cx88_board cx88_boards[] = {
} },
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB,
.num_frontends = 2,
},
[CX88_BOARD_HAUPPAUGE_HVR4000LITE] = {
.name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2",
......@@ -3002,12 +3004,17 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
cx88_card_list(core, pci);
}
memset(&core->board, 0, sizeof(core->board));
memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
if (!core->board.num_frontends)
core->board.num_frontends=1;
info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n",
pci->subsystem_vendor, pci->subsystem_device, core->board.name,
core->boardnr, card[core->nr] == core->boardnr ?
"insmod option" : "autodetected");
"insmod option" : "autodetected",
core->board.num_frontends);
if (tuner[core->nr] != UNSET)
core->board.tuner_type = tuner[core->nr];
......
......@@ -116,13 +116,24 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
struct cx8802_dev *dev= fe->dvb->priv;
struct cx8802_driver *drv = NULL;
int ret = 0;
int fe_id;
fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
if (!fe_id) {
printk(KERN_ERR "%s() No frontend found\n", __FUNCTION__);
return -EINVAL;
}
drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
if (drv) {
if (acquire)
if (acquire){
dev->frontends.active_fe_id = fe_id;
ret = drv->request_acquire(drv);
else
} else {
ret = drv->request_release(drv);
dev->frontends.active_fe_id = 0;
}
}
return ret;
......@@ -483,6 +494,7 @@ static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
{
struct dvb_frontend *fe;
struct videobuf_dvb_frontend *fe0 = NULL;
struct xc2028_ctrl ctl;
struct xc2028_config cfg = {
.i2c_adap = &dev->core->i2c_adap,
......@@ -490,7 +502,12 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
.ctrl = &ctl,
};
if (!dev->dvb.frontend) {
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
if (!fe0->dvb.frontend) {
printk(KERN_ERR "%s/2: dvb frontend not attached. "
"Can't attach xc3028\n",
dev->core->name);
......@@ -504,10 +521,13 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
*/
cx88_setup_xc3028(dev->core, &ctl);
fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->core->name);
dvb_frontend_detach(fe0->dvb.frontend);
dvb_unregister_frontend(fe0->dvb.frontend);
fe0->dvb.frontend = NULL;
return -EINVAL;
}
......@@ -532,8 +552,10 @@ static int cx24116_reset_device(struct dvb_frontend *fe)
struct cx88_core *core = dev->core;
/* Reset the part */
/* Put the cx24116 into reset */
cx_write(MO_SRST_IO, 0);
msleep(10);
/* Take the cx24116 out of reset */
cx_write(MO_SRST_IO, 1);
msleep(10);
......@@ -573,20 +595,28 @@ static struct stv0288_config tevii_tuner_earda_config = {
static int dvb_register(struct cx8802_dev *dev)
{
//struct cx88_core *core = dev->core;
///* init struct videobuf_dvb */
//fe->dvb.name = core->name;
//dev->ts_gen_cntrl = 0x0c;
struct cx88_core *core = dev->core;
struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
/* init struct videobuf_dvb */
dev->dvb.name = core->name;
dev->ts_gen_cntrl = 0x0c;
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
/* init frontend */
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = dvb_attach(cx22702_attach,
fe0->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, &core->i2c_adap,
DVB_PLL_THOMSON_DTT759X))
goto frontend_detach;
......@@ -596,11 +626,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_CONEXANT_DVB_T1:
case CX88_BOARD_KWORLD_DVB_T_CX22702:
case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = dvb_attach(cx22702_attach,
fe0->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x60, &core->i2c_adap,
DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
......@@ -610,33 +640,65 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
case CX88_BOARD_HAUPPAUGE_HVR1300:
case CX88_BOARD_HAUPPAUGE_HVR3000:
dev->dvb.frontend = dvb_attach(cx22702_attach,
fe0->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3))
goto frontend_detach;
}
break;
case CX88_BOARD_HAUPPAUGE_HVR3000:
/* DVB-S init */
fe0->dvb.frontend = dvb_attach(cx24123_attach,
&hauppauge_novas_config,
&dev->core->i2c_adap);
if (fe0->dvb.frontend) {
if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
&dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
dprintk( 1, "%s(): HVR3000 - DVB-S LNB Init: failed\n", __FUNCTION__);
}
} else {
dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __FUNCTION__);
}
/* DVB-T init */
fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
if (fe1) {
fe1->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config,
&dev->core->i2c_adap);
if (fe1->dvb.frontend) {
fe1->dvb.frontend->id = 1;
if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
&dev->core->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3)) {
dprintk( 1, "%s(): HVR3000 - DVB-T misc Init: failed\n", __FUNCTION__);
}
} else {
dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __FUNCTION__);
}
} else {
dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __FUNCTION__);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
dev->dvb.frontend = dvb_attach(mt352_attach,
fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x60, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x60, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
}
......@@ -644,31 +706,31 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
/* The tin box says DEE1601, but it seems to be DTT7579
* compatible, with a slightly different MT352 AGC gain. */
dev->dvb.frontend = dvb_attach(mt352_attach,
fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_dual,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_THOMSON_DTT7579))
goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
dev->dvb.frontend = dvb_attach(mt352_attach,
fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_LG_Z201))
goto frontend_detach;
}
......@@ -676,11 +738,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_ADSTECH_DVB_T_PCI:
dev->dvb.frontend = dvb_attach(mt352_attach,
fe0->dvb.frontend = dvb_attach(mt352_attach,
&dntv_live_dvbt_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
0x61, NULL, DVB_PLL_UNKNOWN_1))
goto frontend_detach;
}
......@@ -688,10 +750,10 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
/* MT352 is on a secondary I2C bus made from some GPIO lines */
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&dev->vp3054->adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3))
goto frontend_detach;
......@@ -702,22 +764,22 @@ static int dvb_register(struct cx8802_dev *dev)
#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
dev->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_hybrid,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_THOMSON_FE6600))
goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
dev->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
&core->i2c_adap);
if (dev->dvb.frontend == NULL)
dev->dvb.frontend = dvb_attach(mt352_attach,
if (fe0->dvb.frontend == NULL)
fe0->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_mt352_xc3028,
&core->i2c_adap);
/*
......@@ -725,16 +787,16 @@ static int dvb_register(struct cx8802_dev *dev)
* We must not permit gate_ctrl to be performed, or
* the xc3028 cannot communicate on the bus.
*/
if (dev->dvb.frontend)
dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
if (fe0->dvb.frontend)
fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
if (attach_xc3028(0x61, dev) < 0)
return -EINVAL;
break;
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_THOMSON_DTT761X))
goto frontend_detach;
......@@ -751,11 +813,11 @@ static int dvb_register(struct cx8802_dev *dev)
/* Select RF connector callback */
fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_MICROTUNE_4042FI5))
goto frontend_detach;
......@@ -769,11 +831,11 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 9);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_THOMSON_DTT761X))
goto frontend_detach;
......@@ -787,15 +849,15 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_5_gold,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_LG_TDVS_H06XF))
goto frontend_detach;
if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x43))
goto frontend_detach;
}
......@@ -808,25 +870,25 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&pchdtv_hd5500,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_LG_TDVS_H06XF))
goto frontend_detach;
if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x43))
goto frontend_detach;
}
break;
case CX88_BOARD_ATI_HDTVWONDER:
dev->dvb.frontend = dvb_attach(nxt200x_attach,
fe0->dvb.frontend = dvb_attach(nxt200x_attach,
&ati_hdtvwonder,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x61,
TUNER_PHILIPS_TUV1236D))
goto frontend_detach;
......@@ -834,49 +896,49 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
dev->dvb.frontend = dvb_attach(cx24123_attach,
fe0->dvb.frontend = dvb_attach(cx24123_attach,
&hauppauge_novas_config,
&core->i2c_adap);
if (dev->dvb.frontend) {
if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
if (fe0->dvb.frontend) {
if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
&core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
goto frontend_detach;
}
break;
case CX88_BOARD_KWORLD_DVBS_100:
dev->dvb.frontend = dvb_attach(cx24123_attach,
fe0->dvb.frontend = dvb_attach(cx24123_attach,
&kworld_dvbs_100_config,
&core->i2c_adap);
if (dev->dvb.frontend) {
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
if (fe0->dvb.frontend) {
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
}
break;
case CX88_BOARD_GENIATECH_DVBS:
dev->dvb.frontend = dvb_attach(cx24123_attach,
fe0->dvb.frontend = dvb_attach(cx24123_attach,
&geniatech_dvbs_config,
&core->i2c_adap);
if (dev->dvb.frontend) {
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
if (fe0->dvb.frontend) {
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
}
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&pinnacle_pctv_hd_800i_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
&core->i2c_adap,
&pinnacle_pctv_hd_800i_tuner_config))
goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&dvico_hdtv5_pci_nano_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
.i2c_adap = &core->i2c_adap,
......@@ -889,17 +951,17 @@ static int dvb_register(struct cx8802_dev *dev)
};
fe = dvb_attach(xc2028_attach,
dev->dvb.frontend, &cfg);
fe0->dvb.frontend, &cfg);
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
break;
case CX88_BOARD_PINNACLE_HYBRID_PCTV:
dev->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_pinnacle_hybrid_pctv,
&core->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
if (fe0->dvb.frontend) {
fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
if (attach_xc3028(0x61, dev) < 0)
goto frontend_detach;
}
......@@ -907,85 +969,116 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_GENIATECH_X8000_MT:
dev->ts_gen_cntrl = 0x00;
dev->dvb.frontend = dvb_attach(zl10353_attach,
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_geniatech_x8000_mt,
&core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
goto frontend_detach;
break;
case CX88_BOARD_KWORLD_ATSC_120:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&kworld_atsc_120_config,
&core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
goto frontend_detach;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
dev->dvb.frontend = dvb_attach(s5h1411_attach,
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&dvico_fusionhdtv7_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
&core->i2c_adap,
&dvico_fusionhdtv7_tuner_config))
goto frontend_detach;
}
break;
case CX88_BOARD_HAUPPAUGE_HVR4000:
/* DVB-S/S2 Init */
fe0->dvb.frontend = dvb_attach(cx24116_attach,
&hauppauge_hvr4000_config,
&dev->core->i2c_adap);
if (fe0->dvb.frontend) {
if(!dvb_attach(isl6421_attach, fe0->dvb.frontend,
&dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
dprintk( 1, "%s(): HVR4000 - DVB-S LNB Init: failed\n", __FUNCTION__);
}
} else {
dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __FUNCTION__);
}
/* DVB-T Init */
fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
if (fe1) {
fe1->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config,
&dev->core->i2c_adap);
if (fe1->dvb.frontend) {
fe1->dvb.frontend->id = 1;
if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
&dev->core->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3)) {
dprintk( 1, "%s(): HVR4000 - DVB-T misc Init: failed\n", __FUNCTION__);
}
} else {
dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __FUNCTION__);
}
} else {
dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __FUNCTION__);
}
break;
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
/* Support for DVB-S only, not DVB-T support */
dev->dvb.frontend = dvb_attach(cx24116_attach,
fe0->dvb.frontend = dvb_attach(cx24116_attach,
&hauppauge_hvr4000_config,
&dev->core->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(isl6421_attach, dev->dvb.frontend,
if (fe0->dvb.frontend) {
dvb_attach(isl6421_attach, fe0->dvb.frontend,
&dev->core->i2c_adap,
0x08, ISL6421_DCL, 0x00);
}
break;
case CX88_BOARD_TEVII_S420:
dev->dvb.frontend = dvb_attach(stv0299_attach,
fe0->dvb.frontend = dvb_attach(stv0299_attach,
&tevii_tuner_sharp_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
&core->i2c_adap, DVB_PLL_OPERA1))
goto frontend_detach;
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
} else {
dev->dvb.frontend = dvb_attach(stv0288_attach,
fe0->dvb.frontend = dvb_attach(stv0288_attach,
&tevii_tuner_earda_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
if (!dvb_attach(stb6000_attach, dev->dvb.frontend, 0x61,
if (fe0->dvb.frontend != NULL) {
if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
&core->i2c_adap))
goto frontend_detach;
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
}
}
break;
case CX88_BOARD_TEVII_S460:
dev->dvb.frontend = dvb_attach(cx24116_attach,
fe0->dvb.frontend = dvb_attach(cx24116_attach,
&tevii_s460_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
if (fe0->dvb.frontend != NULL) {
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
}
break;
case CX88_BOARD_OMICOM_SS4_PCI:
case CX88_BOARD_TBS_8920:
case CX88_BOARD_PROF_7300:
dev->dvb.frontend = dvb_attach(cx24116_attach,
fe0->dvb.frontend = dvb_attach(cx24116_attach,
&hauppauge_hvr4000_config,
&core->i2c_adap);
if (dev->dvb.frontend != NULL) {
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
if (fe0->dvb.frontend != NULL) {
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
}
break;
default:
......@@ -993,29 +1086,32 @@ static int dvb_register(struct cx8802_dev *dev)
core->name);
break;
}
if (NULL == dev->dvb.frontend) {
if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
printk(KERN_ERR
"%s/2: frontend initialization failed\n",
core->name);
return -EINVAL;
}
/* define general-purpose callback pointer */
dev->dvb.frontend->callback = cx88_tuner_callback;
fe0->dvb.frontend->callback = cx88_tuner_callback;
/* Ensure all frontends negotiate bus access */
dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
if (fe1)
fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
/* Put the analog decoder in standby to keep it quiet */
cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
/* register everything */
return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
&dev->pci->dev, adapter_nr);
frontend_detach:
if (dev->dvb.frontend) {
dvb_frontend_detach(dev->dvb.frontend);
dev->dvb.frontend = NULL;
if (fe0->dvb.frontend) {
dvb_frontend_detach(fe0->dvb.frontend);
fe0->dvb.frontend = NULL;
}
return -EINVAL;
}
......@@ -1039,6 +1135,66 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
cx_clear(MO_GP0_IO, 0x00000004);
udelay(1000);
break;
case CX88_BOARD_HAUPPAUGE_HVR3000: /* ? */
if(core->dvbdev->frontends.active_fe_id == 1) {
/* DVB-S/S2 Enabled */
/* Toggle reset on cx22702 leaving i2c active */
cx_write(MO_GP0_IO, core->board.input[0].gpio0);
udelay(1000);
cx_clear(MO_GP0_IO, 0x00000080);
udelay(50);
cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */
cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */
udelay(1000);
cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */
core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
} else
if (core->dvbdev->frontends.active_fe_id == 2) {
/* DVB-T Enabled */
/* Put the cx24116/cx24123 into reset */
cx_write(MO_SRST_IO, 0);
/* cx22702 out of reset and enable it */
cx_set(MO_GP0_IO, 0x00000080);
cx_clear(MO_GP0_IO, 0x00000004);
core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
udelay(1000);
}
break;
case CX88_BOARD_HAUPPAUGE_HVR4000:
if(core->dvbdev->frontends.active_fe_id == 1) {
/* DVB-S/S2 Enabled */
/* Toggle reset on cx22702 leaving i2c active */
cx_write(MO_GP0_IO, (core->board.input[0].gpio0 & 0x0000ff00) | 0x00000080);
udelay(1000);
cx_clear(MO_GP0_IO, 0x00000080);
udelay(50);
cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */
cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */
udelay(1000);
cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */
core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
} else
if (core->dvbdev->frontends.active_fe_id == 2) {
/* DVB-T Enabled */
/* Put the cx24116/cx24123 into reset */
cx_write(MO_SRST_IO, 0);
/* cx22702 out of reset and enable it */
cx_set(MO_GP0_IO, 0x00000080);
cx_clear(MO_GP0_IO, 0x00000004);
core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
udelay(1000);
}
break;
default:
err = -ENODEV;
}
......@@ -1056,6 +1212,9 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Do Nothing, leave the cx22702 on the bus. */
break;
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR4000:
break;
default:
err = -ENODEV;
}
......@@ -1066,7 +1225,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
struct cx8802_dev *dev = drv->core->dvbdev;
int err;
int err,i;
struct videobuf_dvb_frontend *fe;
dprintk( 1, "%s\n", __func__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
......@@ -1086,12 +1246,23 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
/* dvb stuff */
printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
videobuf_queue_sg_init(&dev->dvb.dvbq, &dvb_qops,
dev->ts_gen_cntrl = 0x0c;
for (i = 1; i <= core->board.num_frontends; i++) {
fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
if (!fe) {
printk(KERN_ERR "%s() failed to get frontend(%d)\n", __FUNCTION__, i);
continue;
}
videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_TOP,
sizeof(struct cx88_buffer),
dev);
/* init struct videobuf_dvb */
fe->dvb.name = dev->core->name;
}
err = dvb_register(dev);
if (err != 0)
printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
......@@ -1105,9 +1276,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
{
struct cx8802_dev *dev = drv->core->dvbdev;
/* dvb */
if (dev->dvb.frontend)
videobuf_dvb_unregister(&dev->dvb);
videobuf_dvb_unregister_bus(&dev->frontends);
vp3054_i2c_remove(dev);
......
......@@ -116,18 +116,23 @@ static int detach_inform(struct i2c_client *client)
void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
{
struct videobuf_dvb_frontend *fe0 = NULL;
if (0 != core->i2c_rc)
return;
#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
if (core->dvbdev) {
/* Get the first frontend and assume that all I2C is routed through it */
/* TODO: Get _THIS_FE_ then find the right i2c_gate_ctrl for it */
fe0 = videobuf_dvb_get_frontend(&core->dvbdev->frontends, 1);
if (fe0 && fe0->dvb.frontend && fe0->dvb.frontend->ops.i2c_gate_ctrl)
fe0->dvb.frontend->ops.i2c_gate_ctrl(fe0->dvb.frontend, 1);
i2c_clients_command(&core->i2c_adap, cmd, arg);
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
if (fe0 && fe0->dvb.frontend && fe0->dvb.frontend->ops.i2c_gate_ctrl)
fe0->dvb.frontend->ops.i2c_gate_ctrl(fe0->dvb.frontend, 0);
} else
#endif
i2c_clients_command(&core->i2c_adap, cmd, arg);
......
......@@ -495,6 +495,7 @@ void cx88_ir_irq(struct cx88_core *core)
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
//TODO Darron has other code here
if ((ircode & 0xfffff000) != 0x3000)
break;
ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f, ircode);
......
......@@ -768,7 +768,8 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
{
struct cx8802_dev *dev;
struct cx88_core *core;
int err;
struct videobuf_dvb_frontend *demod;
int err,i;
/* general setup */
core = cx88_core_get(pci_dev);
......@@ -781,6 +782,11 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
if (!core->board.mpeg)
goto fail_core;
if (!core->board.num_frontends) {
printk(KERN_ERR "%s() .num_frontends should be non-zero, err = %d\n", __FUNCTION__, err);
goto fail_core;
}
err = -ENOMEM;
dev = kzalloc(sizeof(*dev),GFP_KERNEL);
if (NULL == dev)
......@@ -795,6 +801,20 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
INIT_LIST_HEAD(&dev->drvlist);
list_add_tail(&dev->devlist,&cx8802_devlist);
mutex_init(&dev->frontends.lock);
INIT_LIST_HEAD(&dev->frontends.frontend.felist);
printk(KERN_INFO "%s() allocating %d frontend(s)\n", __FUNCTION__, core->board.num_frontends);
for (i = 1; i <= core->board.num_frontends; i++) {
demod = videobuf_dvb_alloc_frontend(dev, &dev->frontends, i);
if(demod == NULL) {
printk(KERN_ERR "%s() failed to alloc\n", __FUNCTION__);
err = -ENOMEM;
goto fail_free;
}
}
/* Maintain a reference so cx88-video can query the 8802 device. */
core->dvbdev = dev;
......
......@@ -261,6 +261,7 @@ struct cx88_board {
struct cx88_input radio;
enum cx88_board_type mpeg;
unsigned int audio_chip;
int num_frontends;
};
struct cx88_subid {
......@@ -356,6 +357,7 @@ struct cx88_core {
struct cx8802_dev *dvbdev;
enum cx88_board_type active_type_id;
int active_ref;
int active_fe_id;
};
struct cx8800_dev;
......@@ -490,7 +492,7 @@ struct cx8802_dev {
#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
/* for dvb only */
struct videobuf_dvb dvb;
struct videobuf_dvb_frontends frontends;
#endif
#if defined(CONFIG_VIDEO_CX88_VP3054) || \
......
......@@ -535,11 +535,15 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
struct tda1004x_config *cdec_conf,
struct tda827x_config *tuner_conf)
{
dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
if (dev->dvb.frontend) {
struct videobuf_dvb_frontend *fe0;
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 0);
fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
if (fe0->dvb.frontend) {
if (cdec_conf->i2c_gate)
dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
if (dvb_attach(tda827x_attach, dev->dvb.frontend,
fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
cdec_conf->tuner_address,
&dev->i2c_adap, tuner_conf))
return 0;
......@@ -944,12 +948,18 @@ static int dvb_init(struct saa7134_dev *dev)
{
int ret;
int attach_xc3028 = 0;
struct videobuf_dvb_frontend *fe0;
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 0);
if (!fe0)
return -EINVAL;
/* init struct videobuf_dvb */
dev->ts.nr_bufs = 32;
dev->ts.nr_packets = 32*4;
dev->dvb.name = dev->name;
videobuf_queue_sg_init(&dev->dvb.dvbq, &saa7134_ts_qops,
fe0->dvb.name = dev->name;
videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
......@@ -959,47 +969,47 @@ static int dvb_init(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
dprintk("pinnacle 300i dvb setup\n");
dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
if (fe0->dvb.frontend) {
fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
}
break;
case SAA7134_BOARD_AVERMEDIA_777:
case SAA7134_BOARD_AVERMEDIA_A16AR:
dprintk("avertv 777 dvb setup\n");
dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend) {
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0x61,
TUNER_PHILIPS_TD1316);
}
break;
case SAA7134_BOARD_AVERMEDIA_A16D:
dprintk("AverMedia A16D dvb setup\n");
dev->dvb.frontend = dvb_attach(mt352_attach,
fe0->dvb.frontend = dvb_attach(mt352_attach,
&avermedia_xc3028_mt352_dev,
&dev->i2c_adap);
attach_xc3028 = 1;
break;
case SAA7134_BOARD_MD7134:
dev->dvb.frontend = dvb_attach(tda10046_attach,
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&medion_cardbus,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend) {
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, medion_cardbus.tuner_address,
TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
dev->dvb.frontend = dvb_attach(tda10046_attach,
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_tu1216_60_config,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
if (fe0->dvb.frontend) {
fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
}
break;
case SAA7134_BOARD_FLYDVBTDUO:
......@@ -1010,24 +1020,24 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
dev->dvb.frontend = dvb_attach(tda10046_attach,
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_europa_config,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
if (fe0->dvb.frontend) {
dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
dev->dvb.frontend = dvb_attach(tda10046_attach,
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_tu1216_61_config,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
if (fe0->dvb.frontend) {
fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
}
break;
case SAA7134_BOARD_KWORLD_DVBT_210:
......@@ -1060,20 +1070,20 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_0) < 0)
goto dettach_frontend;
break;
case SAA7134_BOARD_FLYDVB_TRIO:
case SAA7134_BOARD_FLYDVB_TRIO: // XXXXXX multifrontend
if (!use_frontend) { /* terrestrial */
if (configure_tda827x_fe(dev, &lifeview_trio_config,
&tda827x_cfg_0) < 0)
goto dettach_frontend;
} else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
if (fe0->dvb.frontend) {
if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
goto dettach_frontend;
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
0x08, 0, 0) == NULL) {
wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
goto dettach_frontend;
......@@ -1083,11 +1093,11 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
dev->dvb.frontend = dvb_attach(tda10046_attach,
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&ads_tech_duo_config,
&dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda827x_attach,dev->dvb.frontend,
if (fe0->dvb.frontend) {
if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
ads_tech_duo_config.tuner_address, &dev->i2c_adap,
&ads_duo_cfg) == NULL) {
wprintk("no tda827x tuner found at addr: %02x\n",
......@@ -1108,15 +1118,15 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_0) < 0)
goto dettach_frontend;
} else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach,
fe0->dvb.frontend = dvb_attach(tda10086_attach,
&flydvbs, &dev->i2c_adap);
if (dev->dvb.frontend) {
struct dvb_frontend *fe = dev->dvb.frontend;
if (fe0->dvb.frontend) {
struct dvb_frontend *fe = fe0->dvb.frontend;
u8 dev_id = dev->eedata[2];
u8 data = 0xc4;
struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
if (dvb_attach(tda826x_attach, dev->dvb.frontend,
if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
0x60, &dev->i2c_adap, 0) == NULL) {
wprintk("%s: Medion Quadro, no tda826x "
"found !\n", __func__);
......@@ -1150,31 +1160,31 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
&dev->i2c_adap);
if (dev->dvb.frontend)
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
if (fe0->dvb.frontend)
dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
NULL, DVB_PLL_TDHU2);
break;
case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
case SAA7134_BOARD_KWORLD_ATSC110:
dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
&dev->i2c_adap);
if (dev->dvb.frontend)
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
if (fe0->dvb.frontend)
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0x61,
TUNER_PHILIPS_TUV1236D);
break;
case SAA7134_BOARD_FLYDVBS_LR300:
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
&dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
if (fe0->dvb.frontend) {
if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
goto dettach_frontend;
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend,
if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: No ISL6421 found!\n", __func__);
goto dettach_frontend;
......@@ -1182,25 +1192,25 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
dev->dvb.frontend = dvb_attach(tda10046_attach,
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&medion_cardbus,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
if (fe0->dvb.frontend) {
dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
&dev->i2c_adap, medion_cardbus.tuner_address,
TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
dev->dvb.frontend = dvb_attach(tda10046_attach,
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_europa_config,
&dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
if (fe0->dvb.frontend) {
fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
}
break;
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
......@@ -1239,15 +1249,15 @@ static int dvb_init(struct saa7134_dev *dev)
goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_SNAKE:
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
&dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
if (fe0->dvb.frontend) {
if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
goto dettach_frontend;
}
if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0, 0) == NULL) {
wprintk("%s: No lnbp21 found!\n", __func__);
goto dettach_frontend;
......@@ -1269,24 +1279,24 @@ static int dvb_init(struct saa7134_dev *dev)
saa7134_set_gpio(dev, 25, 0);
msleep(10);
saa7134_set_gpio(dev, 25, 1);
dev->dvb.frontend = dvb_attach(mt352_attach,
fe0->dvb.frontend = dvb_attach(mt352_attach,
&avermedia_xc3028_mt352_dev,
&dev->i2c_adap);
attach_xc3028 = 1;
break;
case SAA7134_BOARD_MD7134_BRIDGE_2:
dev->dvb.frontend = dvb_attach(tda10086_attach,
fe0->dvb.frontend = dvb_attach(tda10086_attach,
&sd1878_4m, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (fe0->dvb.frontend) {
struct dvb_frontend *fe;
if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
&dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
wprintk("%s: MD7134 DVB-S, no SD1878 "
"found !\n", __func__);
goto dettach_frontend;
}
/* we need to open the i2c gate (we know it exists) */
fe = dev->dvb.frontend;
fe = fe0->dvb.frontend;
fe->ops.i2c_gate_ctrl(fe, 1);
if (dvb_attach(isl6405_attach, fe,
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
......@@ -1305,7 +1315,7 @@ static int dvb_init(struct saa7134_dev *dev)
saa7134_set_gpio(dev, 25, 0);
msleep(10);
saa7134_set_gpio(dev, 25, 1);
dev->dvb.frontend = dvb_attach(mt352_attach,
fe0->dvb.frontend = dvb_attach(mt352_attach,
&avermedia_xc3028_mt352_dev,
&dev->i2c_adap);
attach_xc3028 = 1;
......@@ -1316,17 +1326,17 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_2) < 0)
goto dettach_frontend;
} else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach,
fe0->dvb.frontend = dvb_attach(tda10086_attach,
&flydvbs, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (fe0->dvb.frontend) {
if (dvb_attach(tda826x_attach,
dev->dvb.frontend, 0x60,
fe0->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: Asus Tiger 3in1, no "
"tda826x found!\n", __func__);
goto dettach_frontend;
}
if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
&dev->i2c_adap, 0, 0) == NULL) {
wprintk("%s: Asus Tiger 3in1, no lnbp21"
" found!\n", __func__);
......@@ -1352,10 +1362,10 @@ static int dvb_init(struct saa7134_dev *dev)
.i2c_addr = 0x61,
};
if (!dev->dvb.frontend)
if (!fe0->dvb.frontend)
return -1;
fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->name);
......@@ -1363,40 +1373,47 @@ static int dvb_init(struct saa7134_dev *dev)
}
}
if (NULL == dev->dvb.frontend) {
if (NULL == fe0->dvb.frontend) {
printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
return -1;
}
/* define general-purpose callback pointer */
dev->dvb.frontend->callback = saa7134_tuner_callback;
fe0->dvb.frontend->callback = saa7134_tuner_callback;
/* register everything else */
ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
adapter_nr);
ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
&dev->pci->dev, adapter_nr);
/* this sequence is necessary to make the tda1004x load its firmware
* and to enter analog mode of hybrid boards
*/
if (!ret) {
if (dev->dvb.frontend->ops.init)
dev->dvb.frontend->ops.init(dev->dvb.frontend);
if (dev->dvb.frontend->ops.sleep)
dev->dvb.frontend->ops.sleep(dev->dvb.frontend);
if (dev->dvb.frontend->ops.tuner_ops.sleep)
dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
if (fe0->dvb.frontend->ops.init)
fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
if (fe0->dvb.frontend->ops.sleep)
fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
if (fe0->dvb.frontend->ops.tuner_ops.sleep)
fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
}
return ret;
dettach_frontend:
if (dev->dvb.frontend)
dvb_frontend_detach(dev->dvb.frontend);
dev->dvb.frontend = NULL;
if (fe0->dvb.frontend)
dvb_frontend_detach(fe0->dvb.frontend);
fe0->dvb.frontend = NULL;
return -1;
}
static int dvb_fini(struct saa7134_dev *dev)
{
struct videobuf_dvb_frontend *fe0;
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
/* FIXME: I suspect that this code is bogus, since the entry for
Pinnacle 300I DVB-T PAL already defines the proper init to allow
the detection of mt2032 (TDA9887_PORT2_INACTIVE)
......@@ -1416,7 +1433,7 @@ static int dvb_fini(struct saa7134_dev *dev)
u8 data = 0x80;
struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
struct dvb_frontend *fe;
fe = dev->dvb.frontend;
fe = fe0->dvb.frontend;
if (fe->ops.i2c_gate_ctrl) {
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
......@@ -1424,8 +1441,8 @@ static int dvb_fini(struct saa7134_dev *dev)
}
}
}
if (dev->dvb.frontend)
videobuf_dvb_unregister(&dev->dvb);
if (fe0->dvb.frontend)
videobuf_dvb_unregister_bus(&dev->frontends);
return 0;
}
......
......@@ -581,7 +581,7 @@ struct saa7134_dev {
#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
struct videobuf_dvb_frontends frontends;
int (*original_demod_sleep)(struct dvb_frontend *fe);
int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
......
......@@ -135,29 +135,75 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
}
/* ------------------------------------------------------------------ */
/* Register a single adapter and one or more frontends */
int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
struct module *module,
void *adapter_priv,
struct device *device,
short *adapter_nr) //NEW
{
struct list_head *list, *q;
struct videobuf_dvb_frontend *fe;
int res = -EINVAL;
fe = videobuf_dvb_get_frontend(f, 1);
if (!fe) {
printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
goto err;
}
/* Bring up the adapter */
res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr); //NEW
if (res < 0) {
printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
goto err;
}
/* Attach all of the frontends to the adapter */
mutex_lock(&f->lock);
list_for_each_safe(list, q, &f->frontend.felist) {
fe = list_entry(list, struct videobuf_dvb_frontend, felist);
int videobuf_dvb_register(struct videobuf_dvb *dvb,
res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb);
if (res < 0) {
printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n",
fe->dvb.name, res);
}
}
mutex_unlock(&f->lock);
err:
return res;
}
int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
struct module *module,
void *adapter_priv,
struct device *device,
short *adapter_nr)
char *adapter_name,
short *adapter_nr) //NEW
{
int result;
mutex_init(&dvb->lock);
mutex_init(&fe->lock);
/* register adapter */
result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device,
adapter_nr);
result = dvb_register_adapter(&fe->adapter, adapter_name, module, device, adapter_nr);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
dvb->name, result);
goto fail_adapter;
adapter_name, result);
}
dvb->adapter.priv = adapter_priv;
fe->adapter.priv = adapter_priv;
return result;
}
int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_dvb *dvb)
{
int result;
/* register frontend */
result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
result = dvb_register_frontend(adapter, dvb->frontend);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
dvb->name, result);
......@@ -183,7 +229,9 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
dvb->dmxdev.filternum = 256;
dvb->dmxdev.demux = &dvb->demux.dmx;
dvb->dmxdev.capabilities = 0;
result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
//result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
dvb->name, result);
......@@ -214,7 +262,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
}
/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
return 0;
fail_fe_conn:
......@@ -230,24 +278,101 @@ fail_dmx:
fail_frontend:
dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
fail_adapter:
return result;
}
void videobuf_dvb_unregister(struct videobuf_dvb *dvb)
void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f)
{
dvb_net_release(&dvb->net);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
dvb_dmxdev_release(&dvb->dmxdev);
dvb_dmx_release(&dvb->demux);
dvb_unregister_frontend(dvb->frontend);
dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
struct list_head *list, *q;
struct videobuf_dvb_frontend *fe;
mutex_lock(&f->lock);
list_for_each_safe(list, q, &f->frontend.felist) {
fe = list_entry(list, struct videobuf_dvb_frontend, felist);
dvb_net_release(&fe->dvb.net);
fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem);
fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw);
dvb_dmxdev_release(&fe->dvb.dmxdev);
dvb_dmx_release(&fe->dvb.demux);
dvb_unregister_frontend(fe->dvb.frontend);
dvb_frontend_detach(fe->dvb.frontend);
list_del(list);
kfree(fe);
}
mutex_unlock(&f->lock);
dvb_unregister_adapter(&f->adapter);
}
struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id)
{
struct list_head *list, *q;
struct videobuf_dvb_frontend *fe, *ret = NULL;
mutex_lock(&f->lock);
list_for_each_safe(list, q, &f->frontend.felist) {
fe = list_entry(list, struct videobuf_dvb_frontend, felist);
if (fe->id == id) {
ret = fe;
break;
}
}
mutex_unlock(&f->lock);
return ret;
}
int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p)
{
struct list_head *list, *q;
struct videobuf_dvb_frontend *fe = NULL;
int ret = 0;
mutex_lock(&f->lock);
list_for_each_safe(list, q, &f->frontend.felist) {
fe = list_entry(list, struct videobuf_dvb_frontend, felist);
if (fe->dvb.frontend == p) {
ret = fe->id;
break;
}
}
mutex_unlock(&f->lock);
return ret;
}
struct videobuf_dvb_frontend * videobuf_dvb_alloc_frontend(void *private, struct videobuf_dvb_frontends *f, int id)
{
struct videobuf_dvb_frontend *fe;
fe = kzalloc(sizeof(struct videobuf_dvb_frontend),GFP_KERNEL);
if (fe == NULL)
goto fail_alloc;
fe->dev = private;
fe->id = id;
mutex_init(&fe->dvb.lock);
mutex_lock(&f->lock);
list_add_tail(&fe->felist,&f->frontend.felist);
mutex_unlock(&f->lock);
fail_alloc:
return fe;
}
EXPORT_SYMBOL(videobuf_dvb_register);
EXPORT_SYMBOL(videobuf_dvb_unregister);
EXPORT_SYMBOL(videobuf_dvb_register_bus);
EXPORT_SYMBOL(videobuf_dvb_unregister_bus);
EXPORT_SYMBOL(videobuf_dvb_alloc_frontend);
EXPORT_SYMBOL(videobuf_dvb_get_frontend);
EXPORT_SYMBOL(videobuf_dvb_find_frontend);
/* ------------------------------------------------------------------ */
/*
......
......@@ -24,12 +24,42 @@ struct videobuf_dvb {
struct dvb_net net;
};
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct videobuf_dvb_frontend {
void *dev;
struct list_head felist;
int id;
struct videobuf_dvb dvb;
};
struct videobuf_dvb_frontends {
struct mutex lock;
struct dvb_adapter adapter;
int active_fe_id; /* Indicates which frontend in the felist is in use */
struct videobuf_dvb_frontend frontend;
};
int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
struct module *module,
void *adapter_priv,
struct device *device,
short *adapter_nr);
void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
short *adapter_nr); //NEW
void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f);
int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *f,
struct module *module,
void *adapter_priv,
struct device *device,
char *adapter_name,
short *adapter_nr); //NEW
int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_dvb *dvb);
struct videobuf_dvb_frontend * videobuf_dvb_alloc_frontend(void *private, struct videobuf_dvb_frontends *f, int id);
struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id);
int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p);
/*
* Local variables:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment