diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 26671757c70b..62696f865576 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -47,6 +47,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)."); @@ -58,6 +59,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 seconds on open() for multi-frontend to become available (default:5 seconds)"); #define dprintk if (dvb_frontend_debug) printk @@ -1706,13 +1709,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) @@ -1732,6 +1768,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: @@ -1739,6 +1777,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; } diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 665776d72a48..a113744a56cc 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -326,6 +326,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/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 89d12dc477a7..574e336bac35 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/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/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index c14878f74bcc..78851526db68 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -556,7 +556,7 @@ static int dvb_register(struct cx23885_tsport *port) /* register everything */ return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, - &dev->pci->dev, adapter_nr); + &dev->pci->dev, adapter_nr, 0); } diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 9bb7bee0da6d..0dd0ff9227fb 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -594,14 +594,9 @@ 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; + int mfe_shared = 0; /* bus not shared by default */ /* Get the first frontend */ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); @@ -669,6 +664,7 @@ static int dvb_register(struct cx8802_dev *dev) 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); @@ -1013,6 +1009,7 @@ static int dvb_register(struct cx8802_dev *dev) 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); @@ -1110,7 +1107,7 @@ static int dvb_register(struct cx8802_dev *dev) /* register everything */ return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, - &dev->pci->dev, adapter_nr); + &dev->pci->dev, adapter_nr, mfe_shared); frontend_detach: if (fe0->dvb.frontend) { diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 30ae0cbe78a0..d2d238912fbf 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1395,7 +1395,7 @@ static int dvb_init(struct saa7134_dev *dev) /* register everything else */ ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, - &dev->pci->dev, adapter_nr); + &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 diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index a0a80e1e79e3..af0b75cda6fd 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -140,7 +140,8 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, struct module *module, void *adapter_priv, struct device *device, - short *adapter_nr) //NEW + short *adapter_nr, + int mfe_shared) { struct list_head *list, *q; struct videobuf_dvb_frontend *fe; @@ -153,7 +154,7 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, } /* Bring up the adapter */ - res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr); //NEW + 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; @@ -181,7 +182,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, void *adapter_priv, struct device *device, char *adapter_name, - short *adapter_nr) //NEW + short *adapter_nr, + int mfe_shared) { int result; @@ -194,6 +196,7 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, adapter_name, result); } fe->adapter.priv = adapter_priv; + fe->adapter.mfe_shared = mfe_shared; return result; } diff --git a/include/media/videobuf-dvb.h b/include/media/videobuf-dvb.h index 47bc2c5e7ba9..1a401f7320b9 100644 --- a/include/media/videobuf-dvb.h +++ b/include/media/videobuf-dvb.h @@ -43,7 +43,8 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, struct module *module, void *adapter_priv, struct device *device, - short *adapter_nr); //NEW + short *adapter_nr, + int mfe_shared); void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f); @@ -52,7 +53,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *f, void *adapter_priv, struct device *device, char *adapter_name, - short *adapter_nr); //NEW + short *adapter_nr, + int mfe_shared); int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_dvb *dvb);