Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-drm-fsl-dcu.git] / drivers / net / wireless / libertas / if_cs.c
index 9c298396be50b7fe5d0d6f8c6b102ecef441b3f7..e213a5dc049dc634b0daf4198f03ca027fd42be4 100644 (file)
@@ -48,7 +48,6 @@
 MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
 MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("libertas_cs_helper.fw");
 
 
 
@@ -61,9 +60,34 @@ struct if_cs_card {
        struct lbs_private *priv;
        void __iomem *iobase;
        bool align_regs;
+       u32 model;
 };
 
 
+enum {
+       MODEL_UNKNOWN = 0x00,
+       MODEL_8305 = 0x01,
+       MODEL_8381 = 0x02,
+       MODEL_8385 = 0x03
+};
+
+static const struct lbs_fw_table fw_table[] = {
+       { MODEL_8305, "libertas/cf8305.bin", NULL },
+       { MODEL_8305, "libertas_cs_helper.fw", NULL },
+       { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
+       { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
+       { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
+       { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
+       { 0, NULL, NULL }
+};
+MODULE_FIRMWARE("libertas/cf8305.bin");
+MODULE_FIRMWARE("libertas/cf8381_helper.bin");
+MODULE_FIRMWARE("libertas/cf8381.bin");
+MODULE_FIRMWARE("libertas/cf8385_helper.bin");
+MODULE_FIRMWARE("libertas/cf8385.bin");
+MODULE_FIRMWARE("libertas_cs_helper.fw");
+MODULE_FIRMWARE("libertas_cs.fw");
+
 
 /********************************************************************/
 /* Hardware access                                                  */
@@ -289,22 +313,19 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
 #define CF8385_MANFID          0x02df
 #define CF8385_CARDID          0x8103
 
-static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev)
-{
-       return (p_dev->manf_id == CF8305_MANFID &&
-               p_dev->card_id == CF8305_CARDID);
-}
-
-static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev)
-{
-       return (p_dev->manf_id == CF8381_MANFID &&
-               p_dev->card_id == CF8381_CARDID);
-}
-
-static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev)
+/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
+ * that gets fixed.  Currently there's no way to access it from the probe hook.
+ */
+static inline u32 get_model(u16 manf_id, u16 card_id)
 {
-       return (p_dev->manf_id == CF8385_MANFID &&
-               p_dev->card_id == CF8385_CARDID);
+       /* NOTE: keep in sync with if_cs_ids */
+       if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
+               return MODEL_8305;
+       else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
+               return MODEL_8381;
+       else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
+               return MODEL_8385;
+       return MODEL_UNKNOWN;
 }
 
 /********************************************************************/
@@ -558,12 +579,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
  *
  * Return 0 on success
  */
-static int if_cs_prog_helper(struct if_cs_card *card)
+static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
 {
        int ret = 0;
        int sent = 0;
        u8  scratch;
-       const struct firmware *fw;
 
        lbs_deb_enter(LBS_DEB_CS);
 
@@ -589,14 +609,6 @@ static int if_cs_prog_helper(struct if_cs_card *card)
                goto done;
        }
 
-       /* TODO: make firmware file configurable */
-       ret = request_firmware(&fw, "libertas_cs_helper.fw",
-               &card->p_dev->dev);
-       if (ret) {
-               lbs_pr_err("can't load helper firmware\n");
-               ret = -ENODEV;
-               goto done;
-       }
        lbs_deb_cs("helper size %td\n", fw->size);
 
        /* "Set the 5 bytes of the helper image to 0" */
@@ -635,7 +647,7 @@ static int if_cs_prog_helper(struct if_cs_card *card)
                if (ret < 0) {
                        lbs_pr_err("can't download helper at 0x%x, ret %d\n",
                                sent, ret);
-                       goto err_release;
+                       goto done;
                }
 
                if (count == 0)
@@ -644,17 +656,14 @@ static int if_cs_prog_helper(struct if_cs_card *card)
                sent += count;
        }
 
-err_release:
-       release_firmware(fw);
 done:
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
        return ret;
 }
 
 
