提交 59b1842d 编写于 作者: D Darron Broad 提交者: Mauro Carvalho Chehab

V4L/DVB (9227): MFE: Add multi-frontend mutual exclusion

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.
Signed-off-by: NDarron Broad <darron@kewl.org>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 2f3af9e6
...@@ -47,6 +47,7 @@ static int dvb_shutdown_timeout; ...@@ -47,6 +47,7 @@ static int dvb_shutdown_timeout;
static int dvb_force_auto_inversion; static int dvb_force_auto_inversion;
static int dvb_override_tune_delay; static int dvb_override_tune_delay;
static int dvb_powerdown_on_sleep = 1; 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_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off)."); 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); ...@@ -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_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_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_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 #define dprintk if (dvb_frontend_debug) printk
...@@ -1706,13 +1709,46 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -1706,13 +1709,46 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_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; int ret;
dprintk ("%s\n", __func__); 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 (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
return ret; goto err0;
} }
if ((ret = dvb_generic_open (inode, file)) < 0) if ((ret = dvb_generic_open (inode, file)) < 0)
...@@ -1732,6 +1768,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -1732,6 +1768,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
fepriv->events.eventr = fepriv->events.eventw = 0; fepriv->events.eventr = fepriv->events.eventw = 0;
} }
if (adapter->mfe_shared)
mutex_unlock (&adapter->mfe_lock);
return ret; return ret;
err2: err2:
...@@ -1739,6 +1777,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ...@@ -1739,6 +1777,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
err1: err1:
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl(fe, 0); fe->ops.ts_bus_ctrl(fe, 0);
err0:
if (adapter->mfe_shared)
mutex_unlock (&adapter->mfe_lock);
return ret; return ret;
} }
......
...@@ -326,6 +326,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, ...@@ -326,6 +326,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
adap->name = name; adap->name = name;
adap->module = module; adap->module = module;
adap->device = device; 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); list_add_tail (&adap->list_head, &dvb_adapter_list);
......
...@@ -62,6 +62,10 @@ struct dvb_adapter { ...@@ -62,6 +62,10 @@ struct dvb_adapter {
struct device *device; struct device *device;
struct module *module; 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 */
}; };
......
...@@ -556,7 +556,7 @@ static int dvb_register(struct cx23885_tsport *port) ...@@ -556,7 +556,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* register everything */ /* register everything */
return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr); &dev->pci->dev, adapter_nr, 0);
} }
......
...@@ -594,14 +594,9 @@ static struct stv0288_config tevii_tuner_earda_config = { ...@@ -594,14 +594,9 @@ static struct stv0288_config tevii_tuner_earda_config = {
static int dvb_register(struct cx8802_dev *dev) 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 cx88_core *core = dev->core;
struct videobuf_dvb_frontend *fe0, *fe1 = NULL; struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
int mfe_shared = 0; /* bus not shared by default */
/* Get the first frontend */ /* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
...@@ -669,6 +664,7 @@ static int dvb_register(struct cx8802_dev *dev) ...@@ -669,6 +664,7 @@ static int dvb_register(struct cx8802_dev *dev)
fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
if (fe1) { if (fe1) {
dev->frontends.gate = 2; dev->frontends.gate = 2;
mfe_shared = 1;
fe1->dvb.frontend = dvb_attach(cx22702_attach, fe1->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config, &hauppauge_hvr_config,
&dev->core->i2c_adap); &dev->core->i2c_adap);
...@@ -1013,6 +1009,7 @@ static int dvb_register(struct cx8802_dev *dev) ...@@ -1013,6 +1009,7 @@ static int dvb_register(struct cx8802_dev *dev)
fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
if (fe1) { if (fe1) {
dev->frontends.gate = 2; dev->frontends.gate = 2;
mfe_shared = 1;
fe1->dvb.frontend = dvb_attach(cx22702_attach, fe1->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config, &hauppauge_hvr_config,
&dev->core->i2c_adap); &dev->core->i2c_adap);
...@@ -1110,7 +1107,7 @@ static int dvb_register(struct cx8802_dev *dev) ...@@ -1110,7 +1107,7 @@ static int dvb_register(struct cx8802_dev *dev)
/* register everything */ /* register everything */
return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
&dev->pci->dev, adapter_nr); &dev->pci->dev, adapter_nr, mfe_shared);
frontend_detach: frontend_detach:
if (fe0->dvb.frontend) { if (fe0->dvb.frontend) {
......
...@@ -1395,7 +1395,7 @@ static int dvb_init(struct saa7134_dev *dev) ...@@ -1395,7 +1395,7 @@ static int dvb_init(struct saa7134_dev *dev)
/* register everything else */ /* register everything else */
ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, 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 /* this sequence is necessary to make the tda1004x load its firmware
* and to enter analog mode of hybrid boards * and to enter analog mode of hybrid boards
......
...@@ -140,7 +140,8 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, ...@@ -140,7 +140,8 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
struct module *module, struct module *module,
void *adapter_priv, void *adapter_priv,
struct device *device, struct device *device,
short *adapter_nr) //NEW short *adapter_nr,
int mfe_shared)
{ {
struct list_head *list, *q; struct list_head *list, *q;
struct videobuf_dvb_frontend *fe; struct videobuf_dvb_frontend *fe;
...@@ -153,7 +154,7 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, ...@@ -153,7 +154,7 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
} }
/* Bring up the adapter */ /* 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) { if (res < 0) {
printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
goto err; goto err;
...@@ -181,7 +182,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, ...@@ -181,7 +182,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
void *adapter_priv, void *adapter_priv,
struct device *device, struct device *device,
char *adapter_name, char *adapter_name,
short *adapter_nr) //NEW short *adapter_nr,
int mfe_shared)
{ {
int result; int result;
...@@ -194,6 +196,7 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, ...@@ -194,6 +196,7 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
adapter_name, result); adapter_name, result);
} }
fe->adapter.priv = adapter_priv; fe->adapter.priv = adapter_priv;
fe->adapter.mfe_shared = mfe_shared;
return result; return result;
} }
......
...@@ -43,7 +43,8 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, ...@@ -43,7 +43,8 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
struct module *module, struct module *module,
void *adapter_priv, void *adapter_priv,
struct device *device, struct device *device,
short *adapter_nr); //NEW short *adapter_nr,
int mfe_shared);
void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f); void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f);
...@@ -52,7 +53,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *f, ...@@ -52,7 +53,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *f,
void *adapter_priv, void *adapter_priv,
struct device *device, struct device *device,
char *adapter_name, 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); int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_dvb *dvb);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册