V4L/DVB (6676): Improve s-code support
authorMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 25 Nov 2007 22:26:36 +0000 (19:26 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Fri, 25 Jan 2008 21:02:58 +0000 (19:02 -0200)
s-code tables are related to IF frequency used for video demodulation.

The s-codes for analog are automatically loaded, according with video standard.
However, for digital, they will depend on the IF of the demoduler chip. IF of
the demoduler.

Before this patch, only a few IF's where possible to use. This patch allows
selecting any IF defined at firmware file.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/tuner-xc2028-types.h
drivers/media/video/tuner-xc2028.c
drivers/media/video/tuner-xc2028.h

index c0dc6ec19f098fde1ca01eeaf32ba200c9135e2b..d0057fbf0ec72e9569a92b30121961663e371e3a 100644 (file)
@@ -82,6 +82,9 @@
 #define INPUT2         (1 << 28)
 #define SCODE          (1 << 29)
 
+/* This flag identifies that the scode table has a new format */
+#define HAS_IF         (1 << 30)
+
 #define SCODE_TYPES    (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
                         LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794|     \
                         DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
index 9743331c895c072ce12c94ef51208c6ac89300c0..cf72f22986a436b901fb6bf3ea9ec9756fda4a96 100644 (file)
@@ -50,6 +50,7 @@ static DEFINE_MUTEX(xc2028_list_mutex);
 struct firmware_description {
        unsigned int  type;
        v4l2_std_id   id;
+       __u16         int_freq;
        unsigned char *ptr;
        unsigned int  size;
 };
@@ -58,6 +59,7 @@ struct firmware_properties {
        unsigned int    type;
        v4l2_std_id     id;
        v4l2_std_id     std_req;
+       __u16           int_freq;
        unsigned int    scode_table;
        int             scode_nr;
 };
@@ -301,6 +303,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
        while (p < endp) {
                __u32 type, size;
                v4l2_std_id id;
+               __u16 int_freq = 0;
 
                n++;
                if (n >= n_array) {
@@ -321,6 +324,11 @@ static int load_all_firmwares(struct dvb_frontend *fe)
                id = le64_to_cpu(*(v4l2_std_id *) p);
                p += sizeof(id);
 
+               if (type & HAS_IF) {
+                       int_freq = le16_to_cpu(*(__u16 *) p);
+                       p += sizeof(int_freq);
+               }
+
                size = le32_to_cpu(*(__u32 *) p);
                p += sizeof(size);
 
@@ -351,6 +359,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
                priv->firm[n].type = type;
                priv->firm[n].id   = id;
                priv->firm[n].size = size;
+               priv->firm[n].int_freq = int_freq;
 
                p += size;
        }
@@ -565,7 +574,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
 }
 
 static int load_scode(struct dvb_frontend *fe, unsigned int type,
-                        v4l2_std_id *id, int scode)
+                        v4l2_std_id *id, __u16 int_freq, int scode)
 {
        struct xc2028_data *priv = fe->tuner_priv;
        int                pos, rc;
@@ -573,17 +582,34 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
 
        tuner_dbg("%s called\n", __FUNCTION__);
 
-       pos = seek_firmware(fe, type, id);
-       if (pos < 0)
-               return pos;
+       if (!int_freq) {
+               pos = seek_firmware(fe, type, id);
+               if (pos < 0)
+                       return pos;
+       } else {
+               for (pos = 0; pos < priv->firm_size; pos++) {
+                       if ((priv->firm[pos].int_freq == int_freq) &&
+                           (type & HAS_IF))
+                               break;
+               }
+               if (pos == priv->firm_size)
+                       return -ENOENT;
+       }
 
        p = priv->firm[pos].ptr;
 
-       /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
-        * has a 2-byte size header in the firmware format. */
-       if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
-           le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
-               return -EINVAL;
+       if (type & HAS_IF) {
+               if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+                       return -EINVAL;
+               p += 12 * scode;
+       } else {
+               /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
+                * has a 2-byte size header in the firmware format. */
+               if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
+                   le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
+                       return -EINVAL;
+               p += 14 * scode + 2;
+       }
 
        tuner_info("Loading SCODE for type=");
        dump_firm_type(priv->firm[pos].type);
@@ -597,7 +623,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
        if (rc < 0)
                return -EIO;
 
-       rc = i2c_send(priv, p + 14 * scode + 2, 12);
+       rc = i2c_send(priv, p, 12);
        if (rc < 0)
                return -EIO;
 
@@ -609,7 +635,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
 }
 
 static int check_firmware(struct dvb_frontend *fe, unsigned int type,
-                         v4l2_std_id std)
+                         v4l2_std_id std, __u16 int_freq)
 {
        struct xc2028_data         *priv = fe->tuner_priv;
        struct firmware_properties new_fw;
@@ -639,6 +665,7 @@ retry:
        new_fw.std_req = std;
        new_fw.scode_table = SCODE | priv->ctrl.scode_table;
        new_fw.scode_nr = 0;
+       new_fw.int_freq = int_freq;
 
        tuner_dbg("checking firmware, user requested type=");
        if (debug) {
@@ -719,8 +746,8 @@ skip_std_specific:
        /* Load SCODE firmware, if exists */
        tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
 
-       rc = load_scode(fe, new_fw.type | new_fw.scode_table,
-                       &new_fw.id, new_fw.scode_nr);
+       rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+                       new_fw.int_freq, new_fw.scode_nr);
 
 check_device:
        if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
@@ -810,9 +837,10 @@ ret:
 #define DIV 15625
 
 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
-                              enum tuner_mode new_mode,
-                              unsigned int type,
-                              v4l2_std_id std)
+                           enum tuner_mode new_mode,
+                           unsigned int type,
+                           v4l2_std_id std,
+                           u16 int_freq)
 {
        struct xc2028_data *priv = fe->tuner_priv;
        int                rc = -EINVAL;
@@ -825,7 +853,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
 
        tuner_dbg("should set frequency %d kHz\n", freq / 1000);
 
-       if (check_firmware(fe, type, std) < 0)
+       if (check_firmware(fe, type, std, int_freq) < 0)
                goto ret;
 
        /* On some cases xc2028 can disable video output, if
@@ -896,7 +924,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
                if (priv->ctrl.input1)
                        type |= INPUT1;
                return generic_set_freq(fe, (625l * p->frequency) / 10,
-                               T_ANALOG_TV, type, 0);
+                               T_ANALOG_TV, type, 0, 0);
        }
 
        /* if std is not defined, choose one */
@@ -911,22 +939,9 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
        p->std |= parse_audio_std_option();
 
        return generic_set_freq(fe, 62500l * p->frequency,
-                               T_ANALOG_TV, type, p->std);
+                               T_ANALOG_TV, type, p->std, 0);
 }
 
