diff options
Diffstat (limited to 'drivers/net/wireless/libertas/if_cs.c')
-rw-r--r-- | drivers/net/wireless/libertas/if_cs.c | 130 |
1 files changed, 74 insertions, 56 deletions
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 9c298396be50..e213a5dc049d 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c | |||
@@ -48,7 +48,6 @@ | |||
48 | MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>"); | 48 | MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>"); |
49 | MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); | 49 | MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); |
50 | MODULE_LICENSE("GPL"); | 50 | MODULE_LICENSE("GPL"); |
51 | MODULE_FIRMWARE("libertas_cs_helper.fw"); | ||
52 | 51 | ||
53 | 52 | ||
54 | 53 | ||
@@ -61,9 +60,34 @@ struct if_cs_card { | |||
61 | struct lbs_private *priv; | 60 | struct lbs_private *priv; |
62 | void __iomem *iobase; | 61 | void __iomem *iobase; |
63 | bool align_regs; | 62 | bool align_regs; |
63 | u32 model; | ||
64 | }; | 64 | }; |
65 | 65 | ||
66 | 66 | ||
67 | enum { | ||
68 | MODEL_UNKNOWN = 0x00, | ||
69 | MODEL_8305 = 0x01, | ||
70 | MODEL_8381 = 0x02, | ||
71 | MODEL_8385 = 0x03 | ||
72 | }; | ||
73 | |||
74 | static const struct lbs_fw_table fw_table[] = { | ||
75 | { MODEL_8305, "libertas/cf8305.bin", NULL }, | ||
76 | { MODEL_8305, "libertas_cs_helper.fw", NULL }, | ||
77 | { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" }, | ||
78 | { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" }, | ||
79 | { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" }, | ||
80 | { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" }, | ||
81 | { 0, NULL, NULL } | ||
82 | }; | ||
83 | MODULE_FIRMWARE("libertas/cf8305.bin"); | ||
84 | MODULE_FIRMWARE("libertas/cf8381_helper.bin"); | ||
85 | MODULE_FIRMWARE("libertas/cf8381.bin"); | ||
86 | MODULE_FIRMWARE("libertas/cf8385_helper.bin"); | ||
87 | MODULE_FIRMWARE("libertas/cf8385.bin"); | ||
88 | MODULE_FIRMWARE("libertas_cs_helper.fw"); | ||
89 | MODULE_FIRMWARE("libertas_cs.fw"); | ||
90 | |||
67 | 91 | ||
68 | /********************************************************************/ | 92 | /********************************************************************/ |
69 | /* Hardware access */ | 93 | /* Hardware access */ |
@@ -289,22 +313,19 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r | |||
289 | #define CF8385_MANFID 0x02df | 313 | #define CF8385_MANFID 0x02df |
290 | #define CF8385_CARDID 0x8103 | 314 | #define CF8385_CARDID 0x8103 |
291 | 315 | ||
292 | static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev) | 316 | /* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when |
293 | { | 317 | * that gets fixed. Currently there's no way to access it from the probe hook. |
294 | return (p_dev->manf_id == CF8305_MANFID && | 318 | */ |
295 | p_dev->card_id == CF8305_CARDID); | 319 | static inline u32 get_model(u16 manf_id, u16 card_id) |
296 | } | ||
297 | |||
298 | static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev) | ||
299 | { | ||
300 | return (p_dev->manf_id == CF8381_MANFID && | ||
301 | p_dev->card_id == CF8381_CARDID); | ||
302 | } | ||
303 | |||
304 | static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev) | ||
305 | { | 320 | { |
306 | return (p_dev->manf_id == CF8385_MANFID && | 321 | /* NOTE: keep in sync with if_cs_ids */ |
307 | p_dev->card_id == CF8385_CARDID); | 322 | if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID) |
323 | return MODEL_8305; | ||
324 | else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID) | ||
325 | return MODEL_8381; | ||
326 | else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID) | ||
327 | return MODEL_8385; | ||
328 | return MODEL_UNKNOWN; | ||
308 | } | 329 | } |
309 | 330 | ||
310 | /********************************************************************/ | 331 | /********************************************************************/ |
@@ -558,12 +579,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) | |||
558 | * | 579 | * |
559 | * Return 0 on success | 580 | * Return 0 on success |
560 | */ | 581 | */ |
561 | static int if_cs_prog_helper(struct if_cs_card *card) | 582 | static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) |
562 | { | 583 | { |
563 | int ret = 0; | 584 | int ret = 0; |
564 | int sent = 0; | 585 | int sent = 0; |
565 | u8 scratch; | 586 | u8 scratch; |
566 | const struct firmware *fw; | ||
567 | 587 | ||
568 | lbs_deb_enter(LBS_DEB_CS); | 588 | lbs_deb_enter(LBS_DEB_CS); |
569 | 589 | ||
@@ -589,14 +609,6 @@ static int if_cs_prog_helper(struct if_cs_card *card) | |||
589 | goto done; | 609 | goto done; |
590 | } | 610 | } |
591 | 611 | ||
592 | /* TODO: make firmware file configurable */ | ||
593 | ret = request_firmware(&fw, "libertas_cs_helper.fw", | ||
594 | &card->p_dev->dev); | ||
595 | if (ret) { | ||
596 | lbs_pr_err("can't load helper firmware\n"); | ||
597 | ret = -ENODEV; | ||
598 | goto done; | ||
599 | } | ||
600 | lbs_deb_cs("helper size %td\n", fw->size); | 612 | lbs_deb_cs("helper size %td\n", fw->size); |
601 | 613 | ||
602 | /* "Set the 5 bytes of the helper image to 0" */ | 614 | /* "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) | |||
635 | if (ret < 0) { | 647 | if (ret < 0) { |
636 | lbs_pr_err("can't download helper at 0x%x, ret %d\n", | 648 | lbs_pr_err("can't download helper at 0x%x, ret %d\n", |
637 | sent, ret); | 649 | sent, ret); |
638 | goto err_release; | 650 | goto done; |
639 | } | 651 | } |
640 | 652 | ||
641 | if (count == 0) | 653 | if (count == 0) |
@@ -644,17 +656,14 @@ static int if_cs_prog_helper(struct if_cs_card *card) | |||
644 | sent += count; | 656 | sent += count; |
645 | } | 657 | } |
646 | 658 | ||
647 | err_release: | ||
648 | release_firmware(fw); | ||
649 | done: | 659 | done: |
650 | lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); | 660 | lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); |
651 | return ret; | 661 | return ret; |
652 | } | 662 | } |
653 | 663 | ||
654 | 664 | ||
655 | static int if_cs_prog_real(struct if_cs_card *card) | 665 | static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) |
656 | { | 666 | { |
657 | const struct firmware *fw; | ||
658 | int ret = 0; | 667 | int ret = 0; |
659 | int retry = 0; | 668 | int retry = 0; |
660 | int len = 0; | 669 | int len = 0; |
@@ -662,21 +671,13 @@ static int if_cs_prog_real(struct if_cs_card *card) | |||
662 | 671 | ||
663 | lbs_deb_enter(LBS_DEB_CS); | 672 | lbs_deb_enter(LBS_DEB_CS); |
664 | 673 | ||
665 | /* TODO: make firmware file configurable */ | ||
666 | ret = request_firmware(&fw, "libertas_cs.fw", | ||
667 | &card->p_dev->dev); | ||
668 | if (ret) { | ||
669 | lbs_pr_err("can't load firmware\n"); | ||
670 | ret = -ENODEV; | ||
671 | goto done; | ||
672 | } | ||
673 | lbs_deb_cs("fw size %td\n", fw->size); | 674 | lbs_deb_cs("fw size %td\n", fw->size); |
674 | 675 | ||
675 | ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, | 676 | ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, |
676 | IF_CS_SQ_HELPER_OK); | 677 | IF_CS_SQ_HELPER_OK); |
677 | if (ret < 0) { | 678 | if (ret < 0) { |
678 | lbs_pr_err("helper firmware doesn't answer\n"); | 679 | lbs_pr_err("helper firmware doesn't answer\n"); |
679 | goto err_release; | 680 | goto done; |
680 | } | 681 | } |
681 | 682 | ||
682 | for (sent = 0; sent < fw->size; sent += len) { | 683 | for (sent = 0; sent < fw->size; sent += len) { |
@@ -691,7 +692,7 @@ static int if_cs_prog_real(struct if_cs_card *card) | |||
691 | if (retry > 20) { | 692 | if (retry > 20) { |
692 | lbs_pr_err("could not download firmware\n"); | 693 | lbs_pr_err("could not download firmware\n"); |
693 | ret = -ENODEV; | 694 | ret = -ENODEV; |
694 | goto err_release; | 695 | goto done; |
695 | } | 696 | } |
696 | if (retry) { | 697 | if (retry) { |
697 | sent -= len; | 698 | sent -= len; |
@@ -710,7 +711,7 @@ static int if_cs_prog_real(struct if_cs_card *card) | |||
710 | IF_CS_BIT_COMMAND); | 711 | IF_CS_BIT_COMMAND); |
711 | if (ret < 0) { | 712 | if (ret < 0) { |
712 | lbs_pr_err("can't download firmware at 0x%x\n", sent); | 713 | lbs_pr_err("can't download firmware at 0x%x\n", sent); |
713 | goto err_release; | 714 | goto done; |
714 | } | 715 | } |
715 | } | 716 | } |
716 | 717 | ||
@@ -718,9 +719,6 @@ static int if_cs_prog_real(struct if_cs_card *card) | |||
718 | if (ret < 0) | 719 | if (ret < 0) |
719 | lbs_pr_err("firmware download failed\n"); | 720 | lbs_pr_err("firmware download failed\n"); |
720 | 721 | ||
721 | err_release: | ||
722 | release_firmware(fw); | ||
723 | |||
724 | done: | 722 | done: |
725 | lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); | 723 | lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); |
726 | return ret; | 724 | return ret; |
@@ -824,6 +822,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev) | |||
824 | unsigned int prod_id; | 822 | unsigned int prod_id; |
825 | struct lbs_private *priv; | 823 | struct lbs_private *priv; |
826 | struct if_cs_card *card; | 824 | struct if_cs_card *card; |
825 | const struct firmware *helper = NULL; | ||
826 | const struct firmware *mainfw = NULL; | ||
827 | 827 | ||
828 | lbs_deb_enter(LBS_DEB_CS); | 828 | lbs_deb_enter(LBS_DEB_CS); |
829 | 829 | ||
@@ -843,7 +843,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) | |||
843 | goto out1; | 843 | goto out1; |
844 | } | 844 | } |
845 | 845 | ||
846 | |||
847 | /* | 846 | /* |
848 | * Allocate an interrupt line. Note that this does not assign | 847 | * Allocate an interrupt line. Note that this does not assign |
849 | * a handler to the interrupt, unless the 'Handler' member of | 848 | * a handler to the interrupt, unless the 'Handler' member of |
@@ -881,34 +880,47 @@ static int if_cs_probe(struct pcmcia_device *p_dev) | |||
881 | */ | 880 | */ |
882 | card->align_regs = 0; | 881 | card->align_regs = 0; |
883 | 882 | ||
883 | card->model = get_model(p_dev->manf_id, p_dev->card_id); | ||
884 | if (card->model == MODEL_UNKNOWN) { | ||
885 | lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", | ||
886 | p_dev->manf_id, p_dev->card_id); | ||
887 | goto out2; | ||
888 | } | ||
889 | |||
884 | /* Check if we have a current silicon */ | 890 | /* Check if we have a current silicon */ |
885 | prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); | 891 | prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); |
886 | if (if_cs_hw_is_cf8305(p_dev)) { | 892 | if (card->model == MODEL_8305) { |
887 | card->align_regs = 1; | 893 | card->align_regs = 1; |
888 | if (prod_id < IF_CS_CF8305_B1_REV) { | 894 | if (prod_id < IF_CS_CF8305_B1_REV) { |
889 | lbs_pr_err("old chips like 8305 rev B3 " | 895 | lbs_pr_err("8305 rev B0 and older are not supported\n"); |
890 | "aren't supported\n"); | ||
891 | ret = -ENODEV; | 896 | ret = -ENODEV; |
892 | goto out2; | 897 | goto out2; |
893 | } | 898 | } |
894 | } | 899 | } |
895 | 900 | ||
896 | if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) { | 901 | if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) { |
897 | lbs_pr_err("old chips like 8381 rev B3 aren't supported\n"); | 902 | lbs_pr_err("8381 rev B2 and older are not supported\n"); |
898 | ret = -ENODEV; | 903 | ret = -ENODEV; |
899 | goto out2; | 904 | goto out2; |
900 | } | 905 | } |
901 | 906 | ||
902 | if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) { | 907 | if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) { |
903 | lbs_pr_err("old chips like 8385 rev B1 aren't supported\n"); | 908 | lbs_pr_err("8385 rev B0 and older are not supported\n"); |
904 | ret = -ENODEV; | 909 | ret = -ENODEV; |
905 | goto out2; | 910 | goto out2; |
906 | } | 911 | } |
907 | 912 | ||
913 | ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model, | ||
914 | &fw_table[0], &helper, &mainfw); | ||
915 | if (ret) { | ||
916 | lbs_pr_err("failed to find firmware (%d)\n", ret); | ||
917 | goto out2; | ||
918 | } | ||
919 | |||
908 | /* Load the firmware early, before calling into libertas.ko */ | 920 | /* Load the firmware early, before calling into libertas.ko */ |
909 | ret = if_cs_prog_helper(card); | 921 | ret = if_cs_prog_helper(card, helper); |
910 | if (ret == 0 && !if_cs_hw_is_cf8305(p_dev)) | 922 | if (ret == 0 && (card->model != MODEL_8305)) |
911 | ret = if_cs_prog_real(card); | 923 | ret = if_cs_prog_real(card, mainfw); |
912 | if (ret) | 924 | if (ret) |
913 | goto out2; | 925 | goto out2; |
914 | 926 | ||
@@ -957,6 +969,11 @@ out2: | |||
957 | out1: | 969 | out1: |
958 | pcmcia_disable_device(p_dev); | 970 | pcmcia_disable_device(p_dev); |
959 | out: | 971 | out: |
972 | if (helper) | ||
973 | release_firmware(helper); | ||
974 | if (mainfw) | ||
975 | release_firmware(mainfw); | ||
976 | |||
960 | lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); | 977 | lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); |
961 | return ret; | 978 | return ret; |
962 | } | 979 | } |
@@ -993,6 +1010,7 @@ static struct pcmcia_device_id if_cs_ids[] = { | |||
993 | PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), | 1010 | PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), |
994 | PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), | 1011 | PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), |
995 | PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), | 1012 | PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), |
1013 | /* NOTE: keep in sync with get_model() */ | ||
996 | PCMCIA_DEVICE_NULL, | 1014 | PCMCIA_DEVICE_NULL, |
997 | }; | 1015 | }; |
998 | MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); | 1016 | MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); |