]> err.no Git - linux-2.6/blobdiff - drivers/media/video/tuner-core.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[linux-2.6] / drivers / media / video / tuner-core.c
index 695f39ebe77ba8416b3a86211de0ea940f2fef40..78a09a2a4857b94028e7eadbbecb37dea0c91908 100644 (file)
@@ -20,7 +20,6 @@
 #include <media/tuner-types.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-i2c-drv-legacy.h>
-#include "tuner-driver.h"
 #include "mt20xx.h"
 #include "tda8290.h"
 #include "tea5761.h"
 #include "tuner-xc2028.h"
 #include "tuner-simple.h"
 #include "tda9887.h"
+#include "xc5000.h"
 
 #define UNSET (-1U)
 
 #define PREFIX t->i2c->driver->driver.name
 
+struct tuner {
+       /* device */
+       struct dvb_frontend fe;
+       struct i2c_client   *i2c;
+       struct list_head    list;
+       unsigned int        using_v4l2:1;
+
+       /* keep track of the current settings */
+       v4l2_std_id         std;
+       unsigned int        tv_freq;
+       unsigned int        radio_freq;
+       unsigned int        audmode;
+
+       unsigned int        mode;
+       unsigned int        mode_mask; /* Combination of allowable modes */
+
+       unsigned int        type; /* chip type id */
+       unsigned int        config;
+       int (*tuner_callback) (void *dev, int command, int arg);
+};
+
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
 #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
@@ -123,8 +144,6 @@ static void fe_release(struct dvb_frontend *fe)
        if (fe->ops.tuner_ops.release)
                fe->ops.tuner_ops.release(fe);
 
-       fe->ops.analog_demod_ops = NULL;
-
        /* DO NOT kfree(fe->analog_demod_priv)
         *
         * If we are in this function, analog_demod_priv contains a pointer
@@ -169,7 +188,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
 
 static void tuner_status(struct dvb_frontend *fe);
 
-static struct analog_tuner_ops tuner_core_ops = {
+static struct analog_demod_ops tuner_core_ops = {
        .set_params     = fe_set_params,
        .standby        = fe_standby,
        .release        = fe_release,
@@ -182,7 +201,7 @@ static struct analog_tuner_ops tuner_core_ops = {
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        struct analog_parameters params = {
                .mode      = t->mode,
@@ -194,7 +213,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if ((NULL == ops) || (NULL == ops->set_params)) {
+       if (NULL == analog_ops->set_params) {
                tuner_warn ("Tuner has no way to set tv freq\n");
                return;
        }
@@ -211,13 +230,13 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
        }
        params.frequency = freq;
 
-       ops->set_params(&t->fe, &params);
+       analog_ops->set_params(&t->fe, &params);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        struct analog_parameters params = {
                .mode      = t->mode,
@@ -229,7 +248,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
                tuner_warn ("tuner type not set\n");
                return;
        }
-       if ((NULL == ops) || (NULL == ops->set_params)) {
+       if (NULL == analog_ops->set_params) {
                tuner_warn ("tuner has no way to set radio frequency\n");
                return;
        }
@@ -246,7 +265,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
        }
        params.frequency = freq;
 
-       ops->set_params(&t->fe, &params);
+       analog_ops->set_params(&t->fe, &params);
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -278,6 +297,12 @@ static void tuner_i2c_address_check(struct tuner *t)
            ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
                return;
 
+       /* We already know that the XC5000 can only be located at
+        * i2c address 0x61, 0x62, 0x63 or 0x64 */
+       if ((t->type == TUNER_XC5000) &&
+           ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
+               return;
+
        tuner_warn("====================== WARNING! ======================\n");
        tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
        tuner_warn("will soon be dropped. This message indicates that your\n");
@@ -311,13 +336,15 @@ static void attach_tda829x(struct tuner *t)
        tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
 }
 
