V4L/DVB (7893): xc5000: bug-fix: allow multiple devices in a single system

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>

authored by Michael Krufky and committed by Mauro Carvalho Chehab 48723543 07c87a83

+29 -30
+5 -4
drivers/media/common/tuners/xc5000.c
··· 212 dprintk(1, "%s()\n", __func__); 213 214 if (priv->cfg->tuner_callback) { 215 - ret = priv->cfg->tuner_callback(priv->cfg->priv, 216 XC5000_TUNER_RESET, 0); 217 if (ret) 218 printk(KERN_ERR "xc5000: reset failed\n"); ··· 900 .get_status = xc5000_get_status 901 }; 902 903 - struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, 904 - struct i2c_adapter *i2c, 905 - struct xc5000_config *cfg) 906 { 907 struct xc5000_priv *priv = NULL; 908 u16 id = 0; ··· 916 priv->cfg = cfg; 917 priv->bandwidth = BANDWIDTH_6_MHZ; 918 priv->i2c = i2c; 919 920 /* Check if firmware has been loaded. It is possible that another 921 instance of the driver has loaded the firmware.
··· 212 dprintk(1, "%s()\n", __func__); 213 214 if (priv->cfg->tuner_callback) { 215 + ret = priv->cfg->tuner_callback(priv->devptr, 216 XC5000_TUNER_RESET, 0); 217 if (ret) 218 printk(KERN_ERR "xc5000: reset failed\n"); ··· 900 .get_status = xc5000_get_status 901 }; 902 903 + struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, 904 + struct i2c_adapter *i2c, 905 + struct xc5000_config *cfg, void *devptr) 906 { 907 struct xc5000_priv *priv = NULL; 908 u16 id = 0; ··· 916 priv->cfg = cfg; 917 priv->bandwidth = BANDWIDTH_6_MHZ; 918 priv->i2c = i2c; 919 + priv->devptr = devptr; 920 921 /* Check if firmware has been loaded. It is possible that another 922 instance of the driver has loaded the firmware.
+12 -10
drivers/media/common/tuners/xc5000.h
··· 31 u8 i2c_address; 32 u32 if_khz; 33 34 - /* For each bridge framework, when it attaches either analog or digital, 35 - * it has to store a reference back to its _core equivalent structure, 36 - * so that it can service the hardware by steering gpio's etc. 37 - * Each bridge implementation is different so cast priv accordingly. 38 - * The xc5000 driver cares not for this value, other than ensuring 39 - * it's passed back to a bridge during tuner_callback(). 40 - */ 41 - void *priv; 42 int (*tuner_callback) (void *priv, int command, int arg); 43 }; 44 45 /* xc5000 callback command */ 46 #define XC5000_TUNER_RESET 0 47 48 #if defined(CONFIG_MEDIA_TUNER_XC5000) || \ 49 (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) 50 extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, 51 struct i2c_adapter *i2c, 52 - struct xc5000_config *cfg); 53 #else 54 static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, 55 struct i2c_adapter *i2c, 56 - struct xc5000_config *cfg) 57 { 58 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); 59 return NULL;
··· 31 u8 i2c_address; 32 u32 if_khz; 33 34 int (*tuner_callback) (void *priv, int command, int arg); 35 }; 36 37 /* xc5000 callback command */ 38 #define XC5000_TUNER_RESET 0 39 40 + /* For each bridge framework, when it attaches either analog or digital, 41 + * it has to store a reference back to its _core equivalent structure, 42 + * so that it can service the hardware by steering gpio's etc. 43 + * Each bridge implementation is different so cast devptr accordingly. 44 + * The xc5000 driver cares not for this value, other than ensuring 45 + * it's passed back to a bridge during tuner_callback(). 46 + */ 47 + 48 #if defined(CONFIG_MEDIA_TUNER_XC5000) || \ 49 (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) 50 extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, 51 struct i2c_adapter *i2c, 52 + struct xc5000_config *cfg, 53 + void *devptr); 54 #else 55 static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, 56 struct i2c_adapter *i2c, 57 + struct xc5000_config *cfg, 58 + void *devptr) 59 { 60 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); 61 return NULL;
+2
drivers/media/common/tuners/xc5000_priv.h
··· 31 u8 video_standard; 32 u8 rf_mode; 33 u8 fwloaded; 34 }; 35 36 #endif
··· 31 u8 video_standard; 32 u8 rf_mode; 33 u8 fwloaded; 34 + 35 + void *devptr; 36 }; 37 38 #endif
+2 -4
drivers/media/video/au0828/au0828-dvb.c
··· 337 dvb->frontend = dvb_attach(au8522_attach, 338 &hauppauge_hvr950q_config, 339 &dev->i2c_adap); 340 - if (dvb->frontend != NULL) { 341 - hauppauge_hvr950q_tunerconfig.priv = dev; 342 dvb_attach(xc5000_attach, dvb->frontend, 343 &dev->i2c_adap, 344 - &hauppauge_hvr950q_tunerconfig); 345 - } 346 break; 347 default: 348 printk(KERN_WARNING "The frontend of your DVB/ATSC card "
··· 337 dvb->frontend = dvb_attach(au8522_attach, 338 &hauppauge_hvr950q_config, 339 &dev->i2c_adap); 340 + if (dvb->frontend != NULL) 341 dvb_attach(xc5000_attach, dvb->frontend, 342 &dev->i2c_adap, 343 + &hauppauge_hvr950q_tunerconfig, dev); 344 break; 345 default: 346 printk(KERN_WARNING "The frontend of your DVB/ATSC card "
+2 -4
drivers/media/video/cx23885/cx23885-dvb.c
··· 384 port->dvb.frontend = dvb_attach(s5h1409_attach, 385 &hauppauge_hvr1500q_config, 386 &dev->i2c_bus[0].i2c_adap); 387 - if (port->dvb.frontend != NULL) { 388 - hauppauge_hvr1500q_tunerconfig.priv = i2c_bus; 389 dvb_attach(xc5000_attach, port->dvb.frontend, 390 &i2c_bus->i2c_adap, 391 - &hauppauge_hvr1500q_tunerconfig); 392 - } 393 break; 394 case CX23885_BOARD_HAUPPAUGE_HVR1500: 395 i2c_bus = &dev->i2c_bus[1];
··· 384 port->dvb.frontend = dvb_attach(s5h1409_attach, 385 &hauppauge_hvr1500q_config, 386 &dev->i2c_bus[0].i2c_adap); 387 + if (port->dvb.frontend != NULL) 388 dvb_attach(xc5000_attach, port->dvb.frontend, 389 &i2c_bus->i2c_adap, 390 + &hauppauge_hvr1500q_tunerconfig, i2c_bus); 391 break; 392 case CX23885_BOARD_HAUPPAUGE_HVR1500: 393 i2c_bus = &dev->i2c_bus[1];
+4 -6
drivers/media/video/cx88/cx88-dvb.c
··· 816 /* tuner_config.video_dev must point to 817 * i2c_adap.algo_data 818 */ 819 - pinnacle_pctv_hd_800i_tuner_config.priv = 820 - core->i2c_adap.algo_data; 821 if (!dvb_attach(xc5000_attach, dev->dvb.frontend, 822 &core->i2c_adap, 823 - &pinnacle_pctv_hd_800i_tuner_config)) 824 goto frontend_detach; 825 } 826 break; ··· 877 /* tuner_config.video_dev must point to 878 * i2c_adap.algo_data 879 */ 880 - dvico_fusionhdtv7_tuner_config.priv = 881 - core->i2c_adap.algo_data; 882 if (!dvb_attach(xc5000_attach, dev->dvb.frontend, 883 &core->i2c_adap, 884 - &dvico_fusionhdtv7_tuner_config)) 885 goto frontend_detach; 886 } 887 break;
··· 816 /* tuner_config.video_dev must point to 817 * i2c_adap.algo_data 818 */ 819 if (!dvb_attach(xc5000_attach, dev->dvb.frontend, 820 &core->i2c_adap, 821 + &pinnacle_pctv_hd_800i_tuner_config, 822 + core->i2c_adap.algo_data)) 823 goto frontend_detach; 824 } 825 break; ··· 878 /* tuner_config.video_dev must point to 879 * i2c_adap.algo_data 880 */ 881 if (!dvb_attach(xc5000_attach, dev->dvb.frontend, 882 &core->i2c_adap, 883 + &dvico_fusionhdtv7_tuner_config, 884 + core->i2c_adap.algo_data)) 885 goto frontend_detach; 886 } 887 break;
+2 -2
drivers/media/video/tuner-core.c
··· 448 449 xc5000_cfg.i2c_address = t->i2c->addr; 450 xc5000_cfg.if_khz = 5380; 451 - xc5000_cfg.priv = c->adapter->algo_data; 452 xc5000_cfg.tuner_callback = t->tuner_callback; 453 if (!dvb_attach(xc5000_attach, 454 - &t->fe, t->i2c->adapter, &xc5000_cfg)) 455 goto attach_failed; 456 457 xc_tuner_ops = &t->fe.ops.tuner_ops;
··· 448 449 xc5000_cfg.i2c_address = t->i2c->addr; 450 xc5000_cfg.if_khz = 5380; 451 xc5000_cfg.tuner_callback = t->tuner_callback; 452 if (!dvb_attach(xc5000_attach, 453 + &t->fe, t->i2c->adapter, &xc5000_cfg, 454 + c->adapter->algo_data)) 455 goto attach_failed; 456 457 xc_tuner_ops = &t->fe.ops.tuner_ops;