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

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

V4L/DVB (7944): tuner-xc2028: use hybrid_tuner_request_state



Use a standard method to manage multiple instances of a hybrid tuner.

Signed-off-by: default avatarMichael Krufky <mkrufky@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 9adea1c0
Loading
Loading
Loading
Loading
+41 −46
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
				"default firmware name\n");

static LIST_HEAD(xc2028_list);
static LIST_HEAD(hybrid_tuner_instance_list);
static DEFINE_MUTEX(xc2028_list_mutex);

/* struct for storing firmware table */
@@ -68,12 +68,11 @@ struct firmware_properties {
};

struct xc2028_data {
	struct list_head        xc2028_list;
	struct list_head        hybrid_tuner_instance_list;
	struct tuner_i2c_props  i2c_props;
	int                     (*tuner_callback) (void *dev,
						   int command, int arg);
	void			*video_dev;
	int			count;
	__u32			frequency;

	struct firmware_description *firm;
@@ -1072,20 +1071,19 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)

	mutex_lock(&xc2028_list_mutex);

	priv->count--;

	if (!priv->count) {
		list_del(&priv->xc2028_list);

	/* only perform final cleanup if this is the last instance */
	if (hybrid_tuner_report_instance_count(priv) == 1) {
		kfree(priv->ctrl.fname);

		free_firmware(priv);
		kfree(priv);
		fe->tuner_priv = NULL;
	}

	if (priv)
		hybrid_tuner_release_state(priv);

	mutex_unlock(&xc2028_list_mutex);

	fe->tuner_priv = NULL;

	return 0;
}

@@ -1150,7 +1148,7 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
				   struct xc2028_config *cfg)
{
	struct xc2028_data *priv;
	void               *video_dev;
	int instance;

	if (debug)
		printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
@@ -1163,48 +1161,40 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
		return NULL;
	}

	video_dev = cfg->i2c_adap->algo_data;

	if (debug)
		printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev);

	mutex_lock(&xc2028_list_mutex);

	list_for_each_entry(priv, &xc2028_list, xc2028_list) {
		if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) {
			video_dev = NULL;
			if (debug)
				printk(KERN_DEBUG "xc2028: reusing device\n");

	instance = hybrid_tuner_request_state(struct xc2028_data, priv,
					      hybrid_tuner_instance_list,
					      cfg->i2c_adap, cfg->i2c_addr,
					      "xc2028");
	switch (instance) {
	case 0:
		/* memory allocation failure */
		goto fail;
		break;
		}
	}

	if (video_dev) {
		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
		if (priv == NULL) {
			mutex_unlock(&xc2028_list_mutex);
			return NULL;
		}

		priv->i2c_props.addr = cfg->i2c_addr;
		priv->i2c_props.adap = cfg->i2c_adap;
		priv->i2c_props.name = "xc2028";

		priv->video_dev = video_dev;
	case 1:
		/* new tuner instance */
		priv->tuner_callback = cfg->callback;
		priv->ctrl.max_len = 13;

		mutex_init(&priv->lock);

		list_add_tail(&priv->xc2028_list, &xc2028_list);
	}
		/* analog side (tuner-core) uses i2c_adap->algo_data.
		 * digital side is not guaranteed to have algo_data defined.
		 *
		 * digital side will always have fe->dvb defined.
		 * analog side (tuner-core) doesn't (yet) define fe->dvb.
		 */
		priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ?
				   fe->dvb->priv : cfg->i2c_adap->algo_data;

		fe->tuner_priv = priv;
	priv->count++;

	if (debug)
		printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count);
		break;
	case 2:
		/* existing tuner instance */
		fe->tuner_priv = priv;
		break;
	}

	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
	       sizeof(xc2028_dvb_tuner_ops));
@@ -1217,6 +1207,11 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
	mutex_unlock(&xc2028_list_mutex);

	return fe;
fail:
	mutex_unlock(&xc2028_list_mutex);

	xc2028_dvb_release(fe);
	return NULL;
}

EXPORT_SYMBOL(xc2028_attach);