V4L/DVB (9049): convert tuner drivers to use dvb_frontend->callback
[deliverable/linux.git] / drivers / media / common / tuners / tuner-xc2028.c
index 0cbde17bfbb7a7471616112dda6dd5507f21e169..fc82d154c8c2c4a3cdd5de260c104254da5277f7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <media/tuner.h>
 #include <linux/mutex.h>
+#include <asm/unaligned.h>
 #include "tuner-i2c.h"
 #include "tuner-xc2028.h"
 #include "tuner-xc2028-types.h"
@@ -70,9 +71,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 +252,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];
@@ -292,10 +290,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 +322,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 +380,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 +489,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 +544,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 +555,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 +727,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;
 
@@ -930,7 +944,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);
 
@@ -1174,20 +1188,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:
This page took 0.026498 seconds and 5 git commands to generate.