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>
This commit is contained in:
parent
07c87a833e
commit
48723543af
7 changed files with 29 additions and 30 deletions
|
@ -212,7 +212,7 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
|
||||||
dprintk(1, "%s()\n", __func__);
|
dprintk(1, "%s()\n", __func__);
|
||||||
|
|
||||||
if (priv->cfg->tuner_callback) {
|
if (priv->cfg->tuner_callback) {
|
||||||
ret = priv->cfg->tuner_callback(priv->cfg->priv,
|
ret = priv->cfg->tuner_callback(priv->devptr,
|
||||||
XC5000_TUNER_RESET, 0);
|
XC5000_TUNER_RESET, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
printk(KERN_ERR "xc5000: reset failed\n");
|
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
|
.get_status = xc5000_get_status
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
|
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
||||||
struct i2c_adapter *i2c,
|
struct i2c_adapter *i2c,
|
||||||
struct xc5000_config *cfg)
|
struct xc5000_config *cfg, void *devptr)
|
||||||
{
|
{
|
||||||
struct xc5000_priv *priv = NULL;
|
struct xc5000_priv *priv = NULL;
|
||||||
u16 id = 0;
|
u16 id = 0;
|
||||||
|
@ -916,6 +916,7 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
|
||||||
priv->cfg = cfg;
|
priv->cfg = cfg;
|
||||||
priv->bandwidth = BANDWIDTH_6_MHZ;
|
priv->bandwidth = BANDWIDTH_6_MHZ;
|
||||||
priv->i2c = i2c;
|
priv->i2c = i2c;
|
||||||
|
priv->devptr = devptr;
|
||||||
|
|
||||||
/* Check if firmware has been loaded. It is possible that another
|
/* Check if firmware has been loaded. It is possible that another
|
||||||
instance of the driver has loaded the firmware.
|
instance of the driver has loaded the firmware.
|
||||||
|
|
|
@ -31,29 +31,31 @@ struct xc5000_config {
|
||||||
u8 i2c_address;
|
u8 i2c_address;
|
||||||
u32 if_khz;
|
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);
|
int (*tuner_callback) (void *priv, int command, int arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* xc5000 callback command */
|
/* xc5000 callback command */
|
||||||
#define XC5000_TUNER_RESET 0
|
#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) || \
|
#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
|
||||||
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
|
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
|
||||||
extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
|
extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
|
||||||
struct i2c_adapter *i2c,
|
struct i2c_adapter *i2c,
|
||||||
struct xc5000_config *cfg);
|
struct xc5000_config *cfg,
|
||||||
|
void *devptr);
|
||||||
#else
|
#else
|
||||||
static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
|
static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
|
||||||
struct i2c_adapter *i2c,
|
struct i2c_adapter *i2c,
|
||||||
struct xc5000_config *cfg)
|
struct xc5000_config *cfg,
|
||||||
|
void *devptr)
|
||||||
{
|
{
|
||||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -31,6 +31,8 @@ struct xc5000_priv {
|
||||||
u8 video_standard;
|
u8 video_standard;
|
||||||
u8 rf_mode;
|
u8 rf_mode;
|
||||||
u8 fwloaded;
|
u8 fwloaded;
|
||||||
|
|
||||||
|
void *devptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -337,12 +337,10 @@ int au0828_dvb_register(struct au0828_dev *dev)
|
||||||
dvb->frontend = dvb_attach(au8522_attach,
|
dvb->frontend = dvb_attach(au8522_attach,
|
||||||
&hauppauge_hvr950q_config,
|
&hauppauge_hvr950q_config,
|
||||||
&dev->i2c_adap);
|
&dev->i2c_adap);
|
||||||
if (dvb->frontend != NULL) {
|
if (dvb->frontend != NULL)
|
||||||
hauppauge_hvr950q_tunerconfig.priv = dev;
|
|
||||||
dvb_attach(xc5000_attach, dvb->frontend,
|
dvb_attach(xc5000_attach, dvb->frontend,
|
||||||
&dev->i2c_adap,
|
&dev->i2c_adap,
|
||||||
&hauppauge_hvr950q_tunerconfig);
|
&hauppauge_hvr950q_tunerconfig, dev);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
|
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
|
||||||
|
|
|
@ -384,12 +384,10 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||||
port->dvb.frontend = dvb_attach(s5h1409_attach,
|
port->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||||
&hauppauge_hvr1500q_config,
|
&hauppauge_hvr1500q_config,
|
||||||
&dev->i2c_bus[0].i2c_adap);
|
&dev->i2c_bus[0].i2c_adap);
|
||||||
if (port->dvb.frontend != NULL) {
|
if (port->dvb.frontend != NULL)
|
||||||
hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
|
|
||||||
dvb_attach(xc5000_attach, port->dvb.frontend,
|
dvb_attach(xc5000_attach, port->dvb.frontend,
|
||||||
&i2c_bus->i2c_adap,
|
&i2c_bus->i2c_adap,
|
||||||
&hauppauge_hvr1500q_tunerconfig);
|
&hauppauge_hvr1500q_tunerconfig, i2c_bus);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CX23885_BOARD_HAUPPAUGE_HVR1500:
|
case CX23885_BOARD_HAUPPAUGE_HVR1500:
|
||||||
i2c_bus = &dev->i2c_bus[1];
|
i2c_bus = &dev->i2c_bus[1];
|
||||||
|
|
|
@ -816,11 +816,10 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||||
/* tuner_config.video_dev must point to
|
/* tuner_config.video_dev must point to
|
||||||
* i2c_adap.algo_data
|
* i2c_adap.algo_data
|
||||||
*/
|
*/
|
||||||
pinnacle_pctv_hd_800i_tuner_config.priv =
|
|
||||||
core->i2c_adap.algo_data;
|
|
||||||
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
|
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
|
||||||
&core->i2c_adap,
|
&core->i2c_adap,
|
||||||
&pinnacle_pctv_hd_800i_tuner_config))
|
&pinnacle_pctv_hd_800i_tuner_config,
|
||||||
|
core->i2c_adap.algo_data))
|
||||||
goto frontend_detach;
|
goto frontend_detach;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -878,11 +877,10 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||||
/* tuner_config.video_dev must point to
|
/* tuner_config.video_dev must point to
|
||||||
* i2c_adap.algo_data
|
* i2c_adap.algo_data
|
||||||
*/
|
*/
|
||||||
dvico_fusionhdtv7_tuner_config.priv =
|
|
||||||
core->i2c_adap.algo_data;
|
|
||||||
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
|
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
|
||||||
&core->i2c_adap,
|
&core->i2c_adap,
|
||||||
&dvico_fusionhdtv7_tuner_config))
|
&dvico_fusionhdtv7_tuner_config,
|
||||||
|
core->i2c_adap.algo_data))
|
||||||
goto frontend_detach;
|
goto frontend_detach;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -448,10 +448,10 @@ static void set_type(struct i2c_client *c, unsigned int type,
|
||||||
|
|
||||||
xc5000_cfg.i2c_address = t->i2c->addr;
|
xc5000_cfg.i2c_address = t->i2c->addr;
|
||||||
xc5000_cfg.if_khz = 5380;
|
xc5000_cfg.if_khz = 5380;
|
||||||
xc5000_cfg.priv = c->adapter->algo_data;
|
|
||||||
xc5000_cfg.tuner_callback = t->tuner_callback;
|
xc5000_cfg.tuner_callback = t->tuner_callback;
|
||||||
if (!dvb_attach(xc5000_attach,
|
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;
|
goto attach_failed;
|
||||||
|
|
||||||
xc_tuner_ops = &t->fe.ops.tuner_ops;
|
xc_tuner_ops = &t->fe.ops.tuner_ops;
|
||||||
|
|
Loading…
Add table
Reference in a new issue