+static struct xc5000_config xc5000_cfg;
+
 static void set_type(struct i2c_client *c, unsigned int type,
                     unsigned int new_mode_mask, unsigned int new_config,
                     int (*tuner_callback) (void *dev, int command,int arg))
 {
        struct tuner *t = i2c_get_clientdata(c);
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-       struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
        unsigned char buffer[4];
 
        if (type == UNSET || type == TUNER_ABSENT) {
@@ -344,8 +371,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
        }
 
        /* discard private data, in case set_type() was previously called */
-       if (ops && ops->release)
-               ops->release(&t->fe);
+       if (analog_ops->release)
+               analog_ops->release(&t->fe);
 
        switch (t->type) {
        case TUNER_MT2032:
@@ -408,24 +435,40 @@ static void set_type(struct i2c_client *c, unsigned int type,
                break;
        }
        case TUNER_TDA9887:
-               tda9887_attach(t);
+               tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+               break;
+       case TUNER_XC5000:
+               xc5000_cfg.i2c_address    = t->i2c->addr;
+               xc5000_cfg.if_khz         = 5380;
+               xc5000_cfg.priv           = c->adapter->algo_data;
+               xc5000_cfg.tuner_callback = t->tuner_callback;
+               if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
+                       t->type = TUNER_ABSENT;
+                       t->mode_mask = T_UNINITIALIZED;
+                       return;
+               }
+               {
+               struct dvb_tuner_ops *xc_tuner_ops;
+               xc_tuner_ops = &t->fe.ops.tuner_ops;
+               if(xc_tuner_ops->init != NULL)
+                       xc_tuner_ops->init(&t->fe);
+               }
                break;
        default:
                attach_simple_tuner(t);
                break;
        }
 
-       ops = t->fe.ops.analog_demod_ops;
-
-       if (((NULL == ops) || (NULL == ops->set_params)) &&
+       if ((NULL == analog_ops->set_params) &&
            (fe_tuner_ops->set_analog_params)) {
                strlcpy(t->i2c->name, fe_tuner_ops->info.name,
                        sizeof(t->i2c->name));
 
-               t->fe.ops.analog_demod_ops = &tuner_core_ops;
                t->fe.analog_demod_priv = t;
+               memcpy(analog_ops, &tuner_core_ops,
+                      sizeof(struct analog_demod_ops));
        } else {
-               strlcpy(t->i2c->name, ops->info.name,
+               strlcpy(t->i2c->name, analog_ops->info.name,
                        sizeof(t->i2c->name));
        }
 
@@ -604,7 +647,7 @@ static void tuner_status(struct dvb_frontend *fe)
        struct tuner *t = fe->analog_demod_priv;
        unsigned long freq, freq_fraction;
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-       struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
        const char *p;
 
        switch (t->mode) {
@@ -634,14 +677,12 @@ static void tuner_status(struct dvb_frontend *fe)
                if (tuner_status & TUNER_STATUS_STEREO)
                        tuner_info("Stereo:          yes\n");
        }
-       if (ops) {
-               if (ops->has_signal)
-                       tuner_info("Signal strength: %d\n",
-                                  ops->has_signal(fe));
-               if (ops->is_stereo)
-                       tuner_info("Stereo:          %s\n",
-                                  ops->is_stereo(fe) ? "yes" : "no");
-       }
+       if (analog_ops->has_signal)
+               tuner_info("Signal strength: %d\n",
+                          analog_ops->has_signal(fe));
+       if (analog_ops->is_stereo)
+               tuner_info("Stereo:          %s\n",
+                          analog_ops->is_stereo(fe) ? "yes" : "no");
 }
 
 /* ---------------------------------------------------------------------- */
@@ -655,7 +696,7 @@ static void tuner_status(struct dvb_frontend *fe)
 
 static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
 {
-       struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        if (mode == t->mode)
                return 0;
@@ -664,8 +705,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
 
        if (check_mode(t, cmd) == EINVAL) {
                t->mode = T_STANDBY;
-               if (ops && ops->standby)
-                       ops->standby(&t->fe);
+               if (analog_ops->standby)
+                       analog_ops->standby(&t->fe);
                return EINVAL;
        }
        return 0;
@@ -688,7 +729,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct tuner *t = i2c_get_clientdata(client);
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-       struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        if (tuner_debug>1)
                v4l_i2c_print_ioctl(client,cmd);
@@ -715,8 +756,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
                        return 0;
                t->mode = T_STANDBY;
-               if (ops && ops->standby)
-                       ops->standby(&t->fe);
+               if (analog_ops->standby)
+                       analog_ops->standby(&t->fe);
                break;
 #ifdef CONFIG_VIDEO_V4L1
        case VIDIOCSAUDIO:
@@ -784,8 +825,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                        else
                                                vt->flags &= ~VIDEO_TUNER_STEREO_ON;
                                } else {
-                                       if (ops && ops->is_stereo) {
-                                               if (ops->is_stereo(&t->fe))
+                                       if (analog_ops->is_stereo) {
+                                               if (analog_ops->is_stereo(&t->fe))
                                                        vt->flags |=
                                                                VIDEO_TUNER_STEREO_ON;
                                                else
@@ -793,8 +834,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                                                ~VIDEO_TUNER_STEREO_ON;
                                        }
                                }
-                               if (ops && ops->has_signal)
-                                       vt->signal = ops->has_signal(&t->fe);
+                               if (analog_ops->has_signal)
+                                       vt->signal =
+                                               analog_ops->has_signal(&t->fe);
 
                                vt->flags |= VIDEO_TUNER_LOW;   /* Allow freqs at 62.5 Hz */
 
@@ -824,8 +866,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                        fe_tuner_ops->get_status(&t->fe, &tuner_status);
                                        va->mode = (tuner_status & TUNER_STATUS_STEREO)
                                            ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
-                               } else if (ops && ops->is_stereo)
-                                       va->mode = ops->is_stereo(&t->fe)
+                               } else if (analog_ops->is_stereo)
+                                       va->mode = analog_ops->is_stereo(&t->fe)
                                            ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
                        }
                        return 0;
