diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-04-26 15:03:48 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-26 15:03:48 -0400 |
commit | d9b8ae6bd8c3304569a25079fcdbebaa28a48ee4 (patch) | |
tree | 9ce3e4eb355685f970dd7333a0a935109aff0583 /drivers/net/wireless/mwifiex | |
parent | 872f24dbc604ef585ea7eec73020dcdfaffd1956 (diff) | |
parent | 94c514fe240fc0dd02187b78facefde8b6744634 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
drivers/net/wireless/iwlwifi/iwl-testmode.c
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r-- | drivers/net/wireless/mwifiex/11n_aggr.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/Kconfig | 11 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/cmdevt.c | 63 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/decl.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/fw.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/init.c | 64 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_cmd.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_rx.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_tx.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/txrx.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/usb.c | 1052 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/usb.h | 99 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/util.c | 22 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/wmm.c | 18 |
17 files changed, 1399 insertions, 71 deletions
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 9eefb2a0ce9f..ab84eb943749 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c | |||
@@ -233,21 +233,27 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, | |||
233 | 233 | ||
234 | skb_push(skb_aggr, headroom); | 234 | skb_push(skb_aggr, headroom); |
235 | 235 | ||
236 | /* | 236 | if (adapter->iface_type == MWIFIEX_USB) { |
237 | * Padding per MSDU will affect the length of next | 237 | adapter->data_sent = true; |
238 | * packet and hence the exact length of next packet | 238 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA, |
239 | * is uncertain here. | 239 | skb_aggr, NULL); |
240 | * | 240 | } else { |
241 | * Also, aggregation of transmission buffer, while | 241 | /* |
242 | * downloading the data to the card, wont gain much | 242 | * Padding per MSDU will affect the length of next |
243 | * on the AMSDU packets as the AMSDU packets utilizes | 243 | * packet and hence the exact length of next packet |
244 | * the transmission buffer space to the maximum | 244 | * is uncertain here. |
245 | * (adapter->tx_buf_size). | 245 | * |
246 | */ | 246 | * Also, aggregation of transmission buffer, while |
247 | tx_param.next_pkt_len = 0; | 247 | * downloading the data to the card, wont gain much |
248 | 248 | * on the AMSDU packets as the AMSDU packets utilizes | |
249 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | 249 | * the transmission buffer space to the maximum |
250 | skb_aggr, &tx_param); | 250 | * (adapter->tx_buf_size). |
251 | */ | ||
252 | tx_param.next_pkt_len = 0; | ||
253 | |||
254 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
255 | skb_aggr, &tx_param); | ||
256 | } | ||
251 | switch (ret) { | 257 | switch (ret) { |
252 | case -EBUSY: | 258 | case -EBUSY: |
253 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); | 259 | spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); |
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 2a078cea830a..7f91cc694787 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig | |||
@@ -30,3 +30,14 @@ config MWIFIEX_PCIE | |||
30 | 30 | ||
31 | If you choose to build it as a module, it will be called | 31 | If you choose to build it as a module, it will be called |
32 | mwifiex_pcie. | 32 | mwifiex_pcie. |
33 | |||
34 | config MWIFIEX_USB | ||
35 | tristate "Marvell WiFi-Ex Driver for USB8797" | ||
36 | depends on MWIFIEX && USB | ||
37 | select FW_LOADER | ||
38 | ---help--- | ||
39 | This adds support for wireless adapters based on Marvell | ||
40 | Avastar 88W8797 chipset with USB interface. | ||
41 | |||
42 | If you choose to build it as a module, it will be called | ||
43 | mwifiex_usb. | ||
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index b0257ad1bbed..5c1a46bf1e11 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile | |||
@@ -42,3 +42,6 @@ obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o | |||
42 | 42 | ||
43 | mwifiex_pcie-y += pcie.o | 43 | mwifiex_pcie-y += pcie.o |
44 | obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o | 44 | obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o |
45 | |||
46 | mwifiex_usb-y += usb.o | ||
47 | obj-$(CONFIG_MWIFIEX_USB) += mwifiex_usb.o | ||
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 07f6e0092552..1710beffb93a 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c | |||
@@ -139,6 +139,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, | |||
139 | uint16_t cmd_size; | 139 | uint16_t cmd_size; |
140 | struct timeval tstamp; | 140 | struct timeval tstamp; |
141 | unsigned long flags; | 141 | unsigned long flags; |
142 | __le32 tmp; | ||
142 | 143 | ||
143 | if (!adapter || !cmd_node) | 144 | if (!adapter || !cmd_node) |
144 | return -1; | 145 | return -1; |
@@ -178,15 +179,28 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, | |||
178 | le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, | 179 | le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, |
179 | le16_to_cpu(host_cmd->seq_num)); | 180 | le16_to_cpu(host_cmd->seq_num)); |
180 | 181 | ||
181 | skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); | 182 | if (adapter->iface_type == MWIFIEX_USB) { |
182 | 183 | tmp = cpu_to_le32(MWIFIEX_USB_TYPE_CMD); | |
183 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, | 184 | skb_push(cmd_node->cmd_skb, MWIFIEX_TYPE_LEN); |
184 | cmd_node->cmd_skb, NULL); | 185 | memcpy(cmd_node->cmd_skb->data, &tmp, MWIFIEX_TYPE_LEN); |
185 | 186 | adapter->cmd_sent = true; | |
186 | skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); | 187 | ret = adapter->if_ops.host_to_card(adapter, |
188 | MWIFIEX_USB_EP_CMD_EVENT, | ||
189 | cmd_node->cmd_skb, NULL); | ||
190 | skb_pull(cmd_node->cmd_skb, MWIFIEX_TYPE_LEN); | ||
191 | if (ret == -EBUSY) | ||
192 | cmd_node->cmd_skb = NULL; | ||
193 | } else { | ||
194 | skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); | ||
195 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, | ||
196 | cmd_node->cmd_skb, NULL); | ||
197 | skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); | ||
198 | } | ||
187 | 199 | ||
188 | if (ret == -1) { | 200 | if (ret == -1) { |
189 | dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); | 201 | dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); |
202 | if (adapter->iface_type == MWIFIEX_USB) | ||
203 | adapter->cmd_sent = false; | ||
190 | if (cmd_node->wait_q_enabled) | 204 | if (cmd_node->wait_q_enabled) |
191 | adapter->cmd_wait_q.status = -1; | 205 | adapter->cmd_wait_q.status = -1; |
192 | mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); | 206 | mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); |
@@ -232,6 +246,9 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) | |||
232 | struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = | 246 | struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = |
233 | (struct mwifiex_opt_sleep_confirm *) | 247 | (struct mwifiex_opt_sleep_confirm *) |
234 | adapter->sleep_cfm->data; | 248 | adapter->sleep_cfm->data; |
249 | struct sk_buff *sleep_cfm_tmp; | ||
250 | __le32 tmp; | ||
251 | |||
235 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | 252 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); |
236 | 253 | ||
237 | sleep_cfm_buf->seq_num = | 254 | sleep_cfm_buf->seq_num = |
@@ -240,10 +257,28 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) | |||
240 | priv->bss_type))); | 257 | priv->bss_type))); |
241 | adapter->seq_num++; | 258 | adapter->seq_num++; |
242 | 259 | ||
243 | skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); | 260 | if (adapter->iface_type == MWIFIEX_USB) { |
244 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, | 261 | sleep_cfm_tmp = |
245 | adapter->sleep_cfm, NULL); | 262 | dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm) |
246 | skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); | 263 | + MWIFIEX_TYPE_LEN); |
264 | skb_put(sleep_cfm_tmp, sizeof(struct mwifiex_opt_sleep_confirm) | ||
265 | + MWIFIEX_TYPE_LEN); | ||
266 | tmp = cpu_to_le32(MWIFIEX_USB_TYPE_CMD); | ||
267 | memcpy(sleep_cfm_tmp->data, &tmp, MWIFIEX_TYPE_LEN); | ||
268 | memcpy(sleep_cfm_tmp->data + MWIFIEX_TYPE_LEN, | ||
269 | adapter->sleep_cfm->data, | ||
270 | sizeof(struct mwifiex_opt_sleep_confirm)); | ||
271 | ret = adapter->if_ops.host_to_card(adapter, | ||
272 | MWIFIEX_USB_EP_CMD_EVENT, | ||
273 | sleep_cfm_tmp, NULL); | ||
274 | if (ret != -EBUSY) | ||
275 | dev_kfree_skb_any(sleep_cfm_tmp); | ||
276 | } else { | ||
277 | skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); | ||
278 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, | ||
279 | adapter->sleep_cfm, NULL); | ||
280 | skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); | ||
281 | } | ||
247 | 282 | ||
248 | if (ret == -1) { | 283 | if (ret == -1) { |
249 | dev_err(adapter->dev, "SLEEP_CFM: failed\n"); | 284 | dev_err(adapter->dev, "SLEEP_CFM: failed\n"); |
@@ -343,7 +378,12 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) | |||
343 | } | 378 | } |
344 | if (!cmd_array[i].resp_skb) | 379 | if (!cmd_array[i].resp_skb) |
345 | continue; | 380 | continue; |
346 | dev_kfree_skb_any(cmd_array[i].resp_skb); | 381 | |
382 | if (adapter->iface_type == MWIFIEX_USB) | ||
383 | adapter->if_ops.cmdrsp_complete(adapter, | ||
384 | cmd_array[i].resp_skb); | ||
385 | else | ||
386 | dev_kfree_skb_any(cmd_array[i].resp_skb); | ||
347 | } | 387 | } |
348 | /* Release struct cmd_ctrl_node */ | 388 | /* Release struct cmd_ctrl_node */ |
349 | if (adapter->cmd_pool) { | 389 | if (adapter->cmd_pool) { |
@@ -1083,6 +1123,7 @@ mwifiex_process_hs_config(struct mwifiex_adapter *adapter) | |||
1083 | MWIFIEX_BSS_ROLE_ANY), | 1123 | MWIFIEX_BSS_ROLE_ANY), |
1084 | false); | 1124 | false); |
1085 | } | 1125 | } |
1126 | EXPORT_SYMBOL_GPL(mwifiex_process_hs_config); | ||
1086 | 1127 | ||
1087 | /* | 1128 | /* |
1088 | * This function handles the command response of a sleep confirm command. | 1129 | * This function handles the command response of a sleep confirm command. |
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index be5fd1652e53..d04aba4131dc 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h | |||
@@ -53,6 +53,7 @@ | |||
53 | #define MWIFIEX_RATE_BITMAP_MCS127 159 | 53 | #define MWIFIEX_RATE_BITMAP_MCS127 159 |
54 | 54 | ||
55 | #define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) | 55 | #define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) |
56 | #define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024) | ||
56 | 57 | ||
57 | #define MWIFIEX_RTS_MIN_VALUE (0) | 58 | #define MWIFIEX_RTS_MIN_VALUE (0) |
58 | #define MWIFIEX_RTS_MAX_VALUE (2347) | 59 | #define MWIFIEX_RTS_MAX_VALUE (2347) |
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 6b15449a4cb7..2a2cabadb9b5 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -81,6 +81,11 @@ enum KEY_TYPE_ID { | |||
81 | #define FIRMWARE_READY_SDIO 0xfedc | 81 | #define FIRMWARE_READY_SDIO 0xfedc |
82 | #define FIRMWARE_READY_PCIE 0xfedcba00 | 82 | #define FIRMWARE_READY_PCIE 0xfedcba00 |
83 | 83 | ||
84 | enum mwifiex_usb_ep { | ||
85 | MWIFIEX_USB_EP_CMD_EVENT = 1, | ||
86 | MWIFIEX_USB_EP_DATA = 2, | ||
87 | }; | ||
88 | |||
84 | enum MWIFIEX_802_11_PRIVACY_FILTER { | 89 | enum MWIFIEX_802_11_PRIVACY_FILTER { |
85 | MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, | 90 | MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, |
86 | MWIFIEX_802_11_PRIV_FILTER_8021X_WEP | 91 | MWIFIEX_802_11_PRIV_FILTER_8021X_WEP |
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 0d55c5b542d7..d440c3eb640b 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -188,10 +188,10 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) | |||
188 | 188 | ||
189 | adapter->cmd_sent = false; | 189 | adapter->cmd_sent = false; |
190 | 190 | ||
191 | if (adapter->iface_type == MWIFIEX_PCIE) | 191 | if (adapter->iface_type == MWIFIEX_SDIO) |
192 | adapter->data_sent = false; | ||
193 | else | ||
194 | adapter->data_sent = true; | 192 | adapter->data_sent = true; |
193 | else | ||
194 | adapter->data_sent = false; | ||
195 | 195 | ||
196 | adapter->cmd_resp_received = false; | 196 | adapter->cmd_resp_received = false; |
197 | adapter->event_received = false; | 197 | adapter->event_received = false; |
@@ -379,7 +379,8 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) | |||
379 | 379 | ||
380 | dev_dbg(adapter->dev, "info: free scan table\n"); | 380 | dev_dbg(adapter->dev, "info: free scan table\n"); |
381 | 381 | ||
382 | adapter->if_ops.cleanup_if(adapter); | 382 | if (adapter->if_ops.cleanup_if) |
383 | adapter->if_ops.cleanup_if(adapter); | ||
383 | 384 | ||
384 | if (adapter->sleep_cfm) | 385 | if (adapter->sleep_cfm) |
385 | dev_kfree_skb_any(adapter->sleep_cfm); | 386 | dev_kfree_skb_any(adapter->sleep_cfm); |
@@ -419,6 +420,8 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) | |||
419 | spin_lock_init(&adapter->cmd_pending_q_lock); | 420 | spin_lock_init(&adapter->cmd_pending_q_lock); |
420 | spin_lock_init(&adapter->scan_pending_q_lock); | 421 | spin_lock_init(&adapter->scan_pending_q_lock); |
421 | 422 | ||
423 | skb_queue_head_init(&adapter->usb_rx_data_q); | ||
424 | |||
422 | for (i = 0; i < adapter->priv_num; ++i) { | 425 | for (i = 0; i < adapter->priv_num; ++i) { |
423 | INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); | 426 | INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); |
424 | adapter->bss_prio_tbl[i].bss_prio_cur = NULL; | 427 | adapter->bss_prio_tbl[i].bss_prio_cur = NULL; |
@@ -574,6 +577,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | |||
574 | struct mwifiex_private *priv; | 577 | struct mwifiex_private *priv; |
575 | s32 i; | 578 | s32 i; |
576 | unsigned long flags; | 579 | unsigned long flags; |
580 | struct sk_buff *skb; | ||
577 | 581 | ||
578 | /* mwifiex already shutdown */ | 582 | /* mwifiex already shutdown */ |
579 | if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) | 583 | if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) |
@@ -601,6 +605,18 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | |||
601 | 605 | ||
602 | spin_lock_irqsave(&adapter->mwifiex_lock, flags); | 606 | spin_lock_irqsave(&adapter->mwifiex_lock, flags); |
603 | 607 | ||
608 | if (adapter->if_ops.data_complete) { | ||
609 | while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) { | ||
610 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
611 | |||
612 | priv = adapter->priv[rx_info->bss_num]; | ||
613 | if (priv) | ||
614 | priv->stats.rx_dropped++; | ||
615 | |||
616 | adapter->if_ops.data_complete(adapter, skb); | ||
617 | } | ||
618 | } | ||
619 | |||
604 | /* Free adapter structure */ | 620 | /* Free adapter structure */ |
605 | mwifiex_free_adapter(adapter); | 621 | mwifiex_free_adapter(adapter); |
606 | 622 | ||
@@ -630,24 +646,28 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, | |||
630 | int ret; | 646 | int ret; |
631 | u32 poll_num = 1; | 647 | u32 poll_num = 1; |
632 | 648 | ||
633 | adapter->winner = 0; | 649 | if (adapter->if_ops.check_fw_status) { |
650 | adapter->winner = 0; | ||
634 | 651 | ||
635 | /* Check if firmware is already running */ | 652 | /* check if firmware is already running */ |
636 | ret = adapter->if_ops.check_fw_status(adapter, poll_num); | 653 | ret = adapter->if_ops.check_fw_status(adapter, poll_num); |
637 | if (!ret) { | 654 | if (!ret) { |
638 | dev_notice(adapter->dev, | 655 | dev_notice(adapter->dev, |
639 | "WLAN FW already running! Skip FW download\n"); | 656 | "WLAN FW already running! Skip FW dnld\n"); |
640 | goto done; | 657 | goto done; |
641 | } | 658 | } |
642 | poll_num = MAX_FIRMWARE_POLL_TRIES; | 659 | |
643 | 660 | poll_num = MAX_FIRMWARE_POLL_TRIES; | |
644 | /* Check if we are the winner for downloading FW */ | 661 | |
645 | if (!adapter->winner) { | 662 | /* check if we are the winner for downloading FW */ |
646 | dev_notice(adapter->dev, | 663 | if (!adapter->winner) { |
647 | "Other intf already running! Skip FW download\n"); | 664 | dev_notice(adapter->dev, |
648 | poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; | 665 | "FW already running! Skip FW dnld\n"); |
649 | goto poll_fw; | 666 | poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; |
667 | goto poll_fw; | ||
668 | } | ||
650 | } | 669 | } |
670 | |||
651 | if (pmfw) { | 671 | if (pmfw) { |
652 | /* Download firmware with helper */ | 672 | /* Download firmware with helper */ |
653 | ret = adapter->if_ops.prog_fw(adapter, pmfw); | 673 | ret = adapter->if_ops.prog_fw(adapter, pmfw); |
@@ -666,6 +686,8 @@ poll_fw: | |||
666 | } | 686 | } |
667 | done: | 687 | done: |
668 | /* re-enable host interrupt for mwifiex after fw dnld is successful */ | 688 | /* re-enable host interrupt for mwifiex after fw dnld is successful */ |
669 | adapter->if_ops.enable_int(adapter); | 689 | if (adapter->if_ops.enable_int) |
690 | adapter->if_ops.enable_int(adapter); | ||
691 | |||
670 | return ret; | 692 | return ret; |
671 | } | 693 | } |
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 245b7329e0c9..be0f0e583f75 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -58,8 +58,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | |||
58 | memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); | 58 | memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); |
59 | 59 | ||
60 | /* card specific initialization has been deferred until now .. */ | 60 | /* card specific initialization has been deferred until now .. */ |
61 | if (adapter->if_ops.init_if(adapter)) | 61 | if (adapter->if_ops.init_if) |
62 | goto error; | 62 | if (adapter->if_ops.init_if(adapter)) |
63 | goto error; | ||
63 | 64 | ||
64 | adapter->priv_num = 0; | 65 | adapter->priv_num = 0; |
65 | 66 | ||
@@ -140,6 +141,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) | |||
140 | { | 141 | { |
141 | int ret = 0; | 142 | int ret = 0; |
142 | unsigned long flags; | 143 | unsigned long flags; |
144 | struct sk_buff *skb; | ||
143 | 145 | ||
144 | spin_lock_irqsave(&adapter->main_proc_lock, flags); | 146 | spin_lock_irqsave(&adapter->main_proc_lock, flags); |
145 | 147 | ||
@@ -161,7 +163,8 @@ process_start: | |||
161 | if (adapter->int_status) { | 163 | if (adapter->int_status) { |
162 | if (adapter->hs_activated) | 164 | if (adapter->hs_activated) |
163 | mwifiex_process_hs_config(adapter); | 165 | mwifiex_process_hs_config(adapter); |
164 | adapter->if_ops.process_int_status(adapter); | 166 | if (adapter->if_ops.process_int_status) |
167 | adapter->if_ops.process_int_status(adapter); | ||
165 | } | 168 | } |
166 | 169 | ||
167 | /* Need to wake up the card ? */ | 170 | /* Need to wake up the card ? */ |
@@ -174,6 +177,7 @@ process_start: | |||
174 | adapter->if_ops.wakeup(adapter); | 177 | adapter->if_ops.wakeup(adapter); |
175 | continue; | 178 | continue; |
176 | } | 179 | } |
180 | |||
177 | if (IS_CARD_RX_RCVD(adapter)) { | 181 | if (IS_CARD_RX_RCVD(adapter)) { |
178 | adapter->pm_wakeup_fw_try = false; | 182 | adapter->pm_wakeup_fw_try = false; |
179 | if (adapter->ps_state == PS_STATE_SLEEP) | 183 | if (adapter->ps_state == PS_STATE_SLEEP) |
@@ -194,6 +198,11 @@ process_start: | |||
194 | } | 198 | } |
195 | } | 199 | } |
196 | 200 | ||
201 | /* Check Rx data for USB */ | ||
202 | if (adapter->iface_type == MWIFIEX_USB) | ||
203 | while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) | ||
204 | mwifiex_handle_rx_packet(adapter, skb); | ||
205 | |||
197 | /* Check for Cmd Resp */ | 206 | /* Check for Cmd Resp */ |
198 | if (adapter->cmd_resp_received) { | 207 | if (adapter->cmd_resp_received) { |
199 | adapter->cmd_resp_received = false; | 208 | adapter->cmd_resp_received = false; |
@@ -317,7 +326,10 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
317 | fw.fw_buf = (u8 *) adapter->firmware->data; | 326 | fw.fw_buf = (u8 *) adapter->firmware->data; |
318 | fw.fw_len = adapter->firmware->size; | 327 | fw.fw_len = adapter->firmware->size; |
319 | 328 | ||
320 | ret = mwifiex_dnld_fw(adapter, &fw); | 329 | if (adapter->if_ops.dnld_fw) |
330 | ret = adapter->if_ops.dnld_fw(adapter, &fw); | ||
331 | else | ||
332 | ret = mwifiex_dnld_fw(adapter, &fw); | ||
321 | if (ret == -1) | 333 | if (ret == -1) |
322 | goto done; | 334 | goto done; |
323 | 335 | ||
@@ -731,7 +743,8 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
731 | 743 | ||
732 | err_init_fw: | 744 | err_init_fw: |
733 | pr_debug("info: %s: unregister device\n", __func__); | 745 | pr_debug("info: %s: unregister device\n", __func__); |
734 | adapter->if_ops.unregister_dev(adapter); | 746 | if (adapter->if_ops.unregister_dev) |
747 | adapter->if_ops.unregister_dev(adapter); | ||
735 | err_registerdev: | 748 | err_registerdev: |
736 | adapter->surprise_removed = true; | 749 | adapter->surprise_removed = true; |
737 | mwifiex_terminate_workqueue(adapter); | 750 | mwifiex_terminate_workqueue(adapter); |
@@ -836,7 +849,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) | |||
836 | 849 | ||
837 | /* Unregister device */ | 850 | /* Unregister device */ |
838 | dev_dbg(adapter->dev, "info: unregister device\n"); | 851 | dev_dbg(adapter->dev, "info: unregister device\n"); |
839 | adapter->if_ops.unregister_dev(adapter); | 852 | if (adapter->if_ops.unregister_dev) |
853 | adapter->if_ops.unregister_dev(adapter); | ||
840 | /* Free adapter structure */ | 854 | /* Free adapter structure */ |
841 | dev_dbg(adapter->dev, "info: free adapter\n"); | 855 | dev_dbg(adapter->dev, "info: free adapter\n"); |
842 | mwifiex_free_adapter(adapter); | 856 | mwifiex_free_adapter(adapter); |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index a4000f9608d5..324ad390cacd 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -92,9 +92,16 @@ enum { | |||
92 | #define MWIFIEX_OUI_NOT_PRESENT 0 | 92 | #define MWIFIEX_OUI_NOT_PRESENT 0 |
93 | #define MWIFIEX_OUI_PRESENT 1 | 93 | #define MWIFIEX_OUI_PRESENT 1 |
94 | 94 | ||
95 | /* | ||
96 | * Do not check for data_received for USB, as data_received | ||
97 | * is handled in mwifiex_usb_recv for USB | ||
98 | */ | ||
95 | #define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ | 99 | #define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ |
96 | adapter->event_received || \ | 100 | adapter->event_received || \ |
97 | adapter->data_received) | 101 | ((adapter->iface_type != MWIFIEX_USB) && \ |
102 | adapter->data_received) || \ | ||
103 | ((adapter->iface_type == MWIFIEX_USB) && \ | ||
104 | !skb_queue_empty(&adapter->usb_rx_data_q))) | ||
98 | 105 | ||
99 | #define MWIFIEX_TYPE_CMD 1 | 106 | #define MWIFIEX_TYPE_CMD 1 |
100 | #define MWIFIEX_TYPE_DATA 0 | 107 | #define MWIFIEX_TYPE_DATA 0 |
@@ -110,6 +117,11 @@ enum { | |||
110 | 117 | ||
111 | #define MWIFIEX_EVENT_HEADER_LEN 4 | 118 | #define MWIFIEX_EVENT_HEADER_LEN 4 |
112 | 119 | ||
120 | #define MWIFIEX_TYPE_LEN 4 | ||
121 | #define MWIFIEX_USB_TYPE_CMD 0xF00DFACE | ||
122 | #define MWIFIEX_USB_TYPE_DATA 0xBEADC0DE | ||
123 | #define MWIFIEX_USB_TYPE_EVENT 0xBEEFFACE | ||
124 | |||
113 | struct mwifiex_dbg { | 125 | struct mwifiex_dbg { |
114 | u32 num_cmd_host_to_card_failure; | 126 | u32 num_cmd_host_to_card_failure; |
115 | u32 num_cmd_sleep_cfm_host_to_card_failure; | 127 | u32 num_cmd_sleep_cfm_host_to_card_failure; |
@@ -162,6 +174,7 @@ enum MWIFIEX_PS_STATE { | |||
162 | enum mwifiex_iface_type { | 174 | enum mwifiex_iface_type { |
163 | MWIFIEX_SDIO, | 175 | MWIFIEX_SDIO, |
164 | MWIFIEX_PCIE, | 176 | MWIFIEX_PCIE, |
177 | MWIFIEX_USB | ||
165 | }; | 178 | }; |
166 | 179 | ||
167 | struct mwifiex_add_ba_param { | 180 | struct mwifiex_add_ba_param { |
@@ -546,6 +559,8 @@ struct mwifiex_if_ops { | |||
546 | void (*cleanup_mpa_buf) (struct mwifiex_adapter *); | 559 | void (*cleanup_mpa_buf) (struct mwifiex_adapter *); |
547 | int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); | 560 | int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); |
548 | int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); | 561 | int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); |
562 | int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *); | ||
563 | int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); | ||
549 | }; | 564 | }; |
550 | 565 | ||
551 | struct mwifiex_adapter { | 566 | struct mwifiex_adapter { |
@@ -608,6 +623,7 @@ struct mwifiex_adapter { | |||
608 | struct list_head scan_pending_q; | 623 | struct list_head scan_pending_q; |
609 | /* spin lock for scan_pending_q */ | 624 | /* spin lock for scan_pending_q */ |
610 | spinlock_t scan_pending_q_lock; | 625 | spinlock_t scan_pending_q_lock; |
626 | struct sk_buff_head usb_rx_data_q; | ||
611 | u32 scan_processing; | 627 | u32 scan_processing; |
612 | u16 region_code; | 628 | u16 region_code; |
613 | struct mwifiex_802_11d_domain_reg domain_reg; | 629 | struct mwifiex_802_11d_domain_reg domain_reg; |
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 1f7110577b9d..87ed2a1f6cd9 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c | |||
@@ -1293,7 +1293,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) | |||
1293 | if (ret) | 1293 | if (ret) |
1294 | return -1; | 1294 | return -1; |
1295 | 1295 | ||
1296 | if (first_sta) { | 1296 | if (first_sta && (priv->adapter->iface_type != MWIFIEX_USB)) { |
1297 | /* Enable auto deep sleep */ | 1297 | /* Enable auto deep sleep */ |
1298 | auto_ds.auto_ds = DEEP_SLEEP_ON; | 1298 | auto_ds.auto_ds = DEEP_SLEEP_ON; |
1299 | auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; | 1299 | auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; |
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 750b695aca12..02ce3b77d3e7 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c | |||
@@ -145,7 +145,12 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, | |||
145 | " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, | 145 | " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, |
146 | local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length); | 146 | local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length); |
147 | priv->stats.rx_dropped++; | 147 | priv->stats.rx_dropped++; |
148 | dev_kfree_skb_any(skb); | 148 | |
149 | if (adapter->if_ops.data_complete) | ||
150 | adapter->if_ops.data_complete(adapter, skb); | ||
151 | else | ||
152 | dev_kfree_skb_any(skb); | ||
153 | |||
149 | return ret; | 154 | return ret; |
150 | } | 155 | } |
151 | 156 | ||
@@ -196,8 +201,12 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, | |||
196 | (u8) local_rx_pd->rx_pkt_type, | 201 | (u8) local_rx_pd->rx_pkt_type, |
197 | skb); | 202 | skb); |
198 | 203 | ||
199 | if (ret || (rx_pkt_type == PKT_TYPE_BAR)) | 204 | if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { |
200 | dev_kfree_skb_any(skb); | 205 | if (adapter->if_ops.data_complete) |
206 | adapter->if_ops.data_complete(adapter, skb); | ||
207 | else | ||
208 | dev_kfree_skb_any(skb); | ||
209 | } | ||
201 | 210 | ||
202 | if (ret) | 211 | if (ret) |
203 | priv->stats.rx_dropped++; | 212 | priv->stats.rx_dropped++; |
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index 7af534feb420..0a046d3a0c16 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c | |||
@@ -149,10 +149,14 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) | |||
149 | local_tx_pd->bss_num = priv->bss_num; | 149 | local_tx_pd->bss_num = priv->bss_num; |
150 | local_tx_pd->bss_type = priv->bss_type; | 150 | local_tx_pd->bss_type = priv->bss_type; |
151 | 151 | ||
152 | skb_push(skb, INTF_HEADER_LEN); | 152 | if (adapter->iface_type == MWIFIEX_USB) { |
153 | 153 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA, | |
154 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | 154 | skb, NULL); |
155 | skb, NULL); | 155 | } else { |
156 | skb_push(skb, INTF_HEADER_LEN); | ||
157 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
158 | skb, NULL); | ||
159 | } | ||
156 | switch (ret) { | 160 | switch (ret) { |
157 | case -EBUSY: | 161 | case -EBUSY: |
158 | adapter->data_sent = true; | 162 | adapter->data_sent = true; |
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index d2af8cb98541..e2faec4db108 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c | |||
@@ -77,12 +77,23 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, | |||
77 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) | 77 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) |
78 | local_tx_pd = | 78 | local_tx_pd = |
79 | (struct txpd *) (head_ptr + INTF_HEADER_LEN); | 79 | (struct txpd *) (head_ptr + INTF_HEADER_LEN); |
80 | 80 | if (adapter->iface_type == MWIFIEX_USB) { | |
81 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | 81 | adapter->data_sent = true; |
82 | skb, tx_param); | 82 | skb_pull(skb, INTF_HEADER_LEN); |
83 | ret = adapter->if_ops.host_to_card(adapter, | ||
84 | MWIFIEX_USB_EP_DATA, | ||
85 | skb, NULL); | ||
86 | } else { | ||
87 | ret = adapter->if_ops.host_to_card(adapter, | ||
88 | MWIFIEX_TYPE_DATA, | ||
89 | skb, tx_param); | ||
90 | } | ||
83 | } | 91 | } |
84 | 92 | ||
85 | switch (ret) { | 93 | switch (ret) { |
94 | case -ENOSR: | ||
95 | dev_err(adapter->dev, "data: -ENOSR is returned\n"); | ||
96 | break; | ||
86 | case -EBUSY: | 97 | case -EBUSY: |
87 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && | 98 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && |
88 | (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { | 99 | (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { |
@@ -135,6 +146,9 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, | |||
135 | if (!priv) | 146 | if (!priv) |
136 | goto done; | 147 | goto done; |
137 | 148 | ||
149 | if (adapter->iface_type == MWIFIEX_USB) | ||
150 | adapter->data_sent = false; | ||
151 | |||
138 | mwifiex_set_trans_start(priv->netdev); | 152 | mwifiex_set_trans_start(priv->netdev); |
139 | if (!status) { | 153 | if (!status) { |
140 | priv->stats.tx_packets++; | 154 | priv->stats.tx_packets++; |
@@ -162,4 +176,5 @@ done: | |||
162 | 176 | ||
163 | return 0; | 177 | return 0; |
164 | } | 178 | } |
179 | EXPORT_SYMBOL_GPL(mwifiex_write_data_complete); | ||
165 | 180 | ||
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c new file mode 100644 index 000000000000..49ebf20c56eb --- /dev/null +++ b/drivers/net/wireless/mwifiex/usb.c | |||
@@ -0,0 +1,1052 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: USB specific handling | ||
3 | * | ||
4 | * Copyright (C) 2012, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "main.h" | ||
21 | #include "usb.h" | ||
22 | |||
23 | #define USB_VERSION "1.0" | ||
24 | |||
25 | static const char usbdriver_name[] = "usb8797"; | ||
26 | |||
27 | static u8 user_rmmod; | ||
28 | static struct mwifiex_if_ops usb_ops; | ||
29 | static struct semaphore add_remove_card_sem; | ||
30 | |||
31 | static struct usb_device_id mwifiex_usb_table[] = { | ||
32 | {USB_DEVICE(USB8797_VID, USB8797_PID_1)}, | ||
33 | {USB_DEVICE_AND_INTERFACE_INFO(USB8797_VID, USB8797_PID_2, | ||
34 | USB_CLASS_VENDOR_SPEC, | ||
35 | USB_SUBCLASS_VENDOR_SPEC, 0xff)}, | ||
36 | { } /* Terminating entry */ | ||
37 | }; | ||
38 | |||
39 | MODULE_DEVICE_TABLE(usb, mwifiex_usb_table); | ||
40 | |||
41 | static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size); | ||
42 | |||
43 | /* This function handles received packet. Necessary action is taken based on | ||
44 | * cmd/event/data. | ||
45 | */ | ||
46 | static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, | ||
47 | struct sk_buff *skb, u8 ep) | ||
48 | { | ||
49 | struct device *dev = adapter->dev; | ||
50 | u32 recv_type; | ||
51 | __le32 tmp; | ||
52 | |||
53 | if (adapter->hs_activated) | ||
54 | mwifiex_process_hs_config(adapter); | ||
55 | |||
56 | if (skb->len < INTF_HEADER_LEN) { | ||
57 | dev_err(dev, "%s: invalid skb->len\n", __func__); | ||
58 | return -1; | ||
59 | } | ||
60 | |||
61 | switch (ep) { | ||
62 | case MWIFIEX_USB_EP_CMD_EVENT: | ||
63 | dev_dbg(dev, "%s: EP_CMD_EVENT\n", __func__); | ||
64 | skb_copy_from_linear_data(skb, &tmp, INTF_HEADER_LEN); | ||
65 | recv_type = le32_to_cpu(tmp); | ||
66 | skb_pull(skb, INTF_HEADER_LEN); | ||
67 | |||
68 | switch (recv_type) { | ||
69 | case MWIFIEX_USB_TYPE_CMD: | ||
70 | if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) { | ||
71 | dev_err(dev, "CMD: skb->len too large\n"); | ||
72 | return -1; | ||
73 | } else if (!adapter->curr_cmd) { | ||
74 | dev_dbg(dev, "CMD: no curr_cmd\n"); | ||
75 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) { | ||
76 | mwifiex_process_sleep_confirm_resp( | ||
77 | adapter, skb->data, | ||
78 | skb->len); | ||
79 | return 0; | ||
80 | } | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | adapter->curr_cmd->resp_skb = skb; | ||
85 | adapter->cmd_resp_received = true; | ||
86 | break; | ||
87 | case MWIFIEX_USB_TYPE_EVENT: | ||
88 | if (skb->len < sizeof(u32)) { | ||
89 | dev_err(dev, "EVENT: skb->len too small\n"); | ||
90 | return -1; | ||
91 | } | ||
92 | skb_copy_from_linear_data(skb, &tmp, sizeof(u32)); | ||
93 | adapter->event_cause = le32_to_cpu(tmp); | ||
94 | skb_pull(skb, sizeof(u32)); | ||
95 | dev_dbg(dev, "event_cause %#x\n", adapter->event_cause); | ||
96 | |||
97 | if (skb->len > MAX_EVENT_SIZE) { | ||
98 | dev_err(dev, "EVENT: event body too large\n"); | ||
99 | return -1; | ||
100 | } | ||
101 | |||
102 | skb_copy_from_linear_data(skb, adapter->event_body, | ||
103 | skb->len); | ||
104 | adapter->event_received = true; | ||
105 | adapter->event_skb = skb; | ||
106 | break; | ||
107 | default: | ||
108 | dev_err(dev, "unknown recv_type %#x\n", recv_type); | ||
109 | return -1; | ||
110 | } | ||
111 | break; | ||
112 | case MWIFIEX_USB_EP_DATA: | ||
113 | dev_dbg(dev, "%s: EP_DATA\n", __func__); | ||
114 | if (skb->len > MWIFIEX_RX_DATA_BUF_SIZE) { | ||
115 | dev_err(dev, "DATA: skb->len too large\n"); | ||
116 | return -1; | ||
117 | } | ||
118 | skb_queue_tail(&adapter->usb_rx_data_q, skb); | ||
119 | adapter->data_received = true; | ||
120 | break; | ||
121 | default: | ||
122 | dev_err(dev, "%s: unknown endport %#x\n", __func__, ep); | ||
123 | return -1; | ||
124 | } | ||
125 | |||
126 | return -EINPROGRESS; | ||
127 | } | ||
128 | |||
129 | static void mwifiex_usb_rx_complete(struct urb *urb) | ||
130 | { | ||
131 | struct urb_context *context = (struct urb_context *)urb->context; | ||
132 | struct mwifiex_adapter *adapter = context->adapter; | ||
133 | struct sk_buff *skb = context->skb; | ||
134 | struct usb_card_rec *card; | ||
135 | int recv_length = urb->actual_length; | ||
136 | int size, status; | ||
137 | |||
138 | if (!adapter || !adapter->card) { | ||
139 | pr_err("mwifiex adapter or card structure is not valid\n"); | ||
140 | return; | ||
141 | } | ||
142 | |||
143 | card = (struct usb_card_rec *)adapter->card; | ||
144 | if (card->rx_cmd_ep == context->ep) | ||
145 | atomic_dec(&card->rx_cmd_urb_pending); | ||
146 | else | ||
147 | atomic_dec(&card->rx_data_urb_pending); | ||
148 | |||
149 | if (recv_length) { | ||
150 | if (urb->status || (adapter->surprise_removed)) { | ||
151 | dev_err(adapter->dev, | ||
152 | "URB status is failed: %d\n", urb->status); | ||
153 | /* Do not free skb in case of command ep */ | ||
154 | if (card->rx_cmd_ep != context->ep) | ||
155 | dev_kfree_skb_any(skb); | ||
156 | goto setup_for_next; | ||
157 | } | ||
158 | if (skb->len > recv_length) | ||
159 | skb_trim(skb, recv_length); | ||
160 | else | ||
161 | skb_put(skb, recv_length - skb->len); | ||
162 | |||
163 | atomic_inc(&adapter->rx_pending); | ||
164 | status = mwifiex_usb_recv(adapter, skb, context->ep); | ||
165 | |||
166 | dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n", | ||
167 | recv_length, status); | ||
168 | if (status == -EINPROGRESS) { | ||
169 | queue_work(adapter->workqueue, &adapter->main_work); | ||
170 | |||
171 | /* urb for data_ep is re-submitted now; | ||
172 | * urb for cmd_ep will be re-submitted in callback | ||
173 | * mwifiex_usb_recv_complete | ||
174 | */ | ||
175 | if (card->rx_cmd_ep == context->ep) | ||
176 | return; | ||
177 | } else { | ||
178 | atomic_dec(&adapter->rx_pending); | ||
179 | if (status == -1) | ||
180 | dev_err(adapter->dev, | ||
181 | "received data processing failed!\n"); | ||
182 | |||
183 | /* Do not free skb in case of command ep */ | ||
184 | if (card->rx_cmd_ep != context->ep) | ||
185 | dev_kfree_skb_any(skb); | ||
186 | } | ||
187 | } else if (urb->status) { | ||
188 | if (!adapter->is_suspended) { | ||
189 | dev_warn(adapter->dev, | ||
190 | "Card is removed: %d\n", urb->status); | ||
191 | adapter->surprise_removed = true; | ||
192 | } | ||
193 | dev_kfree_skb_any(skb); | ||
194 | return; | ||
195 | } else { | ||
196 | /* Do not free skb in case of command ep */ | ||
197 | if (card->rx_cmd_ep != context->ep) | ||
198 | dev_kfree_skb_any(skb); | ||
199 | |||
200 | /* fall through setup_for_next */ | ||
201 | } | ||
202 | |||
203 | setup_for_next: | ||
204 | if (card->rx_cmd_ep == context->ep) | ||
205 | size = MWIFIEX_RX_CMD_BUF_SIZE; | ||
206 | else | ||
207 | size = MWIFIEX_RX_DATA_BUF_SIZE; | ||
208 | |||
209 | mwifiex_usb_submit_rx_urb(context, size); | ||
210 | |||
211 | return; | ||
212 | } | ||
213 | |||
214 | static void mwifiex_usb_tx_complete(struct urb *urb) | ||
215 | { | ||
216 | struct urb_context *context = (struct urb_context *)(urb->context); | ||
217 | struct mwifiex_adapter *adapter = context->adapter; | ||
218 | struct usb_card_rec *card = adapter->card; | ||
219 | |||
220 | dev_dbg(adapter->dev, "%s: status: %d\n", __func__, urb->status); | ||
221 | |||
222 | if (context->ep == card->tx_cmd_ep) { | ||
223 | dev_dbg(adapter->dev, "%s: CMD\n", __func__); | ||
224 | atomic_dec(&card->tx_cmd_urb_pending); | ||
225 | adapter->cmd_sent = false; | ||
226 | } else { | ||
227 | dev_dbg(adapter->dev, "%s: DATA\n", __func__); | ||
228 | atomic_dec(&card->tx_data_urb_pending); | ||
229 | mwifiex_write_data_complete(adapter, context->skb, | ||
230 | urb->status ? -1 : 0); | ||
231 | } | ||
232 | |||
233 | queue_work(adapter->workqueue, &adapter->main_work); | ||
234 | |||
235 | return; | ||
236 | } | ||
237 | |||
238 | static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size) | ||
239 | { | ||
240 | struct mwifiex_adapter *adapter = ctx->adapter; | ||
241 | struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; | ||
242 | |||
243 | if (card->rx_cmd_ep != ctx->ep) { | ||
244 | ctx->skb = dev_alloc_skb(size); | ||
245 | if (!ctx->skb) { | ||
246 | dev_err(adapter->dev, | ||
247 | "%s: dev_alloc_skb failed\n", __func__); | ||
248 | return -ENOMEM; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | usb_fill_bulk_urb(ctx->urb, card->udev, | ||
253 | usb_rcvbulkpipe(card->udev, ctx->ep), ctx->skb->data, | ||
254 | size, mwifiex_usb_rx_complete, (void *)ctx); | ||
255 | |||
256 | if (card->rx_cmd_ep == ctx->ep) | ||
257 | atomic_inc(&card->rx_cmd_urb_pending); | ||
258 | else | ||
259 | atomic_inc(&card->rx_data_urb_pending); | ||
260 | |||
261 | if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) { | ||
262 | dev_err(adapter->dev, "usb_submit_urb failed\n"); | ||
263 | dev_kfree_skb_any(ctx->skb); | ||
264 | ctx->skb = NULL; | ||
265 | |||
266 | if (card->rx_cmd_ep == ctx->ep) | ||
267 | atomic_dec(&card->rx_cmd_urb_pending); | ||
268 | else | ||
269 | atomic_dec(&card->rx_data_urb_pending); | ||
270 | |||
271 | return -1; | ||
272 | } | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static void mwifiex_usb_free(struct usb_card_rec *card) | ||
278 | { | ||
279 | int i; | ||
280 | |||
281 | if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) | ||
282 | usb_kill_urb(card->rx_cmd.urb); | ||
283 | |||
284 | usb_free_urb(card->rx_cmd.urb); | ||
285 | card->rx_cmd.urb = NULL; | ||
286 | |||
287 | if (atomic_read(&card->rx_data_urb_pending)) | ||
288 | for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) | ||
289 | if (card->rx_data_list[i].urb) | ||
290 | usb_kill_urb(card->rx_data_list[i].urb); | ||
291 | |||
292 | for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { | ||
293 | usb_free_urb(card->rx_data_list[i].urb); | ||
294 | card->rx_data_list[i].urb = NULL; | ||
295 | } | ||
296 | |||
297 | for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) { | ||
298 | usb_free_urb(card->tx_data_list[i].urb); | ||
299 | card->tx_data_list[i].urb = NULL; | ||
300 | } | ||
301 | |||
302 | usb_free_urb(card->tx_cmd.urb); | ||
303 | card->tx_cmd.urb = NULL; | ||
304 | |||
305 | return; | ||
306 | } | ||
307 | |||
308 | /* This function probes an mwifiex device and registers it. It allocates | ||
309 | * the card structure, initiates the device registration and initialization | ||
310 | * procedure by adding a logical interface. | ||
311 | */ | ||
312 | static int mwifiex_usb_probe(struct usb_interface *intf, | ||
313 | const struct usb_device_id *id) | ||
314 | { | ||
315 | struct usb_device *udev = interface_to_usbdev(intf); | ||
316 | struct usb_host_interface *iface_desc = intf->cur_altsetting; | ||
317 | struct usb_endpoint_descriptor *epd; | ||
318 | int ret, i; | ||
319 | struct usb_card_rec *card; | ||
320 | u16 id_vendor, id_product, bcd_device, bcd_usb; | ||
321 | |||
322 | card = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); | ||
323 | if (!card) | ||
324 | return -ENOMEM; | ||
325 | |||
326 | id_vendor = le16_to_cpu(udev->descriptor.idVendor); | ||
327 | id_product = le16_to_cpu(udev->descriptor.idProduct); | ||
328 | bcd_device = le16_to_cpu(udev->descriptor.bcdDevice); | ||
329 | bcd_usb = le16_to_cpu(udev->descriptor.bcdUSB); | ||
330 | pr_debug("info: VID/PID = %X/%X, Boot2 version = %X\n", | ||
331 | id_vendor, id_product, bcd_device); | ||
332 | |||
333 | /* PID_1 is used for firmware downloading only */ | ||
334 | if (id_product == USB8797_PID_1) | ||
335 | card->usb_boot_state = USB8797_FW_DNLD; | ||
336 | else | ||
337 | card->usb_boot_state = USB8797_FW_READY; | ||
338 | |||
339 | card->udev = udev; | ||
340 | card->intf = intf; | ||
341 | |||
342 | pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocl=%#x\n", | ||
343 | udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, | ||
344 | udev->descriptor.bDeviceSubClass, | ||
345 | udev->descriptor.bDeviceProtocol); | ||
346 | |||
347 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | ||
348 | epd = &iface_desc->endpoint[i].desc; | ||
349 | if (usb_endpoint_dir_in(epd) && | ||
350 | usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && | ||
351 | usb_endpoint_xfer_bulk(epd)) { | ||
352 | pr_debug("info: bulk IN: max pkt size: %d, addr: %d\n", | ||
353 | le16_to_cpu(epd->wMaxPacketSize), | ||
354 | epd->bEndpointAddress); | ||
355 | card->rx_cmd_ep = usb_endpoint_num(epd); | ||
356 | atomic_set(&card->rx_cmd_urb_pending, 0); | ||
357 | } | ||
358 | if (usb_endpoint_dir_in(epd) && | ||
359 | usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA && | ||
360 | usb_endpoint_xfer_bulk(epd)) { | ||
361 | pr_debug("info: bulk IN: max pkt size: %d, addr: %d\n", | ||
362 | le16_to_cpu(epd->wMaxPacketSize), | ||
363 | epd->bEndpointAddress); | ||
364 | card->rx_data_ep = usb_endpoint_num(epd); | ||
365 | atomic_set(&card->rx_data_urb_pending, 0); | ||
366 | } | ||
367 | if (usb_endpoint_dir_out(epd) && | ||
368 | usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA && | ||
369 | usb_endpoint_xfer_bulk(epd)) { | ||
370 | pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n", | ||
371 | le16_to_cpu(epd->wMaxPacketSize), | ||
372 | epd->bEndpointAddress); | ||
373 | card->tx_data_ep = usb_endpoint_num(epd); | ||
374 | atomic_set(&card->tx_data_urb_pending, 0); | ||
375 | } | ||
376 | if (usb_endpoint_dir_out(epd) && | ||
377 | usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && | ||
378 | usb_endpoint_xfer_bulk(epd)) { | ||
379 | pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n", | ||
380 | le16_to_cpu(epd->wMaxPacketSize), | ||
381 | epd->bEndpointAddress); | ||
382 | card->tx_cmd_ep = usb_endpoint_num(epd); | ||
383 | atomic_set(&card->tx_cmd_urb_pending, 0); | ||
384 | card->bulk_out_maxpktsize = | ||
385 | le16_to_cpu(epd->wMaxPacketSize); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | usb_set_intfdata(intf, card); | ||
390 | |||
391 | ret = mwifiex_add_card(card, &add_remove_card_sem, &usb_ops, | ||
392 | MWIFIEX_USB); | ||
393 | if (ret) { | ||
394 | pr_err("%s: mwifiex_add_card failed: %d\n", __func__, ret); | ||
395 | usb_reset_device(udev); | ||
396 | kfree(card); | ||
397 | return ret; | ||
398 | } | ||
399 | |||
400 | usb_get_dev(udev); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* Kernel needs to suspend all functions separately. Therefore all | ||
406 | * registered functions must have drivers with suspend and resume | ||
407 | * methods. Failing that the kernel simply removes the whole card. | ||
408 | * | ||
409 | * If already not suspended, this function allocates and sends a | ||
410 | * 'host sleep activate' request to the firmware and turns off the traffic. | ||
411 | */ | ||
412 | static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message) | ||
413 | { | ||
414 | struct usb_card_rec *card = usb_get_intfdata(intf); | ||
415 | struct mwifiex_adapter *adapter; | ||
416 | int i; | ||
417 | |||
418 | if (!card || !card->adapter) { | ||
419 | pr_err("%s: card or card->adapter is NULL\n", __func__); | ||
420 | return 0; | ||
421 | } | ||
422 | adapter = card->adapter; | ||
423 | |||
424 | if (unlikely(adapter->is_suspended)) | ||
425 | dev_warn(adapter->dev, "Device already suspended\n"); | ||
426 | |||
427 | mwifiex_enable_hs(adapter); | ||
428 | |||
429 | /* 'is_suspended' flag indicates device is suspended. | ||
430 | * It must be set here before the usb_kill_urb() calls. Reason | ||
431 | * is in the complete handlers, urb->status(= -ENOENT) and | ||
432 | * this flag is used in combination to distinguish between a | ||
433 | * 'suspended' state and a 'disconnect' one. | ||
434 | */ | ||
435 | adapter->is_suspended = true; | ||
436 | |||
437 | for (i = 0; i < adapter->priv_num; i++) | ||
438 | netif_carrier_off(adapter->priv[i]->netdev); | ||
439 | |||
440 | if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) | ||
441 | usb_kill_urb(card->rx_cmd.urb); | ||
442 | |||
443 | if (atomic_read(&card->rx_data_urb_pending)) | ||
444 | for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) | ||
445 | if (card->rx_data_list[i].urb) | ||
446 | usb_kill_urb(card->rx_data_list[i].urb); | ||
447 | |||
448 | for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) | ||
449 | if (card->tx_data_list[i].urb) | ||
450 | usb_kill_urb(card->tx_data_list[i].urb); | ||
451 | |||
452 | if (card->tx_cmd.urb) | ||
453 | usb_kill_urb(card->tx_cmd.urb); | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | /* Kernel needs to suspend all functions separately. Therefore all | ||
459 | * registered functions must have drivers with suspend and resume | ||
460 | * methods. Failing that the kernel simply removes the whole card. | ||
461 | * | ||
462 | * If already not resumed, this function turns on the traffic and | ||
463 | * sends a 'host sleep cancel' request to the firmware. | ||
464 | */ | ||
465 | static int mwifiex_usb_resume(struct usb_interface *intf) | ||
466 | { | ||
467 | struct usb_card_rec *card = usb_get_intfdata(intf); | ||
468 | struct mwifiex_adapter *adapter; | ||
469 | int i; | ||
470 | |||
471 | if (!card || !card->adapter) { | ||
472 | pr_err("%s: card or card->adapter is NULL\n", __func__); | ||
473 | return 0; | ||
474 | } | ||
475 | adapter = card->adapter; | ||
476 | |||
477 | if (unlikely(!adapter->is_suspended)) { | ||
478 | dev_warn(adapter->dev, "Device already resumed\n"); | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | /* Indicate device resumed. The netdev queue will be resumed only | ||
483 | * after the urbs have been re-submitted | ||
484 | */ | ||
485 | adapter->is_suspended = false; | ||
486 | |||
487 | if (!atomic_read(&card->rx_data_urb_pending)) | ||
488 | for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) | ||
489 | mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], | ||
490 | MWIFIEX_RX_DATA_BUF_SIZE); | ||
491 | |||
492 | if (!atomic_read(&card->rx_cmd_urb_pending)) { | ||
493 | card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); | ||
494 | if (card->rx_cmd.skb) | ||
495 | mwifiex_usb_submit_rx_urb(&card->rx_cmd, | ||
496 | MWIFIEX_RX_CMD_BUF_SIZE); | ||
497 | } | ||
498 | |||
499 | for (i = 0; i < adapter->priv_num; i++) | ||
500 | if (adapter->priv[i]->media_connected) | ||
501 | netif_carrier_on(adapter->priv[i]->netdev); | ||
502 | |||
503 | /* Disable Host Sleep */ | ||
504 | if (adapter->hs_activated) | ||
505 | mwifiex_cancel_hs(mwifiex_get_priv(adapter, | ||
506 | MWIFIEX_BSS_ROLE_ANY), | ||
507 | MWIFIEX_ASYNC_CMD); | ||
508 | |||
509 | #ifdef CONFIG_PM | ||
510 | /* Resume handler may be called due to remote wakeup, | ||
511 | * force to exit suspend anyway | ||
512 | */ | ||
513 | usb_disable_autosuspend(card->udev); | ||
514 | #endif /* CONFIG_PM */ | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static void mwifiex_usb_disconnect(struct usb_interface *intf) | ||
520 | { | ||
521 | struct usb_card_rec *card = usb_get_intfdata(intf); | ||
522 | struct mwifiex_adapter *adapter; | ||
523 | int i; | ||
524 | |||
525 | if (!card || !card->adapter) { | ||
526 | pr_err("%s: card or card->adapter is NULL\n", __func__); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | adapter = card->adapter; | ||
531 | if (!adapter->priv_num) | ||
532 | return; | ||
533 | |||
534 | /* In case driver is removed when asynchronous FW downloading is | ||
535 | * in progress | ||
536 | */ | ||
537 | wait_for_completion(&adapter->fw_load); | ||
538 | |||
539 | if (user_rmmod) { | ||
540 | #ifdef CONFIG_PM | ||
541 | if (adapter->is_suspended) | ||
542 | mwifiex_usb_resume(intf); | ||
543 | #endif | ||
544 | for (i = 0; i < adapter->priv_num; i++) | ||
545 | if ((GET_BSS_ROLE(adapter->priv[i]) == | ||
546 | MWIFIEX_BSS_ROLE_STA) && | ||
547 | adapter->priv[i]->media_connected) | ||
548 | mwifiex_deauthenticate(adapter->priv[i], NULL); | ||
549 | |||
550 | mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, | ||
551 | MWIFIEX_BSS_ROLE_ANY), | ||
552 | MWIFIEX_FUNC_SHUTDOWN); | ||
553 | } | ||
554 | |||
555 | mwifiex_usb_free(card); | ||
556 | |||
557 | dev_dbg(adapter->dev, "%s: removing card\n", __func__); | ||
558 | mwifiex_remove_card(adapter, &add_remove_card_sem); | ||
559 | |||
560 | usb_set_intfdata(intf, NULL); | ||
561 | usb_put_dev(interface_to_usbdev(intf)); | ||
562 | kfree(card); | ||
563 | |||
564 | return; | ||
565 | } | ||
566 | |||
567 | static struct usb_driver mwifiex_usb_driver = { | ||
568 | .name = usbdriver_name, | ||
569 | .probe = mwifiex_usb_probe, | ||
570 | .disconnect = mwifiex_usb_disconnect, | ||
571 | .id_table = mwifiex_usb_table, | ||
572 | .suspend = mwifiex_usb_suspend, | ||
573 | .resume = mwifiex_usb_resume, | ||
574 | .supports_autosuspend = 1, | ||
575 | }; | ||
576 | |||
577 | static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) | ||
578 | { | ||
579 | struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; | ||
580 | int i; | ||
581 | |||
582 | card->tx_cmd.adapter = adapter; | ||
583 | card->tx_cmd.ep = card->tx_cmd_ep; | ||
584 | |||
585 | card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); | ||
586 | if (!card->tx_cmd.urb) { | ||
587 | dev_err(adapter->dev, "tx_cmd.urb allocation failed\n"); | ||
588 | return -ENOMEM; | ||
589 | } | ||
590 | |||
591 | card->tx_data_ix = 0; | ||
592 | |||
593 | for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) { | ||
594 | card->tx_data_list[i].adapter = adapter; | ||
595 | card->tx_data_list[i].ep = card->tx_data_ep; | ||
596 | |||
597 | card->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); | ||
598 | if (!card->tx_data_list[i].urb) { | ||
599 | dev_err(adapter->dev, | ||
600 | "tx_data_list[] urb allocation failed\n"); | ||
601 | return -ENOMEM; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) | ||
609 | { | ||
610 | struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; | ||
611 | int i; | ||
612 | |||
613 | card->rx_cmd.adapter = adapter; | ||
614 | card->rx_cmd.ep = card->rx_cmd_ep; | ||
615 | |||
616 | card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); | ||
617 | if (!card->rx_cmd.urb) { | ||
618 | dev_err(adapter->dev, "rx_cmd.urb allocation failed\n"); | ||
619 | return -ENOMEM; | ||
620 | } | ||
621 | |||
622 | card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); | ||
623 | if (!card->rx_cmd.skb) { | ||
624 | dev_err(adapter->dev, "rx_cmd.skb allocation failed\n"); | ||
625 | return -ENOMEM; | ||
626 | } | ||
627 | |||
628 | if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) | ||
629 | return -1; | ||
630 | |||
631 | for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { | ||
632 | card->rx_data_list[i].adapter = adapter; | ||
633 | card->rx_data_list[i].ep = card->rx_data_ep; | ||
634 | |||
635 | card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); | ||
636 | if (!card->rx_data_list[i].urb) { | ||
637 | dev_err(adapter->dev, | ||
638 | "rx_data_list[] urb allocation failed\n"); | ||
639 | return -1; | ||
640 | } | ||
641 | if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], | ||
642 | MWIFIEX_RX_DATA_BUF_SIZE)) | ||
643 | return -1; | ||
644 | } | ||
645 | |||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, | ||
650 | u32 *len, u8 ep, u32 timeout) | ||
651 | { | ||
652 | struct usb_card_rec *card = adapter->card; | ||
653 | int actual_length, ret; | ||
654 | |||
655 | if (!(*len % card->bulk_out_maxpktsize)) | ||
656 | (*len)++; | ||
657 | |||
658 | /* Send the data block */ | ||
659 | ret = usb_bulk_msg(card->udev, usb_sndbulkpipe(card->udev, ep), pbuf, | ||
660 | *len, &actual_length, timeout); | ||
661 | if (ret) { | ||
662 | dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret); | ||
663 | ret = -1; | ||
664 | } | ||
665 | |||
666 | *len = actual_length; | ||
667 | |||
668 | return ret; | ||
669 | } | ||
670 | |||
671 | static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, | ||
672 | u32 *len, u8 ep, u32 timeout) | ||
673 | { | ||
674 | struct usb_card_rec *card = adapter->card; | ||
675 | int actual_length, ret; | ||
676 | |||
677 | /* Receive the data response */ | ||
678 | ret = usb_bulk_msg(card->udev, usb_rcvbulkpipe(card->udev, ep), pbuf, | ||
679 | *len, &actual_length, timeout); | ||
680 | if (ret) { | ||
681 | dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret); | ||
682 | ret = -1; | ||
683 | } | ||
684 | |||
685 | *len = actual_length; | ||
686 | |||
687 | return ret; | ||
688 | } | ||
689 | |||
690 | /* This function write a command/data packet to card. */ | ||
691 | static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, | ||
692 | struct sk_buff *skb, | ||
693 | struct mwifiex_tx_param *tx_param) | ||
694 | { | ||
695 | struct usb_card_rec *card = adapter->card; | ||
696 | struct urb_context *context; | ||
697 | u8 *data = (u8 *)skb->data; | ||
698 | struct urb *tx_urb; | ||
699 | |||
700 | if (adapter->is_suspended) { | ||
701 | dev_err(adapter->dev, | ||
702 | "%s: not allowed while suspended\n", __func__); | ||
703 | return -1; | ||
704 | } | ||
705 | |||
706 | if (adapter->surprise_removed) { | ||
707 | dev_err(adapter->dev, "%s: device removed\n", __func__); | ||
708 | return -1; | ||
709 | } | ||
710 | |||
711 | if (ep == card->tx_data_ep && | ||
712 | atomic_read(&card->tx_data_urb_pending) >= MWIFIEX_TX_DATA_URB) { | ||
713 | return -EBUSY; | ||
714 | } | ||
715 | |||
716 | dev_dbg(adapter->dev, "%s: ep=%d\n", __func__, ep); | ||
717 | |||
718 | if (ep == card->tx_cmd_ep) { | ||
719 | context = &card->tx_cmd; | ||
720 | } else { | ||
721 | if (card->tx_data_ix >= MWIFIEX_TX_DATA_URB) | ||
722 | card->tx_data_ix = 0; | ||
723 | context = &card->tx_data_list[card->tx_data_ix++]; | ||
724 | } | ||
725 | |||
726 | context->adapter = adapter; | ||
727 | context->ep = ep; | ||
728 | context->skb = skb; | ||
729 | tx_urb = context->urb; | ||
730 | |||
731 | usb_fill_bulk_urb(tx_urb, card->udev, usb_sndbulkpipe(card->udev, ep), | ||
732 | data, skb->len, mwifiex_usb_tx_complete, | ||
733 | (void *)context); | ||
734 | |||
735 | tx_urb->transfer_flags |= URB_ZERO_PACKET; | ||
736 | |||
737 | if (ep == card->tx_cmd_ep) | ||
738 | atomic_inc(&card->tx_cmd_urb_pending); | ||
739 | else | ||
740 | atomic_inc(&card->tx_data_urb_pending); | ||
741 | |||
742 | if (usb_submit_urb(tx_urb, GFP_ATOMIC)) { | ||
743 | dev_err(adapter->dev, "%s: usb_submit_urb failed\n", __func__); | ||
744 | if (ep == card->tx_cmd_ep) { | ||
745 | atomic_dec(&card->tx_cmd_urb_pending); | ||
746 | } else { | ||
747 | atomic_dec(&card->tx_data_urb_pending); | ||
748 | if (card->tx_data_ix) | ||
749 | card->tx_data_ix--; | ||
750 | else | ||
751 | card->tx_data_ix = MWIFIEX_TX_DATA_URB; | ||
752 | } | ||
753 | |||
754 | return -1; | ||
755 | } else { | ||
756 | if (ep == card->tx_data_ep && | ||
757 | atomic_read(&card->tx_data_urb_pending) == | ||
758 | MWIFIEX_TX_DATA_URB) | ||
759 | return -ENOSR; | ||
760 | } | ||
761 | |||
762 | return -EINPROGRESS; | ||
763 | } | ||
764 | |||
765 | /* This function register usb device and initialize parameter. */ | ||
766 | static int mwifiex_register_dev(struct mwifiex_adapter *adapter) | ||
767 | { | ||
768 | struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; | ||
769 | |||
770 | card->adapter = adapter; | ||
771 | adapter->dev = &card->udev->dev; | ||
772 | strcpy(adapter->fw_name, USB8797_DEFAULT_FW_NAME); | ||
773 | |||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | /* This function reads one block of firmware data. */ | ||
778 | static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter, | ||
779 | u32 offset, u32 len, u8 *buf) | ||
780 | { | ||
781 | if (!buf || !len) | ||
782 | return -1; | ||
783 | |||
784 | if (offset + len > adapter->firmware->size) | ||
785 | return -1; | ||
786 | |||
787 | memcpy(buf, adapter->firmware->data + offset, len); | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | ||
793 | struct mwifiex_fw_image *fw) | ||
794 | { | ||
795 | int ret = 0; | ||
796 | u8 *firmware = fw->fw_buf, *recv_buff; | ||
797 | u32 retries = USB8797_FW_MAX_RETRY, dlen; | ||
798 | u32 fw_seqnum = 0, tlen = 0, dnld_cmd = 0; | ||
799 | struct fw_data *fwdata; | ||
800 | struct fw_sync_header sync_fw; | ||
801 | u8 check_winner = 1; | ||
802 | |||
803 | if (!firmware) { | ||
804 | dev_err(adapter->dev, | ||
805 | "No firmware image found! Terminating download\n"); | ||
806 | ret = -1; | ||
807 | goto fw_exit; | ||
808 | } | ||
809 | |||
810 | /* Allocate memory for transmit */ | ||
811 | fwdata = kzalloc(FW_DNLD_TX_BUF_SIZE, GFP_KERNEL); | ||
812 | if (!fwdata) | ||
813 | goto fw_exit; | ||
814 | |||
815 | /* Allocate memory for receive */ | ||
816 | recv_buff = kzalloc(FW_DNLD_RX_BUF_SIZE, GFP_KERNEL); | ||
817 | if (!recv_buff) | ||
818 | goto cleanup; | ||
819 | |||
820 | do { | ||
821 | /* Send pseudo data to check winner status first */ | ||
822 | if (check_winner) { | ||
823 | memset(&fwdata->fw_hdr, 0, sizeof(struct fw_header)); | ||
824 | dlen = 0; | ||
825 | } else { | ||
826 | /* copy the header of the fw_data to get the length */ | ||
827 | if (firmware) | ||
828 | memcpy(&fwdata->fw_hdr, &firmware[tlen], | ||
829 | sizeof(struct fw_header)); | ||
830 | else | ||
831 | mwifiex_get_fw_data(adapter, tlen, | ||
832 | sizeof(struct fw_header), | ||
833 | (u8 *)&fwdata->fw_hdr); | ||
834 | |||
835 | dlen = le32_to_cpu(fwdata->fw_hdr.data_len); | ||
836 | dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd); | ||
837 | tlen += sizeof(struct fw_header); | ||
838 | |||
839 | if (firmware) | ||
840 | memcpy(fwdata->data, &firmware[tlen], dlen); | ||
841 | else | ||
842 | mwifiex_get_fw_data(adapter, tlen, dlen, | ||
843 | (u8 *)fwdata->data); | ||
844 | |||
845 | fwdata->seq_num = cpu_to_le32(fw_seqnum); | ||
846 | tlen += dlen; | ||
847 | } | ||
848 | |||
849 | /* If the send/receive fails or CRC occurs then retry */ | ||
850 | while (retries--) { | ||
851 | u8 *buf = (u8 *)fwdata; | ||
852 | u32 len = FW_DATA_XMIT_SIZE; | ||
853 | |||
854 | /* send the firmware block */ | ||
855 | ret = mwifiex_write_data_sync(adapter, buf, &len, | ||
856 | MWIFIEX_USB_EP_CMD_EVENT, | ||
857 | MWIFIEX_USB_TIMEOUT); | ||
858 | if (ret) { | ||
859 | dev_err(adapter->dev, | ||
860 | "write_data_sync: failed: %d\n", ret); | ||
861 | continue; | ||
862 | } | ||
863 | |||
864 | buf = recv_buff; | ||
865 | len = FW_DNLD_RX_BUF_SIZE; | ||
866 | |||
867 | /* Receive the firmware block response */ | ||
868 | ret = mwifiex_read_data_sync(adapter, buf, &len, | ||
869 | MWIFIEX_USB_EP_CMD_EVENT, | ||
870 | MWIFIEX_USB_TIMEOUT); | ||
871 | if (ret) { | ||
872 | dev_err(adapter->dev, | ||
873 | "read_data_sync: failed: %d\n", ret); | ||
874 | continue; | ||
875 | } | ||
876 | |||
877 | memcpy(&sync_fw, recv_buff, | ||
878 | sizeof(struct fw_sync_header)); | ||
879 | |||
880 | /* check 1st firmware block resp for highest bit set */ | ||
881 | if (check_winner) { | ||
882 | if (le32_to_cpu(sync_fw.cmd) & 0x80000000) { | ||
883 | dev_warn(adapter->dev, | ||
884 | "USB is not the winner %#x\n", | ||
885 | sync_fw.cmd); | ||
886 | |||
887 | /* returning success */ | ||
888 | ret = 0; | ||
889 | goto cleanup; | ||
890 | } | ||
891 | |||
892 | dev_dbg(adapter->dev, | ||
893 | "USB is the winner, start to download FW\n"); | ||
894 | |||
895 | check_winner = 0; | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | /* check the firmware block response for CRC errors */ | ||
900 | if (sync_fw.cmd) { | ||
901 | dev_err(adapter->dev, | ||
902 | "FW received block with CRC %#x\n", | ||
903 | sync_fw.cmd); | ||
904 | ret = -1; | ||
905 | continue; | ||
906 | } | ||
907 | |||
908 | retries = USB8797_FW_MAX_RETRY; | ||
909 | break; | ||
910 | } | ||
911 | fw_seqnum++; | ||
912 | } while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries); | ||
913 | |||
914 | cleanup: | ||
915 | dev_dbg(adapter->dev, "%s: %d bytes downloaded\n", __func__, tlen); | ||
916 | |||
917 | kfree(recv_buff); | ||
918 | kfree(fwdata); | ||
919 | |||
920 | if (retries) | ||
921 | ret = 0; | ||
922 | fw_exit: | ||
923 | return ret; | ||
924 | } | ||
925 | |||
926 | static int mwifiex_usb_dnld_fw(struct mwifiex_adapter *adapter, | ||
927 | struct mwifiex_fw_image *fw) | ||
928 | { | ||
929 | int ret; | ||
930 | struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; | ||
931 | |||
932 | if (card->usb_boot_state == USB8797_FW_DNLD) { | ||
933 | ret = mwifiex_prog_fw_w_helper(adapter, fw); | ||
934 | if (ret) | ||
935 | return -1; | ||
936 | |||
937 | /* Boot state changes after successful firmware download */ | ||
938 | if (card->usb_boot_state == USB8797_FW_DNLD) | ||
939 | return -1; | ||
940 | } | ||
941 | |||
942 | ret = mwifiex_usb_rx_init(adapter); | ||
943 | if (!ret) | ||
944 | ret = mwifiex_usb_tx_init(adapter); | ||
945 | |||
946 | return ret; | ||
947 | } | ||
948 | |||
949 | static void mwifiex_submit_rx_urb(struct mwifiex_adapter *adapter, u8 ep) | ||
950 | { | ||
951 | struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; | ||
952 | |||
953 | skb_push(card->rx_cmd.skb, INTF_HEADER_LEN); | ||
954 | if ((ep == card->rx_cmd_ep) && | ||
955 | (!atomic_read(&card->rx_cmd_urb_pending))) | ||
956 | mwifiex_usb_submit_rx_urb(&card->rx_cmd, | ||
957 | MWIFIEX_RX_CMD_BUF_SIZE); | ||
958 | |||
959 | return; | ||
960 | } | ||
961 | |||
962 | static int mwifiex_usb_cmd_event_complete(struct mwifiex_adapter *adapter, | ||
963 | struct sk_buff *skb) | ||
964 | { | ||
965 | atomic_dec(&adapter->rx_pending); | ||
966 | mwifiex_submit_rx_urb(adapter, MWIFIEX_USB_EP_CMD_EVENT); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static int mwifiex_usb_data_complete(struct mwifiex_adapter *adapter, | ||
972 | struct sk_buff *skb) | ||
973 | { | ||
974 | atomic_dec(&adapter->rx_pending); | ||
975 | dev_kfree_skb_any(skb); | ||
976 | |||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | /* This function wakes up the card. */ | ||
981 | static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) | ||
982 | { | ||
983 | /* Simulation of HS_AWAKE event */ | ||
984 | adapter->pm_wakeup_fw_try = false; | ||
985 | adapter->pm_wakeup_card_req = false; | ||
986 | adapter->ps_state = PS_STATE_AWAKE; | ||
987 | |||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static struct mwifiex_if_ops usb_ops = { | ||
992 | .register_dev = mwifiex_register_dev, | ||
993 | .wakeup = mwifiex_pm_wakeup_card, | ||
994 | .wakeup_complete = mwifiex_pm_wakeup_card_complete, | ||
995 | |||
996 | /* USB specific */ | ||
997 | .dnld_fw = mwifiex_usb_dnld_fw, | ||
998 | .cmdrsp_complete = mwifiex_usb_cmd_event_complete, | ||
999 | .event_complete = mwifiex_usb_cmd_event_complete, | ||
1000 | .data_complete = mwifiex_usb_data_complete, | ||
1001 | .host_to_card = mwifiex_usb_host_to_card, | ||
1002 | }; | ||
1003 | |||
1004 | /* This function initializes the USB driver module. | ||
1005 | * | ||
1006 | * This initiates the semaphore and registers the device with | ||
1007 | * USB bus. | ||
1008 | */ | ||
1009 | static int mwifiex_usb_init_module(void) | ||
1010 | { | ||
1011 | int ret; | ||
1012 | |||
1013 | pr_debug("Marvell USB8797 Driver\n"); | ||
1014 | |||
1015 | sema_init(&add_remove_card_sem, 1); | ||
1016 | |||
1017 | ret = usb_register(&mwifiex_usb_driver); | ||
1018 | if (ret) | ||
1019 | pr_err("Driver register failed!\n"); | ||
1020 | else | ||
1021 | pr_debug("info: Driver registered successfully!\n"); | ||
1022 | |||
1023 | return ret; | ||
1024 | } | ||
1025 | |||
1026 | /* This function cleans up the USB driver. | ||
1027 | * | ||
1028 | * The following major steps are followed in .disconnect for cleanup: | ||
1029 | * - Resume the device if its suspended | ||
1030 | * - Disconnect the device if connected | ||
1031 | * - Shutdown the firmware | ||
1032 | * - Unregister the device from USB bus. | ||
1033 | */ | ||
1034 | static void mwifiex_usb_cleanup_module(void) | ||
1035 | { | ||
1036 | if (!down_interruptible(&add_remove_card_sem)) | ||
1037 | up(&add_remove_card_sem); | ||
1038 | |||
1039 | /* set the flag as user is removing this module */ | ||
1040 | user_rmmod = 1; | ||
1041 | |||
1042 | usb_deregister(&mwifiex_usb_driver); | ||
1043 | } | ||
1044 | |||
1045 | module_init(mwifiex_usb_init_module); | ||
1046 | module_exit(mwifiex_usb_cleanup_module); | ||
1047 | |||
1048 | MODULE_AUTHOR("Marvell International Ltd."); | ||
1049 | MODULE_DESCRIPTION("Marvell WiFi-Ex USB Driver version" USB_VERSION); | ||
1050 | MODULE_VERSION(USB_VERSION); | ||
1051 | MODULE_LICENSE("GPL v2"); | ||
1052 | MODULE_FIRMWARE("mrvl/usb8797_uapsta.bin"); | ||
diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h new file mode 100644 index 000000000000..98c4316cd1a9 --- /dev/null +++ b/drivers/net/wireless/mwifiex/usb.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * This file contains definitions for mwifiex USB interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MWIFIEX_USB_H | ||
21 | #define _MWIFIEX_USB_H | ||
22 | |||
23 | #include <linux/usb.h> | ||
24 | |||
25 | #define USB8797_VID 0x1286 | ||
26 | #define USB8797_PID_1 0x2043 | ||
27 | #define USB8797_PID_2 0x2044 | ||
28 | |||
29 | #define USB8797_FW_DNLD 1 | ||
30 | #define USB8797_FW_READY 2 | ||
31 | #define USB8797_FW_MAX_RETRY 3 | ||
32 | |||
33 | #define MWIFIEX_TX_DATA_URB 6 | ||
34 | #define MWIFIEX_RX_DATA_URB 6 | ||
35 | #define MWIFIEX_USB_TIMEOUT 100 | ||
36 | |||
37 | #define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin" | ||
38 | |||
39 | #define FW_DNLD_TX_BUF_SIZE 620 | ||
40 | #define FW_DNLD_RX_BUF_SIZE 2048 | ||
41 | #define FW_HAS_LAST_BLOCK 0x00000004 | ||
42 | |||
43 | #define FW_DATA_XMIT_SIZE \ | ||
44 | (sizeof(struct fw_header) + dlen + sizeof(u32)) | ||
45 | |||
46 | struct urb_context { | ||
47 | struct mwifiex_adapter *adapter; | ||
48 | struct sk_buff *skb; | ||
49 | struct urb *urb; | ||
50 | u8 ep; | ||
51 | }; | ||
52 | |||
53 | struct usb_card_rec { | ||
54 | struct mwifiex_adapter *adapter; | ||
55 | struct usb_device *udev; | ||
56 | struct usb_interface *intf; | ||
57 | u8 rx_cmd_ep; | ||
58 | struct urb_context rx_cmd; | ||
59 | atomic_t rx_cmd_urb_pending; | ||
60 | struct urb_context rx_data_list[MWIFIEX_RX_DATA_URB]; | ||
61 | u8 usb_boot_state; | ||
62 | u8 rx_data_ep; | ||
63 | atomic_t rx_data_urb_pending; | ||
64 | u8 tx_data_ep; | ||
65 | u8 tx_cmd_ep; | ||
66 | atomic_t tx_data_urb_pending; | ||
67 | atomic_t tx_cmd_urb_pending; | ||
68 | int bulk_out_maxpktsize; | ||
69 | struct urb_context tx_cmd; | ||
70 | int tx_data_ix; | ||
71 | struct urb_context tx_data_list[MWIFIEX_TX_DATA_URB]; | ||
72 | }; | ||
73 | |||
74 | struct fw_header { | ||
75 | __le32 dnld_cmd; | ||
76 | __le32 base_addr; | ||
77 | __le32 data_len; | ||
78 | __le32 crc; | ||
79 | }; | ||
80 | |||
81 | struct fw_sync_header { | ||
82 | __le32 cmd; | ||
83 | __le32 seq_num; | ||
84 | }; | ||
85 | |||
86 | struct fw_data { | ||
87 | struct fw_header fw_hdr; | ||
88 | __le32 seq_num; | ||
89 | u8 data[1]; | ||
90 | }; | ||
91 | |||
92 | /* This function is called after the card has woken up. */ | ||
93 | static inline int | ||
94 | mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) | ||
95 | { | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | #endif /*_MWIFIEX_USB_H */ | ||
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 6b399976d6c8..2864c74bdb6f 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c | |||
@@ -167,6 +167,28 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) | |||
167 | skb->dev = priv->netdev; | 167 | skb->dev = priv->netdev; |
168 | skb->protocol = eth_type_trans(skb, priv->netdev); | 168 | skb->protocol = eth_type_trans(skb, priv->netdev); |
169 | skb->ip_summed = CHECKSUM_NONE; | 169 | skb->ip_summed = CHECKSUM_NONE; |
170 | |||
171 | /* This is required only in case of 11n and USB as we alloc | ||
172 | * a buffer of 4K only if its 11N (to be able to receive 4K | ||
173 | * AMSDU packets). In case of SD we allocate buffers based | ||
174 | * on the size of packet and hence this is not needed. | ||
175 | * | ||
176 | * Modifying the truesize here as our allocation for each | ||
177 | * skb is 4K but we only receive 2K packets and this cause | ||
178 | * the kernel to start dropping packets in case where | ||
179 | * application has allocated buffer based on 2K size i.e. | ||
180 | * if there a 64K packet received (in IP fragments and | ||
181 | * application allocates 64K to receive this packet but | ||
182 | * this packet would almost double up because we allocate | ||
183 | * each 1.5K fragment in 4K and pass it up. As soon as the | ||
184 | * 64K limit hits kernel will start to drop rest of the | ||
185 | * fragments. Currently we fail the Filesndl-ht.scr script | ||
186 | * for UDP, hence this fix | ||
187 | */ | ||
188 | if ((adapter->iface_type == MWIFIEX_USB) && | ||
189 | (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) | ||
190 | skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); | ||
191 | |||
170 | priv->stats.rx_bytes += skb->len; | 192 | priv->stats.rx_bytes += skb->len; |
171 | priv->stats.rx_packets++; | 193 | priv->stats.rx_packets++; |
172 | if (in_interrupt()) | 194 | if (in_interrupt()) |
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 5a7316c6f125..429a1dee2d26 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c | |||
@@ -1120,11 +1120,19 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, | |||
1120 | tx_info = MWIFIEX_SKB_TXCB(skb); | 1120 | tx_info = MWIFIEX_SKB_TXCB(skb); |
1121 | 1121 | ||
1122 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); | 1122 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); |
1123 | tx_param.next_pkt_len = | 1123 | |
1124 | ((skb_next) ? skb_next->len + | 1124 | if (adapter->iface_type == MWIFIEX_USB) { |
1125 | sizeof(struct txpd) : 0); | 1125 | adapter->data_sent = true; |
1126 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, | 1126 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA, |
1127 | &tx_param); | 1127 | skb, NULL); |
1128 | } else { | ||
1129 | tx_param.next_pkt_len = | ||
1130 | ((skb_next) ? skb_next->len + | ||
1131 | sizeof(struct txpd) : 0); | ||
1132 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
1133 | skb, &tx_param); | ||
1134 | } | ||
1135 | |||
1128 | switch (ret) { | 1136 | switch (ret) { |
1129 | case -EBUSY: | 1137 | case -EBUSY: |
1130 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); | 1138 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); |