V4L/DVB (7893): xc5000: bug-fix: allow multiple devices in a single system
authorMichael Krufky <mkrufky@linuxtv.org>
Sat, 10 May 2008 17:34:09 +0000 (14:34 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 14 May 2008 05:56:46 +0000 (02:56 -0300)
The current code passes a context pointer in the xc5000_config struct.
This context pointer is used in the tuner_callback function, used to
reset the device after firmware download.

The xc5000_config struct is a static structure, whose .priv member was
being assigned before calling xc5000_attach().  If there are more than
one of the same device type installed on a single system, the last one
to assign xc5000_config.priv will "win", and all others will cease to
function properly.

This patch passes the context pointer in xc5000_attach() rather that
storing it within the static struct xc5000_config.

Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/common/tuners/xc5000_priv.h
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/tuner-core.c

index 43d35bdb221f0ab367953d557d9c29d4fae2b077..ceae6db901ecaa9543f5e4ef4bcd727e3d10cc42 100644 (file)
@@ -212,7 +212,7 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
        dprintk(1, "%s()\n", __func__);
 
        if (priv->cfg->tuner_callback) {
-               ret = priv->cfg->tuner_callback(priv->cfg->priv,
+               ret = priv->cfg->tuner_callback(priv->devptr,
                                                XC5000_TUNER_RESET, 0);
                if (ret)
                        printk(KERN_ERR "xc5000: reset failed\n");
@@ -900,9 +900,9 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
        .get_status        = xc5000_get_status
 };
 
-struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c,
-       struct xc5000_config *cfg)
+struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+                                  struct i2c_adapter *i2c,
+                                  struct xc5000_config *cfg, void *devptr)
 {
        struct xc5000_priv *priv = NULL;
        u16 id = 0;
@@ -916,6 +916,7 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
        priv->cfg = cfg;
        priv->bandwidth = BANDWIDTH_6_MHZ;
        priv->i2c = i2c;
+       priv->devptr = devptr;
 
        /* Check if firmware has been loaded. It is possible that another
           instance of the driver has loaded the firmware.
index 0ee80f9d19b8fa8621acb2f919650cc266925ae2..c910715addc97bdac548c89a563e2600ffa11b0e 100644 (file)
@@ -31,29 +31,31 @@ struct xc5000_config {
        u8   i2c_address;
        u32  if_khz;
 
-       /* For each bridge framework, when it attaches either analog or digital,
-        * it has to store a reference back to its _core equivalent structure,
-        * so that it can service the hardware by steering gpio's etc.
-        * Each bridge implementation is different so cast priv accordingly.
-        * The xc5000 driver cares not for this value, other than ensuring
-        * it's passed back to a bridge during tuner_callback().
-        */
-       void *priv;
        int  (*tuner_callback) (void *priv, int command, int arg);
 };
 
 /* xc5000 callback command */
 #define XC5000_TUNER_RESET             0
 
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc5000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
 #if defined(CONFIG_MEDIA_TUNER_XC5000) || \
     (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
 extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
                                          struct i2c_adapter *i2c,
-                                         struct xc5000_config *cfg);
+                                         struct xc5000_config *cfg,
+                                         void *devptr);
 #else
 static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
                                                 struct i2c_adapter *i2c,
-                                                struct xc5000_config *cfg)
+                                                struct xc5000_config *cfg,
+                                                void *devptr)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
index 13b2d19341da72cd5cbdc5c450f70f9518223f6d..ecebfe4745adcadf30e3f2a82d31b00c3b21210e 100644 (file)
@@ -31,6 +31,8 @@ struct xc5000_priv {
        u8  video_standard;
        u8  rf_mode;
        u8  fwloaded;
+
+       void *devptr;
 };
 
 #endif
index 1371b4e4b5f15230fd8025fb01db690c53e0dccd..c86a5f17eca81d6b7ff46b583c3121737f6c56d4 100644 (file)
@@ -337,12 +337,10 @@ int au0828_dvb_register(struct au0828_dev *dev)
                dvb->frontend = dvb_attach(au8522_attach,
                                &hauppauge_hvr950q_config,
                                &dev->i2c_adap);
-               if (dvb->frontend != NULL) {
-                       hauppauge_hvr950q_tunerconfig.priv = dev;
+               if (dvb->frontend != NULL)
                        dvb_attach(xc5000_attach, dvb->frontend,
                                &dev->i2c_adap,
-                               &hauppauge_hvr950q_tunerconfig);
-               }
+                               &hauppauge_hvr950q_tunerconfig, dev);
                break;
        default:
                printk(KERN_WARNING "The frontend of your DVB/ATSC card "
index 47e3f9e035f903bd7b9af66be7b3878d4d13490e..022aa391937a673b7780d16dae2e22cd25e14925 100644 (file)
@@ -384,12 +384,10 @@ static int dvb_register(struct cx23885_tsport *port)
                port->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &hauppauge_hvr1500q_config,
                                                &dev->i2c_bus[0].i2c_adap);
-               if (port->dvb.frontend != NULL) {
-                       hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
+               if (port->dvb.frontend != NULL)
                        dvb_attach(xc5000_attach, port->dvb.frontend,
                                &i2c_bus->i2c_adap,
-                               &hauppauge_hvr1500q_tunerconfig);
-               }
+                               &hauppauge_hvr1500q_tunerconfig, i2c_bus);
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
                i2c_bus = &dev->i2c_bus[1];
index 75e2e58349ef9eca285a1fb37529f65930b5a8ef..d96173ff1dbac4a0096f854cdb0cc8008d4b8f7e 100644 (file)
@@ -816,11 +816,10 @@ static int dvb_register(struct cx8802_dev *dev)
                        /* tuner_config.video_dev must point to
                         * i2c_adap.algo_data
                         */
-                       pinnacle_pctv_hd_800i_tuner_config.priv =
-                                               core->i2c_adap.algo_data;
                        if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
                                        &core->i2c_adap,
-                                       &pinnacle_pctv_hd_800i_tuner_config))
+                                       &pinnacle_pctv_hd_800i_tuner_config,
+                                       core->i2c_adap.algo_data))
                                goto frontend_detach;
                }
                break;
@@ -878,11 +877,10 @@ static int dvb_register(struct cx8802_dev *dev)
                        /* tuner_config.video_dev must point to
                         * i2c_adap.algo_data
                         */
-                       dvico_fusionhdtv7_tuner_config.priv =
-                                               core->i2c_adap.algo_data;
                        if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
                                        &core->i2c_adap,
-                                       &dvico_fusionhdtv7_tuner_config))
+                                       &dvico_fusionhdtv7_tuner_config,
+                                       core->i2c_adap.algo_data))
                                goto frontend_detach;
                }
                break;
index 4ca686fad55786597a2e857f5d13174b2e5074c5..5a75788b92ae11ee72e30682fa27f2cd04a09cd7 100644 (file)
@@ -448,10 +448,10 @@ static void set_type(struct i2c_client *c, unsigned int type,
 
                xc5000_cfg.i2c_address    = t->i2c->addr;
                xc5000_cfg.if_khz         = 5380;
-               xc5000_cfg.priv           = c->adapter->algo_data;
                xc5000_cfg.tuner_callback = t->tuner_callback;
                if (!dvb_attach(xc5000_attach,
-                               &t->fe, t->i2c->adapter, &xc5000_cfg))
+                               &t->fe, t->i2c->adapter, &xc5000_cfg,
+                               c->adapter->algo_data))
                        goto attach_failed;
 
                xc_tuner_ops = &t->fe.ops.tuner_ops;