فهرست منبع

V4L/DVB (6986): tda18271: share state between analog and digital tuner instances

Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Michael Krufky 17 سال پیش
والد
کامیت
a4f263b587
3فایلهای تغییر یافته به همراه81 افزوده شده و 24 حذف شده
  1. 71 22
      drivers/media/dvb/frontends/tda18271-fe.c
  2. 3 0
      drivers/media/dvb/frontends/tda18271-priv.h
  3. 7 2
      drivers/media/video/tda8290.c

+ 71 - 22
drivers/media/dvb/frontends/tda18271-fe.c

@@ -27,6 +27,9 @@ module_param_named(debug, tda18271_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level "
 		 "(info=1, map=2, reg=4, adv=8 (or-able))");
 
+static LIST_HEAD(tda18271_list);
+static DEFINE_MUTEX(tda18271_list_mutex);
+
 /*---------------------------------------------------------------------*/
 
 static int tda18271_ir_cal_init(struct dvb_frontend *fe)
@@ -936,8 +939,24 @@ fail:
 
 static int tda18271_release(struct dvb_frontend *fe)
 {
-	kfree(fe->tuner_priv);
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	priv->count--;
+
+	if (!priv->count) {
+		tda_dbg("destroying instance @ %d-%04x\n",
+			i2c_adapter_id(priv->i2c_adap),
+			priv->i2c_addr);
+		list_del(&priv->tda18271_list);
+
+		kfree(priv);
+	}
+	mutex_unlock(&tda18271_list_mutex);
+
 	fe->tuner_priv = NULL;
+
 	return 0;
 }
 
@@ -1071,43 +1090,73 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
 				     struct tda18271_config *cfg)
 {
 	struct tda18271_priv *priv = NULL;
+	int state_found = 0;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	list_for_each_entry(priv, &tda18271_list, tda18271_list) {
+		if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
+		    (priv->i2c_addr == addr)) {
+			tda_dbg("attaching existing tuner @ %d-%04x\n",
+				i2c_adapter_id(priv->i2c_adap),
+				priv->i2c_addr);
+			priv->count++;
+			fe->tuner_priv = priv;
+			state_found = 1;
+			/* allow dvb driver to override i2c gate setting */
+			if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
+				priv->gate = cfg->gate;
+			break;
+		}
+	}
+	if (state_found == 0) {
+		tda_dbg("creating new tuner instance @ %d-%04x\n",
+			i2c_adapter_id(i2c), addr);
+
+		priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
+		if (priv == NULL) {
+			mutex_unlock(&tda18271_list_mutex);
+			return NULL;
+		}
 
-	priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
+		priv->i2c_addr = addr;
+		priv->i2c_adap = i2c;
+		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+		priv->cal_initialized = false;
+		mutex_init(&priv->lock);
+		priv->count++;
 
-	priv->i2c_addr = addr;
-	priv->i2c_adap = i2c;
-	priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
-	priv->cal_initialized = false;
-	mutex_init(&priv->lock);
+		fe->tuner_priv = priv;
 
-	fe->tuner_priv = priv;
+		list_add_tail(&priv->tda18271_list, &tda18271_list);
 
-	if (tda18271_get_id(fe) < 0)
-		goto fail;
+		if (tda18271_get_id(fe) < 0)
+			goto fail;
 
-	if (tda18271_assign_map_layout(fe) < 0)
-		goto fail;
+		if (tda18271_assign_map_layout(fe) < 0)
+			goto fail;
 
-	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
+		mutex_lock(&priv->lock);
+		tda18271_init_regs(fe);
+		mutex_unlock(&priv->lock);
+	}
 
 	/* override default std map with values in config struct */
 	if ((cfg) && (cfg->std_map))
 		tda18271_update_std_map(fe, cfg->std_map);
 
-	if (tda18271_debug & DBG_MAP)
-		tda18271_dump_std_map(fe);
-
-	mutex_lock(&priv->lock);
+	mutex_unlock(&tda18271_list_mutex);
 
-	tda18271_init_regs(fe);
+	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
 
-	mutex_unlock(&priv->lock);
+	if (tda18271_debug & DBG_MAP)
+		tda18271_dump_std_map(fe);
 
 	return fe;
 fail:
+	mutex_unlock(&tda18271_list_mutex);
+
 	tda18271_release(fe);
 	return NULL;
 }

+ 3 - 0
drivers/media/dvb/frontends/tda18271-priv.h

@@ -102,10 +102,13 @@ struct tda18271_priv {
 	struct i2c_adapter *i2c_adap;
 	unsigned char tda18271_regs[TDA18271_NUM_REGS];
 
+	struct list_head tda18271_list;
+
 	enum tda18271_mode mode;
 	enum tda18271_i2c_gate gate;
 	enum tda18271_ver id;
 
+	unsigned int count;
 	unsigned int tm_rfcal;
 	unsigned int cal_initialized:1;
 

+ 7 - 2
drivers/media/video/tda8290.c

@@ -502,8 +502,13 @@ static void tda8290_init_tuner(struct dvb_frontend *fe)
 
 static void tda829x_release(struct dvb_frontend *fe)
 {
-	if (fe->ops.tuner_ops.release)
-		fe->ops.tuner_ops.release(fe);
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	/* dont try to release the tuner
+	 * if we didn't attach it from this module */
+	if ((priv->ver > TDA8290) && (priv->ver > TDA8295))
+		if (fe->ops.tuner_ops.release)
+			fe->ops.tuner_ops.release(fe);
 
 	kfree(fe->analog_demod_priv);
 	fe->analog_demod_priv = NULL;