Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 48723543 authored by Michael Krufky's avatar Michael Krufky Committed by Mauro Carvalho Chehab
Browse files

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: default avatarMichael Krufky <mkrufky@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 07c87a83
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -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");
@@ -902,7 +902,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {

struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
				   struct i2c_adapter *i2c,
	struct xc5000_config *cfg)
				   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.
+12 −10
Original line number Diff line number Diff line
@@ -31,29 +31,31 @@ struct xc5000_config {
	u8   i2c_address;
	u32  if_khz;

	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 priv accordingly.
 * 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().
 */
	void *priv;
	int  (*tuner_callback) (void *priv, int command, int arg);
};

/* xc5000 callback command */
#define XC5000_TUNER_RESET		0

#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;
+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ struct xc5000_priv {
	u8  video_standard;
	u8  rf_mode;
	u8  fwloaded;

	void *devptr;
};

#endif
+2 −4
Original line number Diff line number Diff line
@@ -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 "
+2 −4
Original line number Diff line number Diff line
@@ -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];
Loading