@@ -833,19 +875,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 #endif
        case TUNER_SET_CONFIG:
        {
-               struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
                struct v4l2_priv_tun_config *cfg = arg;
 
                if (t->type != cfg->tuner)
                        break;
 
-               if ((NULL == ops) || (NULL == ops->set_config)) {
-                       tuner_warn("Tuner frontend module has no way to "
-                                  "set config\n");
+               if (analog_ops->set_config) {
+                       analog_ops->set_config(&t->fe, cfg->priv);
                        break;
                }
 
-               ops->set_config(&t->fe, cfg->priv);
+               tuner_dbg("Tuner frontend module has no way to set config\n");
                break;
        }
        /* --- v4l ioctls --- */
@@ -909,8 +949,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        switch_v4l2();
 
                        tuner->type = t->mode;
-                       if (ops && ops->get_afc)
-                               tuner->afc = ops->get_afc(&t->fe);
+                       if (analog_ops->get_afc)
+                               tuner->afc = analog_ops->get_afc(&t->fe);
                        if (t->mode == V4L2_TUNER_ANALOG_TV)
                                tuner->capability |= V4L2_TUNER_CAP_NORM;
                        if (t->mode != V4L2_TUNER_RADIO) {
@@ -931,15 +971,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                        V4L2_TUNER_SUB_STEREO :
                                        V4L2_TUNER_SUB_MONO;
                        } else {
-                               if (ops && ops->is_stereo) {
+                               if (analog_ops->is_stereo) {
                                        tuner->rxsubchans =
-                                               ops->is_stereo(&t->fe) ?
+                                               analog_ops->is_stereo(&t->fe) ?
                                                V4L2_TUNER_SUB_STEREO :
                                                V4L2_TUNER_SUB_MONO;
                                }
                        }
-                       if (ops && ops->has_signal)
-                               tuner->signal = ops->has_signal(&t->fe);
+                       if (analog_ops->has_signal)
+                               tuner->signal = analog_ops->has_signal(&t->fe);
                        tuner->capability |=
                            V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
                        tuner->audmode = t->audmode;
@@ -964,8 +1004,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
        case VIDIOC_LOG_STATUS:
-               if (ops && ops->tuner_status)
-                       ops->tuner_status(&t->fe);
+               if (analog_ops->tuner_status)
+                       analog_ops->tuner_status(&t->fe);
                break;
        }
 
@@ -998,7 +1038,7 @@ static int tuner_resume(struct i2c_client *c)
 
 /* ---------------------------------------------------------------------- */
 
-LIST_HEAD(tuner_list);
+static LIST_HEAD(tuner_list);
 
 /* Search for existing radio and/or TV tuners on the given I2C adapter.
    Note that when this function is called from tuner_probe you can be
@@ -1194,10 +1234,10 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
 static int tuner_remove(struct i2c_client *client)
 {
        struct tuner *t = i2c_get_clientdata(client);
-       struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
-       if (ops && ops->release)
-               ops->release(&t->fe);
+       if (analog_ops->release)
+               analog_ops->release(&t->fe);
 
        list_del(&t->list);
        kfree(t);