]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
V4L/DVB (9227): MFE: Add multi-frontend mutual exclusion
authorDarron Broad <darron@kewl.org>
Sat, 11 Oct 2008 14:44:05 +0000 (11:44 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 17 Oct 2008 20:24:15 +0000 (17:24 -0300)
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: Darron Broad <darron@kewl.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/videobuf-dvb.c
include/media/videobuf-dvb.h

index 26671757c70b460f8c1a35005a16ab39968e3125..62696f86557693fcf838027aa35140d8f8d3df79 100644 (file)
@@ -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 <mfe_wait_time> 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;
 }
 
index 665776d72a48c0456b712b25894760e60f48e4e8..a113744a56cc136c0355184b0af4504b0219970a 100644 (file)
@@ -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);
 
index 89d12dc477a7b4f4017803a86d1bfaa6ef46b7ce..574e336bac35b7b8d81471a32fea7c2558fc530c 100644 (file)
@@ -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 */
 };
 
 
index c14878f74bcc33be88295c5cbee58ac8b694d5e3..78851526db68134e68553180bd10b29808ff9373 100644 (file)
@@ -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);
 
 }
 
index 9bb7bee0da6d8b90c2a2385af86036da81b9260c..0dd0ff9227fb2e827a708503f67e35e0c6062db9 100644 (file)
@@ -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) {
index 30ae0cbe78a005f8194f977375471747eff240d7..d2d238912fbf23c550e9298e8a8f5f63284d4d8d 100644 (file)
@@ -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
index a0a80e1e79e3c08aec59c2e99241eb59f9e6ff0c..af0b75cda6fdb3f63d9cac45630d14453e98893e 100644 (file)
@@ -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;
 }
index 47bc2c5e7ba947dbdebd45ffa4ff8538c55273d3..1a401f7320b9ed8b2afb464ae02d65e6cafd5de9 100644 (file)
@@ -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);