-static unsigned int demod_type [] = {
-       [XC3028_FE_DEFAULT]     = 0,
-       [XC3028_FE_LG60]        = LG60,
-       [XC3028_FE_ATI638]      = ATI638,
-       [XC3028_FE_OREN538]     = OREN538,
-       [XC3028_FE_OREN36]      = OREN36,
-       [XC3028_FE_TOYOTA388]   = TOYOTA388,
-       [XC3028_FE_TOYOTA794]   = TOYOTA794,
-       [XC3028_FE_DIBCOM52]    = DIBCOM52,
-       [XC3028_FE_ZARLINK456]  = ZARLINK456,
-       [XC3028_FE_CHINA]       = CHINA,
-};
-
 static int xc2028_set_params(struct dvb_frontend *fe,
                             struct dvb_frontend_parameters *p)
 {
@@ -978,13 +993,12 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                tuner_err("error: bandwidth not supported.\n");
        };
 
-       if (priv->ctrl.demod < 0 || priv->ctrl.demod > ARRAY_SIZE(demod_type))
-               tuner_err("error: demod type invalid. Assuming default.\n");
-       else
-               type |= demod_type[priv->ctrl.demod];
+       /* All S-code tables need a 200kHz shift */
+       if (priv->ctrl.demod)
+               priv->ctrl.demod += 200;
 
        return generic_set_freq(fe, p->frequency,
-                               T_DIGITAL_TV, type, 0);
+                               T_DIGITAL_TV, type, 0, priv->ctrl.demod);
 }
 
 static int xc2028_sleep(struct dvb_frontend *fe)
index 9b4224e2fe53702319ca3a7bbdf2f1be0c0156ae..1fe8b195960c47e76a2526f83b8eac6d477cbc3c 100644 (file)
 
 #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
 
-enum xc2028_demod_types
-{
-       XC3028_FE_DEFAULT = 0,
-       XC3028_FE_LG60,         /* IF = 6.00 MHz */
-       XC3028_FE_ATI638,       /* IF = 6.38 MHz */
-       XC3028_FE_OREN538,      /* IF = 5.38 MHz */
-       XC3028_FE_OREN36,       /* IF = 3.60 MHz */
-       XC3028_FE_TOYOTA388,    /* IF = 3.88 MHz */
-       XC3028_FE_TOYOTA794,    /* IF = 7.94 MHz */
-       XC3028_FE_DIBCOM52,     /* IF = 5.20 MHz */
-       XC3028_FE_ZARLINK456,   /* IF = 4.56 MHz */
-       XC3028_FE_CHINA,        /* IF = 5.20 MHz */
-};
+/*      Dmoduler               IF (kHz) */
+#define        XC3028_FE_DEFAULT       0
+#define XC3028_FE_LG60         6000
+#define        XC3028_FE_ATI638        6380
+#define        XC3028_FE_OREN538       5380
+#define        XC3028_FE_OREN36        3600
+#define        XC3028_FE_TOYOTA388     3880
+#define        XC3028_FE_TOYOTA794     7940
+#define        XC3028_FE_DIBCOM52      5200
+#define        XC3028_FE_ZARLINK456    4560
+#define        XC3028_FE_CHINA         5200
 
 struct xc2028_ctrl {
        char                    *fname;
@@ -32,7 +30,7 @@ struct xc2028_ctrl {
        unsigned int            mts   :1;
        unsigned int            d2633 :1;
        unsigned int            input1:1;
-       enum xc2028_demod_types demod;
+       unsigned int            demod;
 };
 
 struct xc2028_config {
This page took 0.05277 seconds and 5 git commands to generate.