-static int if_cs_prog_real(struct if_cs_card *card)
+static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
 {
-       const struct firmware *fw;
        int ret = 0;
        int retry = 0;
        int len = 0;
@@ -662,21 +671,13 @@ static int if_cs_prog_real(struct if_cs_card *card)
 
        lbs_deb_enter(LBS_DEB_CS);
 
-       /* TODO: make firmware file configurable */
-       ret = request_firmware(&fw, "libertas_cs.fw",
-               &card->p_dev->dev);
-       if (ret) {
-               lbs_pr_err("can't load firmware\n");
-               ret = -ENODEV;
-               goto done;
-       }
        lbs_deb_cs("fw size %td\n", fw->size);
 
        ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
                IF_CS_SQ_HELPER_OK);
        if (ret < 0) {
                lbs_pr_err("helper firmware doesn't answer\n");
-               goto err_release;
+               goto done;
        }
 
        for (sent = 0; sent < fw->size; sent += len) {
@@ -691,7 +692,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
                if (retry > 20) {
                        lbs_pr_err("could not download firmware\n");
                        ret = -ENODEV;
-                       goto err_release;
+                       goto done;
                }
                if (retry) {
                        sent -= len;
@@ -710,7 +711,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
                        IF_CS_BIT_COMMAND);
                if (ret < 0) {
                        lbs_pr_err("can't download firmware at 0x%x\n", sent);
-                       goto err_release;
+                       goto done;
                }
        }
 
@@ -718,9 +719,6 @@ static int if_cs_prog_real(struct if_cs_card *card)
        if (ret < 0)
                lbs_pr_err("firmware download failed\n");
 
-err_release:
-       release_firmware(fw);
-
 done:
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
        return ret;
@@ -824,6 +822,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
        unsigned int prod_id;
        struct lbs_private *priv;
        struct if_cs_card *card;
+       const struct firmware *helper = NULL;
+       const struct firmware *mainfw = NULL;
 
        lbs_deb_enter(LBS_DEB_CS);
 
@@ -843,7 +843,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
                goto out1;
        }
 
-
        /*
         * Allocate an interrupt line.  Note that this does not assign
         * a handler to the interrupt, unless the 'Handler' member of
@@ -881,34 +880,47 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
         */
        card->align_regs = 0;
 
+       card->model = get_model(p_dev->manf_id, p_dev->card_id);
+       if (card->model == MODEL_UNKNOWN) {
+               lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
+                          p_dev->manf_id, p_dev->card_id);
+               goto out2;
+       }
+
        /* Check if we have a current silicon */
        prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
-       if (if_cs_hw_is_cf8305(p_dev)) {
+       if (card->model == MODEL_8305) {
                card->align_regs = 1;
                if (prod_id < IF_CS_CF8305_B1_REV) {
-                       lbs_pr_err("old chips like 8305 rev B3 "
-                               "aren't supported\n");
+                       lbs_pr_err("8305 rev B0 and older are not supported\n");
                        ret = -ENODEV;
                        goto out2;
                }
        }
 
-       if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) {
-               lbs_pr_err("old chips like 8381 rev B3 aren't supported\n");
+       if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
+               lbs_pr_err("8381 rev B2 and older are not supported\n");
                ret = -ENODEV;
                goto out2;
        }
 
-       if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) {
-               lbs_pr_err("old chips like 8385 rev B1 aren't supported\n");
+       if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
+               lbs_pr_err("8385 rev B0 and older are not supported\n");
                ret = -ENODEV;
                goto out2;
        }
 
+       ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
+                               &fw_table[0], &helper, &mainfw);
+       if (ret) {
+               lbs_pr_err("failed to find firmware (%d)\n", ret);
+               goto out2;
+       }
+
        /* Load the firmware early, before calling into libertas.ko */
-       ret = if_cs_prog_helper(card);
-       if (ret == 0 && !if_cs_hw_is_cf8305(p_dev))
-               ret = if_cs_prog_real(card);
+       ret = if_cs_prog_helper(card, helper);
+       if (ret == 0 && (card->model != MODEL_8305))
+               ret = if_cs_prog_real(card, mainfw);
        if (ret)
                goto out2;
 
@@ -957,6 +969,11 @@ out2:
 out1:
        pcmcia_disable_device(p_dev);
 out:
+       if (helper)
+               release_firmware(helper);
+       if (mainfw)
+               release_firmware(mainfw);
+
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
        return ret;
 }
@@ -993,6 +1010,7 @@ static struct pcmcia_device_id if_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
+       /* NOTE: keep in sync with get_model() */
        PCMCIA_DEVICE_NULL,
 };
 MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);