summaryrefslogtreecommitdiff
path: root/linux/drivers/media
diff options
context:
space:
mode:
authordarron@kewl.org <darron@kewl.org>2008-10-11 15:44:05 +0100
committerdarron@kewl.org <darron@kewl.org>2008-10-11 15:44:05 +0100
commite792b162282b2a6897d82cb48a3ee6222bc01686 (patch)
tree53bb879a2b29b8a2c504d3e73923d349d7842a84 /linux/drivers/media
parent8e5764414cfbfb3a7abb46f3fc79e631c643379c (diff)
downloadmediapointer-dvb-s2-e792b162282b2a6897d82cb48a3ee6222bc01686.tar.gz
mediapointer-dvb-s2-e792b162282b2a6897d82cb48a3ee6222bc01686.tar.bz2
MFE: Add multi-frontend mutual exclusion
From: Darron Broad <darron@kewl.org> This add frontend R/W mutual exclusion. Prior to this point in time it was possible to open both frontends simultaneously which an MFE card cannot support. In order to stop this, a delayed open is performed which has the following function: Return EBUSY after a configurable amount of time if a frontend is unavailable due to the other being in use. Only allow opening of a frontend if the kernel thread of the other has stopped. This solution was chosen to allow switching between frontends to work as seamlessly as possible. When both frontends are actually opened simultaneously then one will only open, but if quick switching is performed between one of many then the new open will succeed in a clean fashion rather than interrupting a kernel thread. Priority: normal Signed-off-by: Darron Broad <darron@kewl.org>
Diffstat (limited to 'linux/drivers/media')
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c43
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.c3
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.h4
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c2
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c11
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c2
-rw-r--r--linux/drivers/media/video/videobuf-dvb.c9
7 files changed, 61 insertions, 13 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index 548d90143..46765bc09 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
@@ -1820,13 +1823,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 +1882,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 +1891,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/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-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index f67493472..5f32c1550 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -557,7 +557,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/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index a2b91e41f..19699f816 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -601,14 +601,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);
@@ -676,6 +671,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);
@@ -1020,6 +1016,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);
@@ -1117,7 +1114,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/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index 7c96e8832..11a7c76bc 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1399,7 +1399,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/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c
index cf699a8ca..33e2f2b2b 100644
--- a/linux/drivers/media/video/videobuf-dvb.c
+++ b/linux/drivers/media/video/videobuf-dvb.c
@@ -145,7 +145,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;
@@ -158,7 +159,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;
@@ -186,7 +187,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;
@@ -199,6 +201,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;
}