diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-15 22:02:21 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-15 22:02:21 -0200 |
commit | 4955fc93620d44b79e1f67d2fe79ab69908a899e (patch) | |
tree | bcc16a3b4b11a1e5f4fe00e9fde2ac76d74601cf /linux/drivers | |
parent | 4afe7ace95f920cd15994f7f5481c3e2e4bf2f20 (diff) | |
parent | 734117f33e377f3732bd813fc648cba0762d43ae (diff) | |
download | mediapointer-dvb-s2-4955fc93620d44b79e1f67d2fe79ab69908a899e.tar.gz mediapointer-dvb-s2-4955fc93620d44b79e1f67d2fe79ab69908a899e.tar.bz2 |
merge: http://www.linuxtv.org/hg/~stoth/mfe
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Priority: normal
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers')
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvb_frontend.c | 67 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvb_frontend.h | 1 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvbdev.c | 3 | ||||
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvbdev.h | 4 | ||||
-rw-r--r-- | linux/drivers/media/video/cx23885/cx23885-core.c | 11 | ||||
-rw-r--r-- | linux/drivers/media/video/cx23885/cx23885-dvb.c | 164 | ||||
-rw-r--r-- | linux/drivers/media/video/cx23885/cx23885.h | 5 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-cards.c | 37 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-dvb.c | 399 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-i2c.c | 17 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-mpeg.c | 22 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88.h | 6 | ||||
-rw-r--r-- | linux/drivers/media/video/saa7134/saa7134-dvb.c | 216 | ||||
-rw-r--r-- | linux/drivers/media/video/saa7134/saa7134.h | 2 | ||||
-rw-r--r-- | linux/drivers/media/video/videobuf-dvb.c | 175 |
15 files changed, 794 insertions, 335 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index c07c14ba0..51fb82edc 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -52,6 +52,7 @@ static int dvb_shutdown_timeout; static int dvb_force_auto_inversion; static int dvb_override_tune_delay; static int dvb_powerdown_on_sleep = 1; +static int dvb_mfe_wait_time = 5; module_param_named(frontend_debug, dvb_frontend_debug, int, 0644); MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off)."); @@ -63,6 +64,8 @@ module_param(dvb_override_tune_delay, int, 0644); MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt"); module_param(dvb_powerdown_on_sleep, int, 0644); MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)"); +module_param(dvb_mfe_wait_time, int, 0644); +MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)"); #define dprintk if (dvb_frontend_debug) printk @@ -217,8 +220,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) @@ -697,7 +701,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); @@ -721,8 +725,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, @@ -735,8 +739,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; } @@ -746,8 +750,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; } @@ -757,8 +761,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; } @@ -1820,13 +1824,46 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_adapter *adapter = fe->dvb; + struct dvb_device *mfedev; + struct dvb_frontend *mfe; + struct dvb_frontend_private *mfepriv; + int mferetry; int ret; dprintk ("%s\n", __func__); + if (adapter->mfe_shared) { + mutex_lock (&adapter->mfe_lock); + if (adapter->mfe_dvbdev != dvbdev) { + if (adapter->mfe_dvbdev) { + mfedev = adapter->mfe_dvbdev; + mfe = mfedev->priv; + mfepriv = mfe->frontend_priv; + mutex_unlock (&adapter->mfe_lock); + mferetry = (dvb_mfe_wait_time << 1); + while (mferetry-- && (mfedev->users != -1 || mfepriv->thread != NULL)) { + if(msleep_interruptible(500)) { + if(signal_pending(current)) + return -EINTR; + } + } + mutex_lock (&adapter->mfe_lock); + mfedev = adapter->mfe_dvbdev; + mfe = mfedev->priv; + mfepriv = mfe->frontend_priv; + if (mfedev->users != -1 || mfepriv->thread != NULL) { + ret = -EBUSY; + goto err0; + } + } + adapter->mfe_dvbdev = dvbdev; + } + } + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) - return ret; + goto err0; } if ((ret = dvb_generic_open (inode, file)) < 0) @@ -1846,6 +1883,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) fepriv->events.eventr = fepriv->events.eventw = 0; } + if (adapter->mfe_shared) + mutex_unlock (&adapter->mfe_lock); return ret; err2: @@ -1853,6 +1892,9 @@ err2: err1: if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) fe->ops.ts_bus_ctrl(fe, 0); +err0: + if (adapter->mfe_shared) + mutex_unlock (&adapter->mfe_lock); return ret; } @@ -1922,8 +1964,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, diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h index a0c591b3b..569b72a96 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -236,6 +236,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, diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.c b/linux/drivers/media/dvb/dvb-core/dvbdev.c index 0820da504..422af5a0d 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.c +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c @@ -341,6 +341,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, adap->name = name; adap->module = module; adap->device = device; + adap->mfe_shared = 0; + adap->mfe_dvbdev = NULL; + mutex_init (&adap->mfe_lock); list_add_tail (&adap->list_head, &dvb_adapter_list); diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h index 89d12dc47..574e336ba 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.h +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h @@ -62,6 +62,10 @@ struct dvb_adapter { struct device *device; struct module *module; + + int mfe_shared; /* indicates mutually exclusive frontends */ + struct dvb_device *mfe_dvbdev; /* frontend device in use */ + struct mutex mfe_lock; /* access lock for thread creation */ }; diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c index c050cd2ce..6fc69988a 100644 --- a/linux/drivers/media/video/cx23885/cx23885-core.c +++ b/linux/drivers/media/video/cx23885/cx23885-core.c @@ -644,6 +644,17 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p port->mpegq.timeout.data = (unsigned long)port; init_timer(&port->mpegq.timeout); + mutex_init(&port->frontends.lock); + INIT_LIST_HEAD(&port->frontends.frontend.felist); + port->frontends.active_fe_id = 0; + + /* This should be hardcoded allow a single frontend + * attachment to this tsport, keeping the -dvb.c + * code clean and safe. + */ + if(!port->num_frontends) + port->num_frontends = 1; + switch(portno) { case 1: port->reg_gpcnt = VID_B_GPCNT; diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index 1909ef6e3..9b96b0600 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -313,19 +313,25 @@ 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; + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + 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); } @@ -334,27 +340,27 @@ static int dvb_register(struct cx23885_tsport *port) i2c_bus = &dev->i2c_bus[0]; switch (alt_tuner) { 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; @@ -362,42 +368,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, @@ -410,7 +416,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); } @@ -418,24 +424,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, @@ -450,7 +456,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); } @@ -458,25 +464,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, @@ -488,7 +494,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); @@ -498,10 +504,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, @@ -513,7 +519,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); @@ -524,43 +530,70 @@ 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, - &dev->pci->dev, adapter_nr); + return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, + &dev->pci->dev, adapter_nr, 0); + } int cx23885_dvb_register(struct cx23885_tsport *port) { + + struct videobuf_dvb_frontend *fe0; struct cx23885_dev *dev = port->dev; - int err; + int err, i; + + /* Here we need to allocate the correct number of frontends, + * as reflected in the cards struct. The reality is that currrently + * no cx23885 boards support this - yet. But, if we don't modify this + * code then the second frontend would never be allocated (later) + * and fail with error before the attach in dvb_register(). + * Without these changes we risk an OOPS later. The changes here + * are for safety, and should provide a good foundation for the + * future addition of any multi-frontend cx23885 based boards. + */ + printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, + port->num_frontends); - dprintk(1, "%s\n", __func__); - dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - dev->board, - dev->name, - dev->pci_bus, - dev->pci_slot); + for (i = 1; i <= port->num_frontends; i++) { + if (videobuf_dvb_alloc_frontend(dev, &port->frontends, i) == NULL) { + printk(KERN_ERR "%s() failed to alloc\n", __func__); + return -ENOMEM; + } - err = -ENODEV; + fe0 = videobuf_dvb_get_frontend(&port->frontends, i); + if (!fe0) + err = -EINVAL; - /* 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, + dprintk(1, "%s\n", __func__); + dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dev->board, + dev->name, + dev->pci_bus, + dev->pci_slot); + + err = -ENODEV; + + /* dvb stuff */ + /* We have to init the queue for each frontend on a port. */ + printk("%s: cx23885 based dvb card\n", dev->name); + 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); if (err != 0) printk("%s() dvb_register failed err = %d\n", __func__, err); @@ -570,9 +603,18 @@ int cx23885_dvb_register(struct cx23885_tsport *port) int cx23885_dvb_unregister(struct cx23885_tsport *port) { - /* dvb */ - if(port->dvb.frontend) - videobuf_dvb_unregister(&port->dvb); + struct videobuf_dvb_frontend *fe0; + + /* FIXME: in an error condition where the we have + * an expected number of frontends (attach problem) + * then this might not clean up correctly, if 1 + * is invalid. + * This comment only applies to future boards IF they + * implement MFE support. + */ + fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + if(fe0->dvb.frontend) + videobuf_dvb_unregister_bus(&port->frontends); return 0; } diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index dea1798f7..2dde9e01a 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -226,7 +226,7 @@ struct cx23885_tsport { int nr; int sram_chno; - struct videobuf_dvb dvb; + struct videobuf_dvb_frontends frontends; /* dma queues */ struct cx23885_dmaqueue mpegq; @@ -263,6 +263,9 @@ struct cx23885_tsport { u32 src_sel_val; u32 vld_misc_val; u32 hw_sop_ctrl_val; + + /* Allow a single tsport to have multiple frontends */ + u32 num_frontends; }; struct cx23885_dev { diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index a351a2220..eac3508d6 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1303,27 +1303,36 @@ static const struct cx88_board cx88_boards[] = { .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_HVR3000] = { - /* FIXME: Add dvb & radio support */ .name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T", .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + .audio_chip = V4L2_IDENT_WM8775, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x84bf, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x84bf, + .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x84bf, + .audioroute = 2, }}, + /* FIXME Radio tunes but only noise is heard */ + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x84bf, + }, .mpeg = CX88_MPEG_DVB, + .num_frontends = 2, }, [CX88_BOARD_NORWOOD_MICRO] = { .name = "Norwood Micro TV Tuner", @@ -1749,6 +1758,7 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + .audio_chip = V4L2_IDENT_WM8775, /* * GPIO0 (WINTV2000) * @@ -1762,7 +1772,7 @@ static const struct cx88_board cx88_boards[] = { * BIT VALUE FUNCTION GP{x}_IO * 0 1 I:? * 1 1 I:? - * 2 1 O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH + * 2 1 O:MPEG PORT 0=DVB-T 1=DVB-S * 3 1 I:? * 4 1 I:? * 5 1 I:? @@ -1783,17 +1793,25 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xc4bf, + .audioroute = 1, }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xc4bf, + .audioroute = 2, }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xc4bf, + .audioroute = 2, } }, - /* fixme: Add radio support */ + /* FIXME Radio tunes but only noise is heard */ + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xc4bf, + }, .mpeg = CX88_MPEG_DVB, + .num_frontends = 2, }, [CX88_BOARD_HAUPPAUGE_HVR4000LITE] = { .name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2", @@ -2695,10 +2713,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR4000: - case CX88_BOARD_HAUPPAUGE_HVR4000LITE: /* Init GPIO */ 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); /* 702 out of reset */ + udelay(1000); break; } } @@ -3037,10 +3058,14 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) 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]; diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 84f235ba0..1a0f971c6 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -117,13 +117,23 @@ 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; @@ -490,6 +500,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, @@ -497,7 +508,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); @@ -511,10 +527,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; } @@ -539,8 +558,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); @@ -581,19 +602,25 @@ static struct stv0288_config tevii_tuner_earda_config = { static int dvb_register(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ - /* 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 */ + /* multi-frontend gate control is undefined or defaults to fe0 */ + dev->frontends.gate = 0; + + /* init frontend(s) */ 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; @@ -603,11 +630,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; @@ -617,33 +644,67 @@ 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) { + dev->frontends.gate = 2; + mfe_shared = 1; + 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; } @@ -651,31 +712,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; } @@ -683,11 +744,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; } @@ -695,10 +756,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; @@ -709,22 +770,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); /* @@ -732,16 +793,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; @@ -758,11 +819,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; @@ -776,11 +837,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; @@ -794,15 +855,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; } @@ -815,25 +876,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; @@ -841,49 +902,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, @@ -896,17 +957,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; } @@ -914,85 +975,118 @@ 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) { + dev->frontends.gate = 2; + mfe_shared = 1; + 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: @@ -1000,29 +1094,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, - &dev->pci->dev, adapter_nr); + return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, + &dev->pci->dev, adapter_nr, mfe_shared); 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; } @@ -1046,6 +1143,38 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) cx_clear(MO_GP0_IO, 0x00000004); udelay(1000); break; + + case CX88_BOARD_HAUPPAUGE_HVR3000: + 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; } @@ -1066,6 +1195,9 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv) cx_set(MO_GP0_IO, 0x00000004); #endif break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + break; default: err = -ENODEV; } @@ -1076,7 +1208,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", @@ -1096,18 +1229,28 @@ 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", core->name, err); - - fail_core: +fail_core: return err; } @@ -1115,9 +1258,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); diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index 8e74d64fd..01de23007 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -116,18 +116,25 @@ 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_frontends *f = &core->dvbdev->frontends; + struct videobuf_dvb_frontend *fe = 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 && f) { + if(f->gate <= 1) /* undefined or fe0 */ + fe = videobuf_dvb_get_frontend(f, 1); + else + fe = videobuf_dvb_get_frontend(f, f->gate); + + if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->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 (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 0); } else #endif i2c_clients_command(&core->i2c_adap, cmd, arg); diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index 4af6604ec..88c237790 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -808,7 +808,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); @@ -821,6 +822,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) @@ -835,6 +841,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; diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 778e1f707..774c0b9b1 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -248,7 +248,7 @@ struct cx88_input { enum cx88_itype type; u32 gpio0, gpio1, gpio2, gpio3; unsigned int vmux:2; - unsigned int audioroute:2; + unsigned int audioroute:4; }; struct cx88_board { @@ -262,6 +262,7 @@ struct cx88_board { struct cx88_input radio; enum cx88_board_type mpeg; unsigned int audio_chip; + int num_frontends; }; struct cx88_subid { @@ -360,6 +361,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; @@ -511,7 +513,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) || \ diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index c84895fca..11a7c76bc 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -535,11 +535,16 @@ 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; + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + + 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 +949,30 @@ static int dvb_init(struct saa7134_dev *dev) { int ret; int attach_xc3028 = 0; + struct videobuf_dvb_frontend *fe0; + + /* FIXME: add support for multi-frontend */ + mutex_init(&dev->frontends.lock); + INIT_LIST_HEAD(&dev->frontends.frontend.felist); + dev->frontends.active_fe_id = 0; + + printk(KERN_INFO "%s() allocating 1 frontend\n", __func__); + + if (videobuf_dvb_alloc_frontend(dev, &dev->frontends, 1) == NULL) { + printk(KERN_ERR "%s() failed to alloc\n", __func__); + return -ENOMEM; + } + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + 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 +982,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 +1033,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: @@ -1066,14 +1089,14 @@ static int dvb_init(struct saa7134_dev *dev) &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 +1106,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 +1131,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 +1173,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 +1205,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 +1262,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,7 +1292,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; @@ -1279,18 +1302,18 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_VIDEOMATE_T750: #endif 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) { @@ -1309,7 +1332,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; @@ -1320,17 +1343,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__); @@ -1356,10 +1379,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); @@ -1367,40 +1390,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, 0); /* 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) @@ -1420,7 +1450,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); @@ -1428,8 +1458,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; } diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index 502cbe60c..837fc5424 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -586,7 +586,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); diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c index d9979ab26..33e2f2b2b 100644 --- a/linux/drivers/media/video/videobuf-dvb.c +++ b/linux/drivers/media/video/videobuf-dvb.c @@ -140,29 +140,78 @@ 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, + int mfe_shared) +{ + 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, mfe_shared); + if (res < 0) { + printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); + goto err; + } -int videobuf_dvb_register(struct videobuf_dvb *dvb, + /* 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); + + 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, + int mfe_shared) { 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; + fe->adapter.mfe_shared = mfe_shared; + + 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); @@ -188,7 +237,8 @@ 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, adapter); + if (result < 0) { printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", dvb->name, result); @@ -219,7 +269,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: @@ -234,25 +284,102 @@ fail_dmx: dvb_unregister_frontend(dvb->frontend); fail_frontend: dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: + dvb_unregister_adapter(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); /* ------------------------------------------------------------------ */ /* |