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>
        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");
        .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;
        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.
 
        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;
 
        u8  video_standard;
        u8  rf_mode;
        u8  fwloaded;
+
+       void *devptr;
 };
 
 #endif
 
                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 "
 
                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];
 
                        /* 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;
                        /* 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;
 
 
                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;