include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / media / common / tuners / tuner-xc2028.c
index 0cbde17..96d6170 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/delay.h>
 #include <media/tuner.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
 #include "tuner-i2c.h"
 #include "tuner-xc2028.h"
 #include "tuner-xc2028-types.h"
@@ -27,6 +29,12 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+       "1 keep device energized and with tuner ready all the times.\n"
+       "  Faster, but consumes more power and keeps the device hotter\n");
+
 static char audio_std[8];
 module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
 MODULE_PARM_DESC(audio_std,
@@ -41,7 +49,7 @@ MODULE_PARM_DESC(audio_std,
        "NICAM/A\n"
        "NICAM/B\n");
 
-static char firmware_name[FIRMWARE_NAME_MAX];
+static char firmware_name[30];
 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");
@@ -70,9 +78,6 @@ struct firmware_properties {
 struct xc2028_data {
        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;
        __u32                   frequency;
 
        struct firmware_description *firm;
@@ -254,7 +259,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
 {
        struct xc2028_data    *priv = fe->tuner_priv;
        const struct firmware *fw   = NULL;
-       unsigned char         *p, *endp;
+       const unsigned char   *p, *endp;
        int                   rc = 0;
        int                   n, n_array;
        char                  name[33];
@@ -268,7 +273,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
                fname = firmware_name;
 
        tuner_dbg("Reading firmware %s\n", fname);
-       rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
+       rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
        if (rc < 0) {
                if (rc == -ENOENT)
                        tuner_err("Error: firmware %s not found.\n",
@@ -292,10 +297,10 @@ static int load_all_firmwares(struct dvb_frontend *fe)
        name[sizeof(name) - 1] = 0;
        p += sizeof(name) - 1;
 
-       priv->firm_version = le16_to_cpu(*(__u16 *) p);
+       priv->firm_version = get_unaligned_le16(p);
        p += 2;
 
-       n_array = le16_to_cpu(*(__u16 *) p);
+       n_array = get_unaligned_le16(p);
        p += 2;
 
        tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
@@ -324,26 +329,26 @@ static int load_all_firmwares(struct dvb_frontend *fe)
                }
 
                /* Checks if there's enough bytes to read */
-               if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
-                       tuner_err("Firmware header is incomplete!\n");
-                       goto corrupt;
-               }
+               if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+                       goto header;
 
-               type = le32_to_cpu(*(__u32 *) p);
+               type = get_unaligned_le32(p);
                p += sizeof(type);
 
-               id = le64_to_cpu(*(v4l2_std_id *) p);
+               id = get_unaligned_le64(p);
                p += sizeof(id);
 
                if (type & HAS_IF) {
-                       int_freq = le16_to_cpu(*(__u16 *) p);
+                       int_freq = get_unaligned_le16(p);
                        p += sizeof(int_freq);
+                       if (endp - p < sizeof(size))
+                               goto header;
                }
 
-               size = le32_to_cpu(*(__u32 *) p);
+               size = get_unaligned_le32(p);
                p += sizeof(size);
 
-               if ((!size) || (size + p > endp)) {
+               if (!size || size > endp - p) {
                        tuner_err("Firmware type ");
                        dump_firm_type(type);
                        printk("(%x), id %llx is corrupted "
@@ -382,6 +387,8 @@ static int load_all_firmwares(struct dvb_frontend *fe)
 
        goto done;
 
+header:
+       tuner_err("Firmware header is incomplete!\n");
 corrupt:
        rc = -EINVAL;
        tuner_err("Error: firmware file is corrupted!\n");
@@ -489,6 +496,23 @@ ret:
        return i;
 }
 
+static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+
+       /* 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.
+        */
+
+       return (!fe->callback) ? -EINVAL :
+               fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+                               fe->dvb->priv : priv->i2c_props.adap->algo_data,
+                            DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
+}
+
 static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                         v4l2_std_id *id)
 {
@@ -527,8 +551,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
 
                if (!size) {
                        /* Special callback command received */
-                       rc = priv->tuner_callback(priv->video_dev,
-                                                 XC2028_TUNER_RESET, 0);
+                       rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
                        if (rc < 0) {
                                tuner_err("Error at RESET code %d\n",
                                           (*p) & 0x7f);
@@ -539,8 +562,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                if (size >= 0xff00) {
                        switch (size) {
                        case 0xff00:
-                               rc = priv->tuner_callback(priv->video_dev,
-                                                       XC2028_RESET_CLK, 0);
+                               rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
                                if (rc < 0) {
                                        tuner_err("Error at RESET code %d\n",
                                                  (*p) & 0x7f);
@@ -712,8 +734,7 @@ retry:
        memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 
        /* Reset is needed before loading firmware */
-       rc = priv->tuner_callback(priv->video_dev,
-                                 XC2028_TUNER_RESET, 0);
+       rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
        if (rc < 0)
                goto fail;
 
@@ -899,21 +920,66 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
         */
        if (new_mode == T_ANALOG_TV) {
                rc = send_seq(priv, {0x00, 0x00});
-       } else if (priv->cur_fw.type & ATSC) {
-               offset = 1750000;
+
+               /* Analog modes require offset = 0 */
        } else {
-               offset = 2750000;
                /*
-                * We must adjust the offset by 500kHz in two cases in order
-                * to correctly center the IF output:
-                * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
-                *    selected and a 7MHz channel is tuned;
-                * 2) When tuning a VHF channel with DTV78 firmware.
+                * Digital modes require an offset to adjust to the
+                * proper frequency. The offset depends on what
+                * firmware version is used.
+                */
+
+               /*
+                * Adjust to the center frequency. This is calculated by the
+                * formula: offset = 1.25MHz - BW/2
+                * For DTV 7/8, the firmware uses BW = 8000, so it needs a
+                * further adjustment to get the frequency center on VHF
                 */
-               if (((priv->cur_fw.type & DTV7) &&
-                    (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
-                   ((priv->cur_fw.type & DTV78) && freq < 470000000))
+               if (priv->cur_fw.type & DTV6)
+                       offset = 1750000;
+               else if (priv->cur_fw.type & DTV7)
+                       offset = 2250000;
+               else    /* DTV8 or DTV78 */
+                       offset = 2750000;
+               if ((priv->cur_fw.type & DTV78) && freq < 470000000)
                        offset -= 500000;
+
+               /*
+                * xc3028 additional "magic"
+                * Depending on the firmware version, it needs some adjustments
+                * to properly centralize the frequency. This seems to be
+                * needed to compensate the SCODE table adjustments made by
+                * newer firmwares
+                */
+
+#if 1
+               /*
+                * The proper adjustment would be to do it at s-code table.
+                * However, this didn't work, as reported by
+                * Robert Lowery <rglowery@exemail.com.au>
+                */
+
+               if (priv->cur_fw.type & DTV7)
+                       offset += 500000;
+
+#else
+               /*
+                * Still need tests for XC3028L (firmware 3.2 or upper)
+                * So, for now, let's just comment the per-firmware
+                * version of this change. Reports with xc3028l working
+                * with and without the lines bellow are welcome
+                */
+
+               if (priv->firm_version < 0x0302) {
+                       if (priv->cur_fw.type & DTV7)
+                               offset += 500000;
+               } else {
+                       if (priv->cur_fw.type & DTV7)
+                               offset -= 300000;
+                       else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
+                               offset += 200000;
+               }
+#endif
        }
 
        div = (freq - offset + DIV / 2) / DIV;
@@ -930,7 +996,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
           The reset CLK is needed only with tm6000.
           Driver should work fine even if this fails.
         */
-       priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
+       do_tuner_callback(fe, XC2028_RESET_CLK, 1);
 
        msleep(10);
 
@@ -971,7 +1037,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, 0);
+                               T_RADIO, type, 0, 0);
        }
 
        /* if std is not defined, choose one */
@@ -999,31 +1065,23 @@ static int xc2028_set_params(struct dvb_frontend *fe,
 
        tuner_dbg("%s called\n", __func__);
 
-       if (priv->ctrl.d2633)
-               type |= D2633;
-       else
-               type |= D2620;
-
        switch(fe->ops.info.type) {
        case FE_OFDM:
                bw = p->u.ofdm.bandwidth;
-               break;
-       case FE_QAM:
-               tuner_info("WARN: There are some reports that "
-                          "QAM 6 MHz doesn't work.\n"
-                          "If this works for you, please report by "
-                          "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
-               bw = BANDWIDTH_6_MHZ;
-               type |= QAM;
+               /*
+                * The only countries with 6MHz seem to be Taiwan/Uruguay.
+                * Both seem to require QAM firmware for OFDM decoding
+                * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
+                */
+               if (bw == BANDWIDTH_6_MHZ)
+                       type |= QAM;
                break;
        case FE_ATSC:
                bw = BANDWIDTH_6_MHZ;
-               /* The only ATSC firmware (at least on v2.7) is D2633,
-                  so overrides ctrl->d2633 */
-               type |= ATSC| D2633;
-               type &= ~D2620;
+               /* The only ATSC firmware (at least on v2.7) is D2633 */
+               type |= ATSC | D2633;
                break;
-       /* DVB-S is not supported */
+       /* DVB-S and pure QAM (FE_QAM) are not supported */
        default:
                return -EINVAL;
        }
@@ -1054,14 +1112,82 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                tuner_err("error: bandwidth not supported.\n");
        };
 
+       /*
+         Selects between D2633 or D2620 firmware.
+         It doesn't make sense for ATSC, since it should be D2633 on all cases
+        */
+       if (fe->ops.info.type != FE_ATSC) {
+               switch (priv->ctrl.type) {
+               case XC2028_D2633:
+                       type |= D2633;
+                       break;
+               case XC2028_D2620:
+                       type |= D2620;
+                       break;
+               case XC2028_AUTO:
+               default:
+                       /* Zarlink seems to need D2633 */
+                       if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
+                               type |= D2633;
+                       else
+                               type |= D2620;
+               }
+       }
+
        /* All S-code tables need a 200kHz shift */
-       if (priv->ctrl.demod)
-               demod = priv->ctrl.demod + 200;
+       if (priv->ctrl.demod) {
+               demod = priv->ctrl.demod;
+
+               /*
+                * Newer firmwares require a 200 kHz offset only for ATSC
+                */
+               if (type == ATSC || priv->firm_version < 0x0302)
+                       demod += 200;
+               /*
+                * The DTV7 S-code table needs a 700 kHz shift.
+                *
+                * DTV7 is only used in Australia.  Germany or Italy may also
+                * use this firmware after initialization, but a tune to a UHF
+                * channel should then cause DTV78 to be used.
+                *
+                * Unfortunately, on real-field tests, the s-code offset
+                * didn't work as expected, as reported by
+                * Robert Lowery <rglowery@exemail.com.au>
+                */
+       }
 
        return generic_set_freq(fe, p->frequency,
                                T_DIGITAL_TV, type, 0, demod);
 }
 
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int rc = 0;
+
+       /* Avoid firmware reload on slow devices or if PM disabled */
+       if (no_poweroff || priv->ctrl.disable_power_mgmt)
+               return 0;
+
+       tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
+       if (debug > 1) {
+               tuner_dbg("Printing sleep stack trace:\n");
+               dump_stack();
+       }
+
+       mutex_lock(&priv->lock);
+
+       if (priv->firm_version < 0x0202)
+               rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+       else
+               rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+
+       priv->cur_fw.type = 0;  /* need firmware reload */
+
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
 
 static int xc2028_dvb_release(struct dvb_frontend *fe)
 {
@@ -1142,6 +1268,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
        .get_frequency     = xc2028_get_frequency,
        .get_rf_strength   = xc2028_signal,
        .set_params        = xc2028_set_params,
+       .sleep             = xc2028_sleep,
 };
 
 struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
@@ -1174,20 +1301,10 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
                break;
        case 1:
                /* new tuner instance */
-               priv->tuner_callback = cfg->callback;
                priv->ctrl.max_len = 13;
 
                mutex_init(&priv->lock);
 
-               /* 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;
                break;
        case 2: