diff options
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 325 |
1 files changed, 217 insertions, 108 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 24958a86747b..8c40949cb076 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -1,8 +1,10 @@ | |||
1 | /** | 1 | /* |
2 | * This file contains the major functions in WLAN | 2 | * This file contains the major functions in WLAN |
3 | * driver. It includes init, exit, open, close and main | 3 | * driver. It includes init, exit, open, close and main |
4 | * thread etc.. | 4 | * thread etc.. |
5 | */ | 5 | */ |
6 | |||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
6 | 8 | ||
7 | #include <linux/moduleparam.h> | 9 | #include <linux/moduleparam.h> |
8 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
@@ -34,19 +36,25 @@ unsigned int lbs_debug; | |||
34 | EXPORT_SYMBOL_GPL(lbs_debug); | 36 | EXPORT_SYMBOL_GPL(lbs_debug); |
35 | module_param_named(libertas_debug, lbs_debug, int, 0644); | 37 | module_param_named(libertas_debug, lbs_debug, int, 0644); |
36 | 38 | ||
39 | unsigned int lbs_disablemesh; | ||
40 | EXPORT_SYMBOL_GPL(lbs_disablemesh); | ||
41 | module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644); | ||
42 | |||
37 | 43 | ||
38 | /* This global structure is used to send the confirm_sleep command as | 44 | /* |
39 | * fast as possible down to the firmware. */ | 45 | * This global structure is used to send the confirm_sleep command as |
46 | * fast as possible down to the firmware. | ||
47 | */ | ||
40 | struct cmd_confirm_sleep confirm_sleep; | 48 | struct cmd_confirm_sleep confirm_sleep; |
41 | 49 | ||
42 | 50 | ||
43 | /** | 51 | /* |
44 | * the table to keep region code | 52 | * the table to keep region code |
45 | */ | 53 | */ |
46 | u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = | 54 | u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = |
47 | { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; | 55 | { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; |
48 | 56 | ||
49 | /** | 57 | /* |
50 | * FW rate table. FW refers to rates by their index in this table, not by the | 58 | * FW rate table. FW refers to rates by their index in this table, not by the |
51 | * rate value itself. Values of 0x00 are | 59 | * rate value itself. Values of 0x00 are |
52 | * reserved positions. | 60 | * reserved positions. |
@@ -57,10 +65,10 @@ static u8 fw_data_rates[MAX_RATES] = | |||
57 | }; | 65 | }; |
58 | 66 | ||
59 | /** | 67 | /** |
60 | * @brief use index to get the data rate | 68 | * lbs_fw_index_to_data_rate - use index to get the data rate |
61 | * | 69 | * |
62 | * @param idx The index of data rate | 70 | * @idx: The index of data rate |
63 | * @return data rate or 0 | 71 | * returns: data rate or 0 |
64 | */ | 72 | */ |
65 | u32 lbs_fw_index_to_data_rate(u8 idx) | 73 | u32 lbs_fw_index_to_data_rate(u8 idx) |
66 | { | 74 | { |
@@ -70,10 +78,10 @@ u32 lbs_fw_index_to_data_rate(u8 idx) | |||
70 | } | 78 | } |
71 | 79 | ||
72 | /** | 80 | /** |
73 | * @brief use rate to get the index | 81 | * lbs_data_rate_to_fw_index - use rate to get the index |
74 | * | 82 | * |
75 | * @param rate data rate | 83 | * @rate: data rate |
76 | * @return index or 0 | 84 | * returns: index or 0 |
77 | */ | 85 | */ |
78 | u8 lbs_data_rate_to_fw_index(u32 rate) | 86 | u8 lbs_data_rate_to_fw_index(u32 rate) |
79 | { | 87 | { |
@@ -91,10 +99,10 @@ u8 lbs_data_rate_to_fw_index(u32 rate) | |||
91 | 99 | ||
92 | 100 | ||
93 | /** | 101 | /** |
94 | * @brief This function opens the ethX interface | 102 | * lbs_dev_open - open the ethX interface |
95 | * | 103 | * |
96 | * @param dev A pointer to net_device structure | 104 | * @dev: A pointer to &net_device structure |
97 | * @return 0 or -EBUSY if monitor mode active | 105 | * returns: 0 or -EBUSY if monitor mode active |
98 | */ | 106 | */ |
99 | static int lbs_dev_open(struct net_device *dev) | 107 | static int lbs_dev_open(struct net_device *dev) |
100 | { | 108 | { |
@@ -104,6 +112,7 @@ static int lbs_dev_open(struct net_device *dev) | |||
104 | lbs_deb_enter(LBS_DEB_NET); | 112 | lbs_deb_enter(LBS_DEB_NET); |
105 | 113 | ||
106 | spin_lock_irq(&priv->driver_lock); | 114 | spin_lock_irq(&priv->driver_lock); |
115 | priv->stopping = false; | ||
107 | 116 | ||
108 | if (priv->connect_status == LBS_CONNECTED) | 117 | if (priv->connect_status == LBS_CONNECTED) |
109 | netif_carrier_on(dev); | 118 | netif_carrier_on(dev); |
@@ -119,10 +128,10 @@ static int lbs_dev_open(struct net_device *dev) | |||
119 | } | 128 | } |
120 | 129 | ||
121 | /** | 130 | /** |
122 | * @brief This function closes the ethX interface | 131 | * lbs_eth_stop - close the ethX interface |
123 | * | 132 | * |
124 | * @param dev A pointer to net_device structure | 133 | * @dev: A pointer to &net_device structure |
125 | * @return 0 | 134 | * returns: 0 |
126 | */ | 135 | */ |
127 | static int lbs_eth_stop(struct net_device *dev) | 136 | static int lbs_eth_stop(struct net_device *dev) |
128 | { | 137 | { |
@@ -131,37 +140,21 @@ static int lbs_eth_stop(struct net_device *dev) | |||
131 | lbs_deb_enter(LBS_DEB_NET); | 140 | lbs_deb_enter(LBS_DEB_NET); |
132 | 141 | ||
133 | spin_lock_irq(&priv->driver_lock); | 142 | spin_lock_irq(&priv->driver_lock); |
143 | priv->stopping = true; | ||
134 | netif_stop_queue(dev); | 144 | netif_stop_queue(dev); |
135 | spin_unlock_irq(&priv->driver_lock); | 145 | spin_unlock_irq(&priv->driver_lock); |
136 | 146 | ||
137 | schedule_work(&priv->mcast_work); | 147 | schedule_work(&priv->mcast_work); |
148 | cancel_delayed_work_sync(&priv->scan_work); | ||
149 | if (priv->scan_req) { | ||
150 | cfg80211_scan_done(priv->scan_req, false); | ||
151 | priv->scan_req = NULL; | ||
152 | } | ||
138 | 153 | ||
139 | lbs_deb_leave(LBS_DEB_NET); | 154 | lbs_deb_leave(LBS_DEB_NET); |
140 | return 0; | 155 | return 0; |
141 | } | 156 | } |
142 | 157 | ||
143 | static void lbs_tx_timeout(struct net_device *dev) | ||
144 | { | ||
145 | struct lbs_private *priv = dev->ml_priv; | ||
146 | |||
147 | lbs_deb_enter(LBS_DEB_TX); | ||
148 | |||
149 | lbs_pr_err("tx watch dog timeout\n"); | ||
150 | |||
151 | dev->trans_start = jiffies; /* prevent tx timeout */ | ||
152 | |||
153 | if (priv->currenttxskb) | ||
154 | lbs_send_tx_feedback(priv, 0); | ||
155 | |||
156 | /* XX: Shouldn't we also call into the hw-specific driver | ||
157 | to kick it somehow? */ | ||
158 | lbs_host_to_card_done(priv); | ||
159 | |||
160 | /* FIXME: reset the card */ | ||
161 | |||
162 | lbs_deb_leave(LBS_DEB_TX); | ||
163 | } | ||
164 | |||
165 | void lbs_host_to_card_done(struct lbs_private *priv) | 158 | void lbs_host_to_card_done(struct lbs_private *priv) |
166 | { | 159 | { |
167 | unsigned long flags; | 160 | unsigned long flags; |
@@ -329,12 +322,12 @@ void lbs_set_multicast_list(struct net_device *dev) | |||
329 | } | 322 | } |
330 | 323 | ||
331 | /** | 324 | /** |
332 | * @brief This function handles the major jobs in the LBS driver. | 325 | * lbs_thread - handles the major jobs in the LBS driver. |
333 | * It handles all events generated by firmware, RX data received | 326 | * It handles all events generated by firmware, RX data received |
334 | * from firmware and TX data sent from kernel. | 327 | * from firmware and TX data sent from kernel. |
335 | * | 328 | * |
336 | * @param data A pointer to lbs_thread structure | 329 | * @data: A pointer to &lbs_thread structure |
337 | * @return 0 | 330 | * returns: 0 |
338 | */ | 331 | */ |
339 | static int lbs_thread(void *data) | 332 | static int lbs_thread(void *data) |
340 | { | 333 | { |
@@ -455,8 +448,8 @@ static int lbs_thread(void *data) | |||
455 | if (priv->cmd_timed_out && priv->cur_cmd) { | 448 | if (priv->cmd_timed_out && priv->cur_cmd) { |
456 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; | 449 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; |
457 | 450 | ||
458 | lbs_pr_info("Timeout submitting command 0x%04x\n", | 451 | netdev_info(dev, "Timeout submitting command 0x%04x\n", |
459 | le16_to_cpu(cmdnode->cmdbuf->command)); | 452 | le16_to_cpu(cmdnode->cmdbuf->command)); |
460 | lbs_complete_command(priv, cmdnode, -ETIMEDOUT); | 453 | lbs_complete_command(priv, cmdnode, -ETIMEDOUT); |
461 | if (priv->reset_card) | 454 | if (priv->reset_card) |
462 | priv->reset_card(priv); | 455 | priv->reset_card(priv); |
@@ -483,8 +476,8 @@ static int lbs_thread(void *data) | |||
483 | * after firmware fixes it | 476 | * after firmware fixes it |
484 | */ | 477 | */ |
485 | priv->psstate = PS_STATE_AWAKE; | 478 | priv->psstate = PS_STATE_AWAKE; |
486 | lbs_pr_alert("ignore PS_SleepConfirm in " | 479 | netdev_alert(dev, |
487 | "non-connected state\n"); | 480 | "ignore PS_SleepConfirm in non-connected state\n"); |
488 | } | 481 | } |
489 | } | 482 | } |
490 | 483 | ||
@@ -532,6 +525,43 @@ static int lbs_thread(void *data) | |||
532 | return 0; | 525 | return 0; |
533 | } | 526 | } |
534 | 527 | ||
528 | /** | ||
529 | * lbs_setup_firmware - gets the HW spec from the firmware and sets | ||
530 | * some basic parameters | ||
531 | * | ||
532 | * @priv: A pointer to &struct lbs_private structure | ||
533 | * returns: 0 or -1 | ||
534 | */ | ||
535 | static int lbs_setup_firmware(struct lbs_private *priv) | ||
536 | { | ||
537 | int ret = -1; | ||
538 | s16 curlevel = 0, minlevel = 0, maxlevel = 0; | ||
539 | |||
540 | lbs_deb_enter(LBS_DEB_FW); | ||
541 | |||
542 | /* Read MAC address from firmware */ | ||
543 | memset(priv->current_addr, 0xff, ETH_ALEN); | ||
544 | ret = lbs_update_hw_spec(priv); | ||
545 | if (ret) | ||
546 | goto done; | ||
547 | |||
548 | /* Read power levels if available */ | ||
549 | ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); | ||
550 | if (ret == 0) { | ||
551 | priv->txpower_cur = curlevel; | ||
552 | priv->txpower_min = minlevel; | ||
553 | priv->txpower_max = maxlevel; | ||
554 | } | ||
555 | |||
556 | /* Send cmd to FW to enable 11D function */ | ||
557 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1); | ||
558 | |||
559 | lbs_set_mac_control(priv); | ||
560 | done: | ||
561 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
535 | int lbs_suspend(struct lbs_private *priv) | 565 | int lbs_suspend(struct lbs_private *priv) |
536 | { | 566 | { |
537 | int ret; | 567 | int ret; |
@@ -541,7 +571,8 @@ int lbs_suspend(struct lbs_private *priv) | |||
541 | if (priv->is_deep_sleep) { | 571 | if (priv->is_deep_sleep) { |
542 | ret = lbs_set_deep_sleep(priv, 0); | 572 | ret = lbs_set_deep_sleep(priv, 0); |
543 | if (ret) { | 573 | if (ret) { |
544 | lbs_pr_err("deep sleep cancellation failed: %d\n", ret); | 574 | netdev_err(priv->dev, |
575 | "deep sleep cancellation failed: %d\n", ret); | ||
545 | return ret; | 576 | return ret; |
546 | } | 577 | } |
547 | priv->deep_sleep_required = 1; | 578 | priv->deep_sleep_required = 1; |
@@ -574,54 +605,23 @@ int lbs_resume(struct lbs_private *priv) | |||
574 | priv->deep_sleep_required = 0; | 605 | priv->deep_sleep_required = 0; |
575 | ret = lbs_set_deep_sleep(priv, 1); | 606 | ret = lbs_set_deep_sleep(priv, 1); |
576 | if (ret) | 607 | if (ret) |
577 | lbs_pr_err("deep sleep activation failed: %d\n", ret); | 608 | netdev_err(priv->dev, |
609 | "deep sleep activation failed: %d\n", ret); | ||
578 | } | 610 | } |
579 | 611 | ||
612 | if (priv->setup_fw_on_resume) | ||
613 | ret = lbs_setup_firmware(priv); | ||
614 | |||
580 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); | 615 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); |
581 | return ret; | 616 | return ret; |
582 | } | 617 | } |
583 | EXPORT_SYMBOL_GPL(lbs_resume); | 618 | EXPORT_SYMBOL_GPL(lbs_resume); |
584 | 619 | ||
585 | /** | 620 | /** |
586 | * @brief This function gets the HW spec from the firmware and sets | 621 | * lbs_cmd_timeout_handler - handles the timeout of command sending. |
587 | * some basic parameters. | 622 | * It will re-send the same command again. |
588 | * | 623 | * |
589 | * @param priv A pointer to struct lbs_private structure | 624 | * @data: &struct lbs_private pointer |
590 | * @return 0 or -1 | ||
591 | */ | ||
592 | static int lbs_setup_firmware(struct lbs_private *priv) | ||
593 | { | ||
594 | int ret = -1; | ||
595 | s16 curlevel = 0, minlevel = 0, maxlevel = 0; | ||
596 | |||
597 | lbs_deb_enter(LBS_DEB_FW); | ||
598 | |||
599 | /* Read MAC address from firmware */ | ||
600 | memset(priv->current_addr, 0xff, ETH_ALEN); | ||
601 | ret = lbs_update_hw_spec(priv); | ||
602 | if (ret) | ||
603 | goto done; | ||
604 | |||
605 | /* Read power levels if available */ | ||
606 | ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); | ||
607 | if (ret == 0) { | ||
608 | priv->txpower_cur = curlevel; | ||
609 | priv->txpower_min = minlevel; | ||
610 | priv->txpower_max = maxlevel; | ||
611 | } | ||
612 | |||
613 | /* Send cmd to FW to enable 11D function */ | ||
614 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1); | ||
615 | |||
616 | lbs_set_mac_control(priv); | ||
617 | done: | ||
618 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); | ||
619 | return ret; | ||
620 | } | ||
621 | |||
622 | /** | ||
623 | * This function handles the timeout of command sending. | ||
624 | * It will re-send the same command again. | ||
625 | */ | 625 | */ |
626 | static void lbs_cmd_timeout_handler(unsigned long data) | 626 | static void lbs_cmd_timeout_handler(unsigned long data) |
627 | { | 627 | { |
@@ -634,8 +634,8 @@ static void lbs_cmd_timeout_handler(unsigned long data) | |||
634 | if (!priv->cur_cmd) | 634 | if (!priv->cur_cmd) |
635 | goto out; | 635 | goto out; |
636 | 636 | ||
637 | lbs_pr_info("command 0x%04x timed out\n", | 637 | netdev_info(priv->dev, "command 0x%04x timed out\n", |
638 | le16_to_cpu(priv->cur_cmd->cmdbuf->command)); | 638 | le16_to_cpu(priv->cur_cmd->cmdbuf->command)); |
639 | 639 | ||
640 | priv->cmd_timed_out = 1; | 640 | priv->cmd_timed_out = 1; |
641 | wake_up_interruptible(&priv->waitq); | 641 | wake_up_interruptible(&priv->waitq); |
@@ -645,8 +645,10 @@ out: | |||
645 | } | 645 | } |
646 | 646 | ||
647 | /** | 647 | /** |
648 | * This function put the device back to deep sleep mode when timer expires | 648 | * auto_deepsleep_timer_fn - put the device back to deep sleep mode when |
649 | * and no activity (command, event, data etc.) is detected. | 649 | * timer expires and no activity (command, event, data etc.) is detected. |
650 | * @data: &struct lbs_private pointer | ||
651 | * returns: N/A | ||
650 | */ | 652 | */ |
651 | static void auto_deepsleep_timer_fn(unsigned long data) | 653 | static void auto_deepsleep_timer_fn(unsigned long data) |
652 | { | 654 | { |
@@ -738,7 +740,7 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
738 | 740 | ||
739 | /* Allocate the command buffers */ | 741 | /* Allocate the command buffers */ |
740 | if (lbs_allocate_cmd_buffer(priv)) { | 742 | if (lbs_allocate_cmd_buffer(priv)) { |
741 | lbs_pr_err("Out of memory allocating command buffers\n"); | 743 | pr_err("Out of memory allocating command buffers\n"); |
742 | ret = -ENOMEM; | 744 | ret = -ENOMEM; |
743 | goto out; | 745 | goto out; |
744 | } | 746 | } |
@@ -748,7 +750,7 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
748 | /* Create the event FIFO */ | 750 | /* Create the event FIFO */ |
749 | ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL); | 751 | ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL); |
750 | if (ret) { | 752 | if (ret) { |
751 | lbs_pr_err("Out of memory allocating event FIFO buffer\n"); | 753 | pr_err("Out of memory allocating event FIFO buffer\n"); |
752 | goto out; | 754 | goto out; |
753 | } | 755 | } |
754 | 756 | ||
@@ -775,18 +777,18 @@ static const struct net_device_ops lbs_netdev_ops = { | |||
775 | .ndo_stop = lbs_eth_stop, | 777 | .ndo_stop = lbs_eth_stop, |
776 | .ndo_start_xmit = lbs_hard_start_xmit, | 778 | .ndo_start_xmit = lbs_hard_start_xmit, |
777 | .ndo_set_mac_address = lbs_set_mac_address, | 779 | .ndo_set_mac_address = lbs_set_mac_address, |
778 | .ndo_tx_timeout = lbs_tx_timeout, | ||
779 | .ndo_set_multicast_list = lbs_set_multicast_list, | 780 | .ndo_set_multicast_list = lbs_set_multicast_list, |
780 | .ndo_change_mtu = eth_change_mtu, | 781 | .ndo_change_mtu = eth_change_mtu, |
781 | .ndo_validate_addr = eth_validate_addr, | 782 | .ndo_validate_addr = eth_validate_addr, |
782 | }; | 783 | }; |
783 | 784 | ||
784 | /** | 785 | /** |
785 | * @brief This function adds the card. it will probe the | 786 | * lbs_add_card - adds the card. It will probe the |
786 | * card, allocate the lbs_priv and initialize the device. | 787 | * card, allocate the lbs_priv and initialize the device. |
787 | * | 788 | * |
788 | * @param card A pointer to card | 789 | * @card: A pointer to card |
789 | * @return A pointer to struct lbs_private structure | 790 | * @dmdev: A pointer to &struct device |
791 | * returns: A pointer to &struct lbs_private structure | ||
790 | */ | 792 | */ |
791 | struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | 793 | struct lbs_private *lbs_add_card(void *card, struct device *dmdev) |
792 | { | 794 | { |
@@ -799,7 +801,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
799 | /* Allocate an Ethernet device and register it */ | 801 | /* Allocate an Ethernet device and register it */ |
800 | wdev = lbs_cfg_alloc(dmdev); | 802 | wdev = lbs_cfg_alloc(dmdev); |
801 | if (IS_ERR(wdev)) { | 803 | if (IS_ERR(wdev)) { |
802 | lbs_pr_err("cfg80211 init failed\n"); | 804 | pr_err("cfg80211 init failed\n"); |
803 | goto done; | 805 | goto done; |
804 | } | 806 | } |
805 | 807 | ||
@@ -808,7 +810,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
808 | priv->wdev = wdev; | 810 | priv->wdev = wdev; |
809 | 811 | ||
810 | if (lbs_init_adapter(priv)) { | 812 | if (lbs_init_adapter(priv)) { |
811 | lbs_pr_err("failed to initialize adapter structure.\n"); | 813 | pr_err("failed to initialize adapter structure\n"); |
812 | goto err_wdev; | 814 | goto err_wdev; |
813 | } | 815 | } |
814 | 816 | ||
@@ -844,9 +846,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
844 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); | 846 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); |
845 | INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); | 847 | INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); |
846 | 848 | ||
847 | priv->wol_criteria = 0xffffffff; | 849 | priv->wol_criteria = EHS_REMOVE_WAKEUP; |
848 | priv->wol_gpio = 0xff; | 850 | priv->wol_gpio = 0xff; |
849 | priv->wol_gap = 20; | 851 | priv->wol_gap = 20; |
852 | priv->ehs_remove_supported = true; | ||
850 | 853 | ||
851 | goto done; | 854 | goto done; |
852 | 855 | ||
@@ -908,8 +911,6 @@ void lbs_remove_card(struct lbs_private *priv) | |||
908 | 911 | ||
909 | lbs_free_adapter(priv); | 912 | lbs_free_adapter(priv); |
910 | lbs_cfg_free(priv); | 913 | lbs_cfg_free(priv); |
911 | |||
912 | priv->dev = NULL; | ||
913 | free_netdev(dev); | 914 | free_netdev(dev); |
914 | 915 | ||
915 | lbs_deb_leave(LBS_DEB_MAIN); | 916 | lbs_deb_leave(LBS_DEB_MAIN); |
@@ -941,17 +942,20 @@ int lbs_start_card(struct lbs_private *priv) | |||
941 | goto done; | 942 | goto done; |
942 | 943 | ||
943 | if (lbs_cfg_register(priv)) { | 944 | if (lbs_cfg_register(priv)) { |
944 | lbs_pr_err("cannot register device\n"); | 945 | pr_err("cannot register device\n"); |
945 | goto done; | 946 | goto done; |
946 | } | 947 | } |
947 | 948 | ||
948 | lbs_update_channel(priv); | 949 | lbs_update_channel(priv); |
949 | 950 | ||
950 | lbs_init_mesh(priv); | 951 | if (!lbs_disablemesh) |
952 | lbs_init_mesh(priv); | ||
953 | else | ||
954 | pr_info("%s: mesh disabled\n", dev->name); | ||
951 | 955 | ||
952 | lbs_debugfs_init_one(priv, dev); | 956 | lbs_debugfs_init_one(priv, dev); |
953 | 957 | ||
954 | lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); | 958 | netdev_info(dev, "Marvell WLAN 802.11 adapter\n"); |
955 | 959 | ||
956 | ret = 0; | 960 | ret = 0; |
957 | 961 | ||
@@ -1047,6 +1051,111 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) | |||
1047 | } | 1051 | } |
1048 | EXPORT_SYMBOL_GPL(lbs_notify_command_response); | 1052 | EXPORT_SYMBOL_GPL(lbs_notify_command_response); |
1049 | 1053 | ||
1054 | /** | ||
1055 | * lbs_get_firmware - Retrieves two-stage firmware | ||
1056 | * | ||
1057 | * @dev: A pointer to &device structure | ||
1058 | * @user_helper: User-defined helper firmware file | ||
1059 | * @user_mainfw: User-defined main firmware file | ||
1060 | * @card_model: Bus-specific card model ID used to filter firmware table | ||
1061 | * elements | ||
1062 | * @fw_table: Table of firmware file names and device model numbers | ||
1063 | * terminated by an entry with a NULL helper name | ||
1064 | * @helper: On success, the helper firmware; caller must free | ||
1065 | * @mainfw: On success, the main firmware; caller must free | ||
1066 | * | ||
1067 | * returns: 0 on success, non-zero on failure | ||
1068 | */ | ||
1069 | int lbs_get_firmware(struct device *dev, const char *user_helper, | ||
1070 | const char *user_mainfw, u32 card_model, | ||
1071 | const struct lbs_fw_table *fw_table, | ||
1072 | const struct firmware **helper, | ||
1073 | const struct firmware **mainfw) | ||
1074 | { | ||
1075 | const struct lbs_fw_table *iter; | ||
1076 | int ret; | ||
1077 | |||
1078 | BUG_ON(helper == NULL); | ||
1079 | BUG_ON(mainfw == NULL); | ||
1080 | |||
1081 | /* Try user-specified firmware first */ | ||
1082 | if (user_helper) { | ||
1083 | ret = request_firmware(helper, user_helper, dev); | ||
1084 | if (ret) { | ||
1085 | dev_err(dev, "couldn't find helper firmware %s\n", | ||
1086 | user_helper); | ||
1087 | goto fail; | ||
1088 | } | ||
1089 | } | ||
1090 | if (user_mainfw) { | ||
1091 | ret = request_firmware(mainfw, user_mainfw, dev); | ||
1092 | if (ret) { | ||
1093 | dev_err(dev, "couldn't find main firmware %s\n", | ||
1094 | user_mainfw); | ||
1095 | goto fail; | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | if (*helper && *mainfw) | ||
1100 | return 0; | ||
1101 | |||
1102 | /* Otherwise search for firmware to use. If neither the helper or | ||
1103 | * the main firmware were specified by the user, then we need to | ||
1104 | * make sure that found helper & main are from the same entry in | ||
1105 | * fw_table. | ||
1106 | */ | ||
1107 | iter = fw_table; | ||
1108 | while (iter && iter->helper) { | ||
1109 | if (iter->model != card_model) | ||
1110 | goto next; | ||
1111 | |||
1112 | if (*helper == NULL) { | ||
1113 | ret = request_firmware(helper, iter->helper, dev); | ||
1114 | if (ret) | ||
1115 | goto next; | ||
1116 | |||
1117 | /* If the device has one-stage firmware (ie cf8305) and | ||
1118 | * we've got it then we don't need to bother with the | ||
1119 | * main firmware. | ||
1120 | */ | ||
1121 | if (iter->fwname == NULL) | ||
1122 | return 0; | ||
1123 | } | ||
1124 | |||
1125 | if (*mainfw == NULL) { | ||
1126 | ret = request_firmware(mainfw, iter->fwname, dev); | ||
1127 | if (ret && !user_helper) { | ||
1128 | /* Clear the helper if it wasn't user-specified | ||
1129 | * and the main firmware load failed, to ensure | ||
1130 | * we don't have mismatched firmware pairs. | ||
1131 | */ | ||
1132 | release_firmware(*helper); | ||
1133 | *helper = NULL; | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | if (*helper && *mainfw) | ||
1138 | return 0; | ||
1139 | |||
1140 | next: | ||
1141 | iter++; | ||
1142 | } | ||
1143 | |||
1144 | fail: | ||
1145 | /* Failed */ | ||
1146 | if (*helper) { | ||
1147 | release_firmware(*helper); | ||
1148 | *helper = NULL; | ||
1149 | } | ||
1150 | if (*mainfw) { | ||
1151 | release_firmware(*mainfw); | ||
1152 | *mainfw = NULL; | ||
1153 | } | ||
1154 | |||
1155 | return -ENOENT; | ||
1156 | } | ||
1157 | EXPORT_SYMBOL_GPL(lbs_get_firmware); | ||
1158 | |||
1050 | static int __init lbs_init_module(void) | 1159 | static int __init lbs_init_module(void) |
1051 | { | 1160 | { |
1052 | lbs_deb_enter(LBS_DEB_MAIN); | 1161 | lbs_deb_enter(LBS_DEB_MAIN); |