V4L/DVB (6986): tda18271: share state between analog and digital tuner instances
authorMichael Krufky <mkrufky@linuxtv.org>
Sun, 6 Jan 2008 18:52:56 +0000 (15:52 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Fri, 25 Jan 2008 21:04:43 +0000 (19:04 -0200)
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/dvb/frontends/tda18271-fe.c
drivers/media/dvb/frontends/tda18271-priv.h
drivers/media/video/tda8290.c

index e860f4c009c212105c5beb8c1116ca8fbf0826a1..aa93e155062793be0981661cc1464d91af947279 100644 (file)
@@ -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;
 }
index af89cfab006607866a13aa4cffe665235b4ad901..5c04d63ae84923e227e856c4afdb7c3122d70877 100644 (file)
@@ -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;
 
index eab530708a49751ecbf6a555b8f570b7d3b827c1..4ac7c04388966ddbdb1b924048b788d99ac9daeb 100644 (file)
@@ -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;