blob: f5dda84176c3d4ae8277c069df06fa3bbc11922d [file] [log] [blame]
Sujithfb9987d2010-03-17 14:25:25 +05301/*
Sujith Manoharan5b681382011-05-17 13:36:18 +05302 * Copyright (c) 2010-2011 Atheros Communications Inc.
Sujithfb9987d2010-03-17 14:25:25 +05303 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Pavel Roskin78fa99a2011-07-15 19:06:33 -040017#include <asm/unaligned.h>
Sujithfb9987d2010-03-17 14:25:25 +053018#include "htc.h"
19
John W. Linvilled0ee0eb2010-06-23 14:20:45 -040020/* identify firmware images */
Sujith Manoharance18f392011-04-13 11:22:42 +053021#define FIRMWARE_AR7010_1_1 "htc_7010.fw"
22#define FIRMWARE_AR9271 "htc_9271.fw"
John W. Linvilled0ee0eb2010-06-23 14:20:45 -040023
John W. Linvilled0ee0eb2010-06-23 14:20:45 -040024MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
25MODULE_FIRMWARE(FIRMWARE_AR9271);
26
Sujithfb9987d2010-03-17 14:25:25 +053027static struct usb_device_id ath9k_hif_usb_ids[] = {
Sujith4e63f762010-06-17 10:29:01 +053028 { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
29 { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */
Sujith4e63f762010-06-17 10:29:01 +053030 { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */
Sujith4e63f762010-06-17 10:29:01 +053031 { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */
32 { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
33 { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
Haitao Zhangac618d72010-11-07 12:50:24 +080034 { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */
Rajkumar Manoharan32b08952010-11-10 17:51:24 +053035 { USB_DEVICE(0x13D3, 0x3348) }, /* Azurewave */
36 { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */
37 { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */
Sujith4e63f762010-06-17 10:29:01 +053038 { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
Rajkumar Manoharan32b08952010-11-10 17:51:24 +053039 { USB_DEVICE(0x040D, 0x3801) }, /* VIA */
Sujith Manoharan452d7dd2010-12-13 07:39:32 +053040 { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
Mohammed Shafi Shajakhan763cbac2012-10-16 21:31:49 +053041 { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */
Luis R. Rodriguez8c345592011-09-29 10:42:19 -070042 { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
Sujith Manoharan0b5ead92010-12-07 16:31:38 +053043
44 { USB_DEVICE(0x0cf3, 0x7015),
45 .driver_info = AR9287_USB }, /* Atheros */
Rajkumar Manoharan64f12172010-11-19 16:53:20 +053046 { USB_DEVICE(0x1668, 0x1200),
Sujith Manoharan0b5ead92010-12-07 16:31:38 +053047 .driver_info = AR9287_USB }, /* Verizon */
48
49 { USB_DEVICE(0x0cf3, 0x7010),
50 .driver_info = AR9280_USB }, /* Atheros */
51 { USB_DEVICE(0x0846, 0x9018),
52 .driver_info = AR9280_USB }, /* Netgear WNDA3200 */
53 { USB_DEVICE(0x083A, 0xA704),
54 .driver_info = AR9280_USB }, /* SMC Networks */
Mohammed Shafi Shajakhan5cf6fa72011-06-28 20:13:41 +053055 { USB_DEVICE(0x0411, 0x017f),
56 .driver_info = AR9280_USB }, /* Sony UWA-BR100 */
Sujith Manoharand90b5702012-04-11 13:58:15 +053057 { USB_DEVICE(0x04da, 0x3904),
58 .driver_info = AR9280_USB },
Sujith Manoharan0b5ead92010-12-07 16:31:38 +053059
Sujith Manoharan36bcce42011-02-21 07:47:52 +053060 { USB_DEVICE(0x0cf3, 0x20ff),
61 .driver_info = STORAGE_DEVICE },
62
Sujithfb9987d2010-03-17 14:25:25 +053063 { },
64};
65
66MODULE_DEVICE_TABLE(usb, ath9k_hif_usb_ids);
67
68static int __hif_usb_tx(struct hif_device_usb *hif_dev);
69
70static void hif_usb_regout_cb(struct urb *urb)
71{
72 struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
Sujithfb9987d2010-03-17 14:25:25 +053073
74 switch (urb->status) {
75 case 0:
76 break;
77 case -ENOENT:
78 case -ECONNRESET:
Sujithfb9987d2010-03-17 14:25:25 +053079 case -ENODEV:
80 case -ESHUTDOWN:
Sujith6f0f2662010-04-06 15:28:17 +053081 goto free;
Sujithfb9987d2010-03-17 14:25:25 +053082 default:
83 break;
84 }
85
86 if (cmd) {
87 ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
Sujith Manoharan2f801942011-04-13 11:26:46 +053088 cmd->skb, true);
Sujithfb9987d2010-03-17 14:25:25 +053089 kfree(cmd);
Sujithfb9987d2010-03-17 14:25:25 +053090 }
Sujith6f0f2662010-04-06 15:28:17 +053091
92 return;
93free:
Ming Lei0fa35a52010-04-13 00:29:15 +080094 kfree_skb(cmd->skb);
Sujith6f0f2662010-04-06 15:28:17 +053095 kfree(cmd);
Sujithfb9987d2010-03-17 14:25:25 +053096}
97
98static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
99 struct sk_buff *skb)
100{
101 struct urb *urb;
102 struct cmd_buf *cmd;
103 int ret = 0;
104
105 urb = usb_alloc_urb(0, GFP_KERNEL);
106 if (urb == NULL)
107 return -ENOMEM;
108
109 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
110 if (cmd == NULL) {
111 usb_free_urb(urb);
112 return -ENOMEM;
113 }
114
115 cmd->skb = skb;
116 cmd->hif_dev = hif_dev;
117
Rajkumar Manoharan4a0e8ecc2010-09-14 14:35:55 +0530118 usb_fill_bulk_urb(urb, hif_dev->udev,
119 usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE),
Sujithfb9987d2010-03-17 14:25:25 +0530120 skb->data, skb->len,
Rajkumar Manoharan4a0e8ecc2010-09-14 14:35:55 +0530121 hif_usb_regout_cb, cmd);
Sujithfb9987d2010-03-17 14:25:25 +0530122
Sujith6f0f2662010-04-06 15:28:17 +0530123 usb_anchor_urb(urb, &hif_dev->regout_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530124 ret = usb_submit_urb(urb, GFP_KERNEL);
125 if (ret) {
Sujith6f0f2662010-04-06 15:28:17 +0530126 usb_unanchor_urb(urb);
Sujithfb9987d2010-03-17 14:25:25 +0530127 kfree(cmd);
128 }
Sujith6f0f2662010-04-06 15:28:17 +0530129 usb_free_urb(urb);
Sujithfb9987d2010-03-17 14:25:25 +0530130
131 return ret;
132}
133
Sujith Manoharan2f801942011-04-13 11:26:46 +0530134static void hif_usb_mgmt_cb(struct urb *urb)
135{
136 struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
Rajkumar Manoharan02c51722011-07-17 11:38:49 +0530137 struct hif_device_usb *hif_dev;
Sujith Manoharan2f801942011-04-13 11:26:46 +0530138 bool txok = true;
139
140 if (!cmd || !cmd->skb || !cmd->hif_dev)
141 return;
142
Rajkumar Manoharan02c51722011-07-17 11:38:49 +0530143 hif_dev = cmd->hif_dev;
144
Sujith Manoharan2f801942011-04-13 11:26:46 +0530145 switch (urb->status) {
146 case 0:
147 break;
148 case -ENOENT:
149 case -ECONNRESET:
150 case -ENODEV:
151 case -ESHUTDOWN:
152 txok = false;
153
154 /*
155 * If the URBs are being flushed, no need to complete
156 * this packet.
157 */
158 spin_lock(&hif_dev->tx.tx_lock);
159 if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
160 spin_unlock(&hif_dev->tx.tx_lock);
161 dev_kfree_skb_any(cmd->skb);
162 kfree(cmd);
163 return;
164 }
165 spin_unlock(&hif_dev->tx.tx_lock);
166
167 break;
168 default:
169 txok = false;
170 break;
171 }
172
173 skb_pull(cmd->skb, 4);
174 ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
175 cmd->skb, txok);
176 kfree(cmd);
177}
178
179static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev,
180 struct sk_buff *skb)
181{
182 struct urb *urb;
183 struct cmd_buf *cmd;
184 int ret = 0;
185 __le16 *hdr;
186
187 urb = usb_alloc_urb(0, GFP_ATOMIC);
188 if (urb == NULL)
189 return -ENOMEM;
190
191 cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
192 if (cmd == NULL) {
193 usb_free_urb(urb);
194 return -ENOMEM;
195 }
196
197 cmd->skb = skb;
198 cmd->hif_dev = hif_dev;
199
200 hdr = (__le16 *) skb_push(skb, 4);
201 *hdr++ = cpu_to_le16(skb->len - 4);
202 *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
203
204 usb_fill_bulk_urb(urb, hif_dev->udev,
205 usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
206 skb->data, skb->len,
207 hif_usb_mgmt_cb, cmd);
208
209 usb_anchor_urb(urb, &hif_dev->mgmt_submitted);
210 ret = usb_submit_urb(urb, GFP_ATOMIC);
211 if (ret) {
212 usb_unanchor_urb(urb);
213 kfree(cmd);
214 }
215 usb_free_urb(urb);
216
217 return ret;
218}
219
Sujitheac8e382010-04-16 11:54:00 +0530220static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
221 struct sk_buff_head *list)
Ming Leif8e1d082010-04-13 00:29:27 +0800222{
223 struct sk_buff *skb;
Sujitheac8e382010-04-16 11:54:00 +0530224
225 while ((skb = __skb_dequeue(list)) != NULL) {
Ming Leif8e1d082010-04-13 00:29:27 +0800226 dev_kfree_skb_any(skb);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530227 }
228}
229
230static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
231 struct sk_buff_head *queue,
232 bool txok)
233{
234 struct sk_buff *skb;
235
236 while ((skb = __skb_dequeue(queue)) != NULL) {
237 ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
238 skb, txok);
John W. Linvilledfa8fc62011-04-14 10:38:22 -0400239 if (txok)
240 TX_STAT_INC(skb_success);
241 else
242 TX_STAT_INC(skb_failed);
Sujitheac8e382010-04-16 11:54:00 +0530243 }
Ming Leif8e1d082010-04-13 00:29:27 +0800244}
245
Sujithc11d8f82010-04-23 10:28:09 +0530246static void hif_usb_tx_cb(struct urb *urb)
247{
248 struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
Dan Carpenter690e7812010-05-14 16:50:56 +0200249 struct hif_device_usb *hif_dev;
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530250 bool txok = true;
Sujithc11d8f82010-04-23 10:28:09 +0530251
Dan Carpenter690e7812010-05-14 16:50:56 +0200252 if (!tx_buf || !tx_buf->hif_dev)
Sujithc11d8f82010-04-23 10:28:09 +0530253 return;
254
Dan Carpenter690e7812010-05-14 16:50:56 +0200255 hif_dev = tx_buf->hif_dev;
256
Sujithc11d8f82010-04-23 10:28:09 +0530257 switch (urb->status) {
258 case 0:
259 break;
260 case -ENOENT:
261 case -ECONNRESET:
262 case -ENODEV:
263 case -ESHUTDOWN:
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530264 txok = false;
Sujith Manoharanff8f59b2010-12-28 14:28:05 +0530265
266 /*
267 * If the URBs are being flushed, no need to add this
268 * URB to the free list.
269 */
270 spin_lock(&hif_dev->tx.tx_lock);
271 if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
272 spin_unlock(&hif_dev->tx.tx_lock);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530273 ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
Sujith Manoharanff8f59b2010-12-28 14:28:05 +0530274 return;
275 }
276 spin_unlock(&hif_dev->tx.tx_lock);
277
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530278 break;
Sujithc11d8f82010-04-23 10:28:09 +0530279 default:
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530280 txok = false;
Sujithc11d8f82010-04-23 10:28:09 +0530281 break;
282 }
283
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530284 ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok);
Sujithc11d8f82010-04-23 10:28:09 +0530285
Sujithc11d8f82010-04-23 10:28:09 +0530286 /* Re-initialize the SKB queue */
287 tx_buf->len = tx_buf->offset = 0;
288 __skb_queue_head_init(&tx_buf->skb_queue);
289
290 /* Add this TX buffer to the free list */
291 spin_lock(&hif_dev->tx.tx_lock);
292 list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
293 hif_dev->tx.tx_buf_cnt++;
294 if (!(hif_dev->tx.flags & HIF_USB_TX_STOP))
295 __hif_usb_tx(hif_dev); /* Check for pending SKBs */
296 TX_STAT_INC(buf_completed);
297 spin_unlock(&hif_dev->tx.tx_lock);
298}
299
Sujithfb9987d2010-03-17 14:25:25 +0530300/* TX lock has to be taken */
301static int __hif_usb_tx(struct hif_device_usb *hif_dev)
302{
303 struct tx_buf *tx_buf = NULL;
304 struct sk_buff *nskb = NULL;
305 int ret = 0, i;
Sujith Manoharan2c273922011-02-27 09:23:52 +0530306 u16 tx_skb_cnt = 0;
Sujithfb9987d2010-03-17 14:25:25 +0530307 u8 *buf;
Sujith Manoharan2c273922011-02-27 09:23:52 +0530308 __le16 *hdr;
Sujithfb9987d2010-03-17 14:25:25 +0530309
310 if (hif_dev->tx.tx_skb_cnt == 0)
311 return 0;
312
313 /* Check if a free TX buffer is available */
314 if (list_empty(&hif_dev->tx.tx_buf))
315 return 0;
316
317 tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list);
Sujithc11d8f82010-04-23 10:28:09 +0530318 list_move_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
Sujithfb9987d2010-03-17 14:25:25 +0530319 hif_dev->tx.tx_buf_cnt--;
320
321 tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM);
322
323 for (i = 0; i < tx_skb_cnt; i++) {
324 nskb = __skb_dequeue(&hif_dev->tx.tx_skb_queue);
325
326 /* Should never be NULL */
327 BUG_ON(!nskb);
328
329 hif_dev->tx.tx_skb_cnt--;
330
331 buf = tx_buf->buf;
332 buf += tx_buf->offset;
Sujith Manoharan2c273922011-02-27 09:23:52 +0530333 hdr = (__le16 *)buf;
334 *hdr++ = cpu_to_le16(nskb->len);
335 *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
Sujithfb9987d2010-03-17 14:25:25 +0530336 buf += 4;
337 memcpy(buf, nskb->data, nskb->len);
338 tx_buf->len = nskb->len + 4;
339
340 if (i < (tx_skb_cnt - 1))
341 tx_buf->offset += (((tx_buf->len - 1) / 4) + 1) * 4;
342
343 if (i == (tx_skb_cnt - 1))
344 tx_buf->len += tx_buf->offset;
345
346 __skb_queue_tail(&tx_buf->skb_queue, nskb);
347 TX_STAT_INC(skb_queued);
348 }
349
350 usb_fill_bulk_urb(tx_buf->urb, hif_dev->udev,
351 usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
352 tx_buf->buf, tx_buf->len,
353 hif_usb_tx_cb, tx_buf);
354
355 ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
356 if (ret) {
357 tx_buf->len = tx_buf->offset = 0;
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530358 ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false);
Sujithfb9987d2010-03-17 14:25:25 +0530359 __skb_queue_head_init(&tx_buf->skb_queue);
360 list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
361 hif_dev->tx.tx_buf_cnt++;
362 }
363
364 if (!ret)
365 TX_STAT_INC(buf_queued);
366
367 return ret;
368}
369
Sujith Manoharan40dc9e42011-04-13 11:24:31 +0530370static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
Sujithfb9987d2010-03-17 14:25:25 +0530371{
Sujith Manoharan40dc9e42011-04-13 11:24:31 +0530372 struct ath9k_htc_tx_ctl *tx_ctl;
Sujithfb9987d2010-03-17 14:25:25 +0530373 unsigned long flags;
Sujith Manoharan2f801942011-04-13 11:26:46 +0530374 int ret = 0;
Sujithfb9987d2010-03-17 14:25:25 +0530375
376 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
377
378 if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
379 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
380 return -ENODEV;
381 }
382
383 /* Check if the max queue count has been reached */
384 if (hif_dev->tx.tx_skb_cnt > MAX_TX_BUF_NUM) {
385 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
386 return -ENOMEM;
387 }
388
Sujith Manoharan2f801942011-04-13 11:26:46 +0530389 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
Sujithfb9987d2010-03-17 14:25:25 +0530390
Sujith Manoharan40dc9e42011-04-13 11:24:31 +0530391 tx_ctl = HTC_SKB_CB(skb);
392
Sujith Manoharan2f801942011-04-13 11:26:46 +0530393 /* Mgmt/Beacon frames don't use the TX buffer pool */
394 if ((tx_ctl->type == ATH9K_HTC_MGMT) ||
395 (tx_ctl->type == ATH9K_HTC_BEACON)) {
396 ret = hif_usb_send_mgmt(hif_dev, skb);
397 }
398
399 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
400
401 if ((tx_ctl->type == ATH9K_HTC_NORMAL) ||
402 (tx_ctl->type == ATH9K_HTC_AMPDU)) {
403 __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
404 hif_dev->tx.tx_skb_cnt++;
405 }
Sujithfb9987d2010-03-17 14:25:25 +0530406
407 /* Check if AMPDUs have to be sent immediately */
Sujith Manoharan2f801942011-04-13 11:26:46 +0530408 if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
Sujithfb9987d2010-03-17 14:25:25 +0530409 (hif_dev->tx.tx_skb_cnt < 2)) {
410 __hif_usb_tx(hif_dev);
411 }
412
413 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
414
Sujith Manoharan2f801942011-04-13 11:26:46 +0530415 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530416}
417
Sujith Manoharane1fe7c32011-04-13 11:26:06 +0530418static void hif_usb_start(void *hif_handle)
Sujithfb9987d2010-03-17 14:25:25 +0530419{
420 struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
421 unsigned long flags;
422
423 hif_dev->flags |= HIF_USB_START;
424
425 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
426 hif_dev->tx.flags &= ~HIF_USB_TX_STOP;
427 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
428}
429
Sujith Manoharane1fe7c32011-04-13 11:26:06 +0530430static void hif_usb_stop(void *hif_handle)
Sujithfb9987d2010-03-17 14:25:25 +0530431{
432 struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
Sujith Manoharanff8f59b2010-12-28 14:28:05 +0530433 struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
Sujithfb9987d2010-03-17 14:25:25 +0530434 unsigned long flags;
435
436 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530437 ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false);
Sujithfb9987d2010-03-17 14:25:25 +0530438 hif_dev->tx.tx_skb_cnt = 0;
439 hif_dev->tx.flags |= HIF_USB_TX_STOP;
440 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
Sujith Manoharanff8f59b2010-12-28 14:28:05 +0530441
442 /* The pending URBs have to be canceled. */
443 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
444 &hif_dev->tx.tx_pending, list) {
445 usb_kill_urb(tx_buf->urb);
446 }
Sujith Manoharan2f801942011-04-13 11:26:46 +0530447
448 usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530449}
450
Sujith Manoharan40dc9e42011-04-13 11:24:31 +0530451static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
Sujithfb9987d2010-03-17 14:25:25 +0530452{
453 struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
454 int ret = 0;
455
456 switch (pipe_id) {
457 case USB_WLAN_TX_PIPE:
Sujith Manoharan40dc9e42011-04-13 11:24:31 +0530458 ret = hif_usb_send_tx(hif_dev, skb);
Sujithfb9987d2010-03-17 14:25:25 +0530459 break;
460 case USB_REG_OUT_PIPE:
461 ret = hif_usb_send_regout(hif_dev, skb);
462 break;
463 default:
Sujith6335ed02010-03-29 16:07:15 +0530464 dev_err(&hif_dev->udev->dev,
465 "ath9k_htc: Invalid TX pipe: %d\n", pipe_id);
Sujithfb9987d2010-03-17 14:25:25 +0530466 ret = -EINVAL;
467 break;
468 }
469
470 return ret;
471}
472
Sujith Manoharan84c9e1642011-04-13 11:26:11 +0530473static inline bool check_index(struct sk_buff *skb, u8 idx)
474{
475 struct ath9k_htc_tx_ctl *tx_ctl;
476
477 tx_ctl = HTC_SKB_CB(skb);
478
479 if ((tx_ctl->type == ATH9K_HTC_AMPDU) &&
480 (tx_ctl->sta_idx == idx))
481 return true;
482
483 return false;
484}
485
486static void hif_usb_sta_drain(void *hif_handle, u8 idx)
487{
488 struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
489 struct sk_buff *skb, *tmp;
490 unsigned long flags;
491
492 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
493
494 skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) {
495 if (check_index(skb, idx)) {
496 __skb_unlink(skb, &hif_dev->tx.tx_skb_queue);
497 ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
498 skb, false);
499 hif_dev->tx.tx_skb_cnt--;
500 TX_STAT_INC(skb_failed);
501 }
502 }
503
504 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
505}
506
Sujithfb9987d2010-03-17 14:25:25 +0530507static struct ath9k_htc_hif hif_usb = {
508 .transport = ATH9K_HIF_USB,
509 .name = "ath9k_hif_usb",
510
511 .control_ul_pipe = USB_REG_OUT_PIPE,
512 .control_dl_pipe = USB_REG_IN_PIPE,
513
514 .start = hif_usb_start,
515 .stop = hif_usb_stop,
Sujith Manoharan84c9e1642011-04-13 11:26:11 +0530516 .sta_drain = hif_usb_sta_drain,
Sujithfb9987d2010-03-17 14:25:25 +0530517 .send = hif_usb_send,
518};
519
520static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
521 struct sk_buff *skb)
522{
Sujithc5032692010-04-06 15:28:15 +0530523 struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER];
Joe Perches44b23b42010-11-30 12:19:11 -0800524 int index = 0, i = 0, len = skb->len;
525 int rx_remain_len, rx_pkt_len;
526 u16 pool_index = 0;
Sujithfb9987d2010-03-17 14:25:25 +0530527 u8 *ptr;
528
Sujith46baa1a2010-04-06 15:28:11 +0530529 spin_lock(&hif_dev->rx_lock);
530
Sujithfb9987d2010-03-17 14:25:25 +0530531 rx_remain_len = hif_dev->rx_remain_len;
532 rx_pkt_len = hif_dev->rx_transfer_len;
533
534 if (rx_remain_len != 0) {
535 struct sk_buff *remain_skb = hif_dev->remain_skb;
536
537 if (remain_skb) {
538 ptr = (u8 *) remain_skb->data;
539
540 index = rx_remain_len;
541 rx_remain_len -= hif_dev->rx_pad_len;
542 ptr += rx_pkt_len;
543
544 memcpy(ptr, skb->data, rx_remain_len);
545
546 rx_pkt_len += rx_remain_len;
547 hif_dev->rx_remain_len = 0;
548 skb_put(remain_skb, rx_pkt_len);
549
550 skb_pool[pool_index++] = remain_skb;
551
552 } else {
553 index = rx_remain_len;
554 }
555 }
556
Sujith46baa1a2010-04-06 15:28:11 +0530557 spin_unlock(&hif_dev->rx_lock);
558
Sujithfb9987d2010-03-17 14:25:25 +0530559 while (index < len) {
Joe Perches44b23b42010-11-30 12:19:11 -0800560 u16 pkt_len;
561 u16 pkt_tag;
562 u16 pad_len;
563 int chk_idx;
564
Sujithfb9987d2010-03-17 14:25:25 +0530565 ptr = (u8 *) skb->data;
566
Pavel Roskin78fa99a2011-07-15 19:06:33 -0400567 pkt_len = get_unaligned_le16(ptr + index);
568 pkt_tag = get_unaligned_le16(ptr + index + 2);
Sujithfb9987d2010-03-17 14:25:25 +0530569
Joe Perches44b23b42010-11-30 12:19:11 -0800570 if (pkt_tag != ATH_USB_RX_STREAM_MODE_TAG) {
Sujithfb9987d2010-03-17 14:25:25 +0530571 RX_STAT_INC(skb_dropped);
Sujithfb9987d2010-03-17 14:25:25 +0530572 return;
573 }
Joe Perches44b23b42010-11-30 12:19:11 -0800574
575 pad_len = 4 - (pkt_len & 0x3);
576 if (pad_len == 4)
577 pad_len = 0;
578
579 chk_idx = index;
580 index = index + 4 + pkt_len + pad_len;
581
582 if (index > MAX_RX_BUF_SIZE) {
583 spin_lock(&hif_dev->rx_lock);
584 hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
585 hif_dev->rx_transfer_len =
586 MAX_RX_BUF_SIZE - chk_idx - 4;
587 hif_dev->rx_pad_len = pad_len;
588
589 nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
590 if (!nskb) {
591 dev_err(&hif_dev->udev->dev,
592 "ath9k_htc: RX memory allocation error\n");
593 spin_unlock(&hif_dev->rx_lock);
594 goto err;
595 }
596 skb_reserve(nskb, 32);
597 RX_STAT_INC(skb_allocated);
598
599 memcpy(nskb->data, &(skb->data[chk_idx+4]),
600 hif_dev->rx_transfer_len);
601
602 /* Record the buffer pointer */
603 hif_dev->remain_skb = nskb;
604 spin_unlock(&hif_dev->rx_lock);
605 } else {
606 nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
607 if (!nskb) {
608 dev_err(&hif_dev->udev->dev,
609 "ath9k_htc: RX memory allocation error\n");
610 goto err;
611 }
612 skb_reserve(nskb, 32);
613 RX_STAT_INC(skb_allocated);
614
615 memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
616 skb_put(nskb, pkt_len);
617 skb_pool[pool_index++] = nskb;
618 }
Sujithfb9987d2010-03-17 14:25:25 +0530619 }
620
621err:
Sujithfb9987d2010-03-17 14:25:25 +0530622 for (i = 0; i < pool_index; i++) {
623 ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i],
624 skb_pool[i]->len, USB_WLAN_RX_PIPE);
625 RX_STAT_INC(skb_completed);
626 }
627}
628
629static void ath9k_hif_usb_rx_cb(struct urb *urb)
630{
631 struct sk_buff *skb = (struct sk_buff *) urb->context;
Joe Perchesb2767362010-11-30 13:42:08 -0800632 struct hif_device_usb *hif_dev =
Sujithfb9987d2010-03-17 14:25:25 +0530633 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
634 int ret;
635
Sujith6335ed02010-03-29 16:07:15 +0530636 if (!skb)
637 return;
638
Sujithfb9987d2010-03-17 14:25:25 +0530639 if (!hif_dev)
640 goto free;
641
642 switch (urb->status) {
643 case 0:
644 break;
645 case -ENOENT:
646 case -ECONNRESET:
647 case -ENODEV:
648 case -ESHUTDOWN:
649 goto free;
650 default:
651 goto resubmit;
652 }
653
654 if (likely(urb->actual_length != 0)) {
655 skb_put(skb, urb->actual_length);
Sujithfb9987d2010-03-17 14:25:25 +0530656 ath9k_hif_usb_rx_stream(hif_dev, skb);
Sujithfb9987d2010-03-17 14:25:25 +0530657 }
658
659resubmit:
660 skb_reset_tail_pointer(skb);
661 skb_trim(skb, 0);
662
Sujith6335ed02010-03-29 16:07:15 +0530663 usb_anchor_urb(urb, &hif_dev->rx_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530664 ret = usb_submit_urb(urb, GFP_ATOMIC);
Sujith6335ed02010-03-29 16:07:15 +0530665 if (ret) {
666 usb_unanchor_urb(urb);
Sujithfb9987d2010-03-17 14:25:25 +0530667 goto free;
Sujith6335ed02010-03-29 16:07:15 +0530668 }
Sujithfb9987d2010-03-17 14:25:25 +0530669
670 return;
671free:
Ming Leif28a7b32010-04-13 00:28:53 +0800672 kfree_skb(skb);
Sujithfb9987d2010-03-17 14:25:25 +0530673}
674
675static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
676{
677 struct sk_buff *skb = (struct sk_buff *) urb->context;
678 struct sk_buff *nskb;
Joe Perchesb2767362010-11-30 13:42:08 -0800679 struct hif_device_usb *hif_dev =
Sujithfb9987d2010-03-17 14:25:25 +0530680 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
681 int ret;
682
Sujith6335ed02010-03-29 16:07:15 +0530683 if (!skb)
684 return;
685
Sujithfb9987d2010-03-17 14:25:25 +0530686 if (!hif_dev)
687 goto free;
688
689 switch (urb->status) {
690 case 0:
691 break;
692 case -ENOENT:
693 case -ECONNRESET:
694 case -ENODEV:
695 case -ESHUTDOWN:
696 goto free;
697 default:
Sujith Manoharan3deff762011-04-13 11:25:23 +0530698 skb_reset_tail_pointer(skb);
699 skb_trim(skb, 0);
700
Sujithfb9987d2010-03-17 14:25:25 +0530701 goto resubmit;
702 }
703
704 if (likely(urb->actual_length != 0)) {
705 skb_put(skb, urb->actual_length);
706
Sujith5ab0af32010-04-23 10:28:17 +0530707 /* Process the command first */
708 ath9k_htc_rx_msg(hif_dev->htc_handle, skb,
709 skb->len, USB_REG_IN_PIPE);
710
711
Ming Leie6c6d332010-04-13 00:29:05 +0800712 nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC);
Sujith5ab0af32010-04-23 10:28:17 +0530713 if (!nskb) {
714 dev_err(&hif_dev->udev->dev,
715 "ath9k_htc: REG_IN memory allocation failure\n");
716 urb->context = NULL;
717 return;
718 }
Sujithfb9987d2010-03-17 14:25:25 +0530719
Rajkumar Manoharan490b3f42010-11-08 12:49:12 +0530720 usb_fill_bulk_urb(urb, hif_dev->udev,
Rajkumar Manoharan0f529e92010-09-16 19:56:55 +0530721 usb_rcvbulkpipe(hif_dev->udev,
722 USB_REG_IN_PIPE),
Sujithfb9987d2010-03-17 14:25:25 +0530723 nskb->data, MAX_REG_IN_BUF_SIZE,
Rajkumar Manoharan490b3f42010-11-08 12:49:12 +0530724 ath9k_hif_usb_reg_in_cb, nskb);
Sujithfb9987d2010-03-17 14:25:25 +0530725 }
726
727resubmit:
Sujith Manoharan3deff762011-04-13 11:25:23 +0530728 usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530729 ret = usb_submit_urb(urb, GFP_ATOMIC);
Sujith Manoharan3deff762011-04-13 11:25:23 +0530730 if (ret) {
731 usb_unanchor_urb(urb);
Sujithfb9987d2010-03-17 14:25:25 +0530732 goto free;
Sujith Manoharan3deff762011-04-13 11:25:23 +0530733 }
Sujithfb9987d2010-03-17 14:25:25 +0530734
735 return;
736free:
Ming Leie6c6d332010-04-13 00:29:05 +0800737 kfree_skb(skb);
Sujith6335ed02010-03-29 16:07:15 +0530738 urb->context = NULL;
Sujithfb9987d2010-03-17 14:25:25 +0530739}
740
741static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
742{
Sujithfb9987d2010-03-17 14:25:25 +0530743 struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
Sujith Manoharanff8f59b2010-12-28 14:28:05 +0530744 unsigned long flags;
Sujithfb9987d2010-03-17 14:25:25 +0530745
Sujithc11d8f82010-04-23 10:28:09 +0530746 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
747 &hif_dev->tx.tx_buf, list) {
748 usb_kill_urb(tx_buf->urb);
Sujithfb9987d2010-03-17 14:25:25 +0530749 list_del(&tx_buf->list);
750 usb_free_urb(tx_buf->urb);
751 kfree(tx_buf->buf);
752 kfree(tx_buf);
753 }
754
Sujith Manoharanff8f59b2010-12-28 14:28:05 +0530755 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
756 hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
757 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
758
Sujithfb9987d2010-03-17 14:25:25 +0530759 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
760 &hif_dev->tx.tx_pending, list) {
761 usb_kill_urb(tx_buf->urb);
762 list_del(&tx_buf->list);
763 usb_free_urb(tx_buf->urb);
764 kfree(tx_buf->buf);
765 kfree(tx_buf);
766 }
Sujith Manoharan2f801942011-04-13 11:26:46 +0530767
768 usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530769}
770
771static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
772{
773 struct tx_buf *tx_buf;
774 int i;
775
776 INIT_LIST_HEAD(&hif_dev->tx.tx_buf);
777 INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
778 spin_lock_init(&hif_dev->tx.tx_lock);
779 __skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
Sujith Manoharan2f801942011-04-13 11:26:46 +0530780 init_usb_anchor(&hif_dev->mgmt_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530781
782 for (i = 0; i < MAX_TX_URB_NUM; i++) {
783 tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
784 if (!tx_buf)
785 goto err;
786
787 tx_buf->buf = kzalloc(MAX_TX_BUF_SIZE, GFP_KERNEL);
788 if (!tx_buf->buf)
789 goto err;
790
791 tx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
792 if (!tx_buf->urb)
793 goto err;
794
795 tx_buf->hif_dev = hif_dev;
796 __skb_queue_head_init(&tx_buf->skb_queue);
797
798 list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
799 }
800
801 hif_dev->tx.tx_buf_cnt = MAX_TX_URB_NUM;
802
803 return 0;
804err:
Dan Carpenter76066882010-05-14 16:52:37 +0200805 if (tx_buf) {
806 kfree(tx_buf->buf);
807 kfree(tx_buf);
808 }
Sujithfb9987d2010-03-17 14:25:25 +0530809 ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
810 return -ENOMEM;
811}
812
Sujithfb9987d2010-03-17 14:25:25 +0530813static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev)
814{
Sujith6335ed02010-03-29 16:07:15 +0530815 usb_kill_anchored_urbs(&hif_dev->rx_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530816}
817
818static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
819{
Sujith6335ed02010-03-29 16:07:15 +0530820 struct urb *urb = NULL;
821 struct sk_buff *skb = NULL;
Sujithfb9987d2010-03-17 14:25:25 +0530822 int i, ret;
823
Sujith6335ed02010-03-29 16:07:15 +0530824 init_usb_anchor(&hif_dev->rx_submitted);
Sujith46baa1a2010-04-06 15:28:11 +0530825 spin_lock_init(&hif_dev->rx_lock);
Sujith6335ed02010-03-29 16:07:15 +0530826
Sujithfb9987d2010-03-17 14:25:25 +0530827 for (i = 0; i < MAX_RX_URB_NUM; i++) {
828
829 /* Allocate URB */
Sujith6335ed02010-03-29 16:07:15 +0530830 urb = usb_alloc_urb(0, GFP_KERNEL);
831 if (urb == NULL) {
Sujithfb9987d2010-03-17 14:25:25 +0530832 ret = -ENOMEM;
Sujith6335ed02010-03-29 16:07:15 +0530833 goto err_urb;
Sujithfb9987d2010-03-17 14:25:25 +0530834 }
835
836 /* Allocate buffer */
Ming Leif28a7b32010-04-13 00:28:53 +0800837 skb = alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL);
Sujith6335ed02010-03-29 16:07:15 +0530838 if (!skb) {
839 ret = -ENOMEM;
840 goto err_skb;
841 }
842
843 usb_fill_bulk_urb(urb, hif_dev->udev,
844 usb_rcvbulkpipe(hif_dev->udev,
845 USB_WLAN_RX_PIPE),
846 skb->data, MAX_RX_BUF_SIZE,
847 ath9k_hif_usb_rx_cb, skb);
848
849 /* Anchor URB */
850 usb_anchor_urb(urb, &hif_dev->rx_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530851
852 /* Submit URB */
Sujith6335ed02010-03-29 16:07:15 +0530853 ret = usb_submit_urb(urb, GFP_KERNEL);
854 if (ret) {
855 usb_unanchor_urb(urb);
856 goto err_submit;
857 }
Sujith66b10e32010-04-06 15:28:13 +0530858
859 /*
860 * Drop reference count.
861 * This ensures that the URB is freed when killing them.
862 */
863 usb_free_urb(urb);
Sujithfb9987d2010-03-17 14:25:25 +0530864 }
865
866 return 0;
867
Sujith6335ed02010-03-29 16:07:15 +0530868err_submit:
Ming Leif28a7b32010-04-13 00:28:53 +0800869 kfree_skb(skb);
Sujith6335ed02010-03-29 16:07:15 +0530870err_skb:
871 usb_free_urb(urb);
872err_urb:
Sujithfb9987d2010-03-17 14:25:25 +0530873 ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
874 return ret;
875}
876
Sujith Manoharan3deff762011-04-13 11:25:23 +0530877static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
Sujithfb9987d2010-03-17 14:25:25 +0530878{
Sujith Manoharan3deff762011-04-13 11:25:23 +0530879 usb_kill_anchored_urbs(&hif_dev->reg_in_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530880}
881
Sujith Manoharan3deff762011-04-13 11:25:23 +0530882static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
Sujithfb9987d2010-03-17 14:25:25 +0530883{
Sujith Manoharan3deff762011-04-13 11:25:23 +0530884 struct urb *urb = NULL;
885 struct sk_buff *skb = NULL;
886 int i, ret;
Sujithfb9987d2010-03-17 14:25:25 +0530887
Sujith Manoharan3deff762011-04-13 11:25:23 +0530888 init_usb_anchor(&hif_dev->reg_in_submitted);
Sujithfb9987d2010-03-17 14:25:25 +0530889
Sujith Manoharan3deff762011-04-13 11:25:23 +0530890 for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
Sujithfb9987d2010-03-17 14:25:25 +0530891
Sujith Manoharan3deff762011-04-13 11:25:23 +0530892 /* Allocate URB */
893 urb = usb_alloc_urb(0, GFP_KERNEL);
894 if (urb == NULL) {
895 ret = -ENOMEM;
896 goto err_urb;
897 }
Sujithfb9987d2010-03-17 14:25:25 +0530898
Sujith Manoharan3deff762011-04-13 11:25:23 +0530899 /* Allocate buffer */
900 skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
901 if (!skb) {
902 ret = -ENOMEM;
903 goto err_skb;
904 }
905
906 usb_fill_bulk_urb(urb, hif_dev->udev,
907 usb_rcvbulkpipe(hif_dev->udev,
908 USB_REG_IN_PIPE),
909 skb->data, MAX_REG_IN_BUF_SIZE,
910 ath9k_hif_usb_reg_in_cb, skb);
911
912 /* Anchor URB */
913 usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
914
915 /* Submit URB */
916 ret = usb_submit_urb(urb, GFP_KERNEL);
917 if (ret) {
918 usb_unanchor_urb(urb);
919 goto err_submit;
920 }
921
922 /*
923 * Drop reference count.
924 * This ensures that the URB is freed when killing them.
925 */
926 usb_free_urb(urb);
927 }
Sujithfb9987d2010-03-17 14:25:25 +0530928
929 return 0;
930
Sujith Manoharan3deff762011-04-13 11:25:23 +0530931err_submit:
932 kfree_skb(skb);
933err_skb:
934 usb_free_urb(urb);
935err_urb:
936 ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
937 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530938}
939
940static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
941{
Sujith6f0f2662010-04-06 15:28:17 +0530942 /* Register Write */
943 init_usb_anchor(&hif_dev->regout_submitted);
944
Sujithfb9987d2010-03-17 14:25:25 +0530945 /* TX */
946 if (ath9k_hif_usb_alloc_tx_urbs(hif_dev) < 0)
947 goto err;
948
949 /* RX */
950 if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0)
Rajkumar Manoharanf8036962010-07-07 15:19:18 +0530951 goto err_rx;
Sujithfb9987d2010-03-17 14:25:25 +0530952
Sujith6f0f2662010-04-06 15:28:17 +0530953 /* Register Read */
Sujith Manoharan3deff762011-04-13 11:25:23 +0530954 if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0)
Rajkumar Manoharanf8036962010-07-07 15:19:18 +0530955 goto err_reg;
Sujithfb9987d2010-03-17 14:25:25 +0530956
957 return 0;
Rajkumar Manoharanf8036962010-07-07 15:19:18 +0530958err_reg:
959 ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
960err_rx:
961 ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
Sujithfb9987d2010-03-17 14:25:25 +0530962err:
963 return -ENOMEM;
964}
965
Sujith.Manoharan@atheros.com1d8af8c2010-05-11 16:24:40 +0530966static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
967{
968 usb_kill_anchored_urbs(&hif_dev->regout_submitted);
Sujith Manoharan3deff762011-04-13 11:25:23 +0530969 ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
Sujith.Manoharan@atheros.com1d8af8c2010-05-11 16:24:40 +0530970 ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
971 ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
972}
973
Sujith Manoharan0ed7b932012-01-30 14:17:18 +0530974static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
Sujithfb9987d2010-03-17 14:25:25 +0530975{
976 int transfer, err;
Ming Lei32e31de2012-08-21 16:04:27 +0800977 const void *data = hif_dev->fw_data;
978 size_t len = hif_dev->fw_size;
Sujithfb9987d2010-03-17 14:25:25 +0530979 u32 addr = AR9271_FIRMWARE;
980 u8 *buf = kzalloc(4096, GFP_KERNEL);
Sujithb1762862010-06-02 15:53:34 +0530981 u32 firm_offset;
Sujithfb9987d2010-03-17 14:25:25 +0530982
983 if (!buf)
984 return -ENOMEM;
985
986 while (len) {
Dan Carpenter291689f2012-02-01 10:43:31 +0300987 transfer = min_t(size_t, len, 4096);
Sujithfb9987d2010-03-17 14:25:25 +0530988 memcpy(buf, data, transfer);
989
990 err = usb_control_msg(hif_dev->udev,
991 usb_sndctrlpipe(hif_dev->udev, 0),
992 FIRMWARE_DOWNLOAD, 0x40 | USB_DIR_OUT,
993 addr >> 8, 0, buf, transfer, HZ);
994 if (err < 0) {
995 kfree(buf);
996 return err;
997 }
998
999 len -= transfer;
1000 data += transfer;
1001 addr += transfer;
1002 }
1003 kfree(buf);
1004
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301005 if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
Sujithb1762862010-06-02 15:53:34 +05301006 firm_offset = AR7010_FIRMWARE_TEXT;
Rajkumar Manoharanfa6e15e2010-11-19 16:53:22 +05301007 else
Sujithb1762862010-06-02 15:53:34 +05301008 firm_offset = AR9271_FIRMWARE_TEXT;
1009
Sujithfb9987d2010-03-17 14:25:25 +05301010 /*
1011 * Issue FW download complete command to firmware.
1012 */
1013 err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0),
1014 FIRMWARE_DOWNLOAD_COMP,
1015 0x40 | USB_DIR_OUT,
Sujithb1762862010-06-02 15:53:34 +05301016 firm_offset >> 8, 0, NULL, 0, HZ);
Sujithfb9987d2010-03-17 14:25:25 +05301017 if (err)
1018 return -EIO;
1019
1020 dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n",
Ming Lei32e31de2012-08-21 16:04:27 +08001021 hif_dev->fw_name, (unsigned long) hif_dev->fw_size);
Sujithfb9987d2010-03-17 14:25:25 +05301022
1023 return 0;
1024}
1025
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301026static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
Sujithfb9987d2010-03-17 14:25:25 +05301027{
Rajkumar Manoharan4a0e8ecc2010-09-14 14:35:55 +05301028 struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
1029 struct usb_endpoint_descriptor *endp;
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301030 int ret, idx;
Sujithfb9987d2010-03-17 14:25:25 +05301031
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301032 ret = ath9k_hif_usb_download_fw(hif_dev);
Sujith.Manoharan@atheros.com1d8af8c2010-05-11 16:24:40 +05301033 if (ret) {
1034 dev_err(&hif_dev->udev->dev,
Sujithce43cee2010-06-02 15:53:30 +05301035 "ath9k_htc: Firmware - %s download failed\n",
1036 hif_dev->fw_name);
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301037 return ret;
Sujith.Manoharan@atheros.com1d8af8c2010-05-11 16:24:40 +05301038 }
1039
Rajkumar Manoharan4a0e8ecc2010-09-14 14:35:55 +05301040 /* On downloading the firmware to the target, the USB descriptor of EP4
1041 * is 'patched' to change the type of the endpoint to Bulk. This will
1042 * bring down CPU usage during the scan period.
1043 */
1044 for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) {
1045 endp = &alt->endpoint[idx].desc;
Rajkumar Manoharan490b3f42010-11-08 12:49:12 +05301046 if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
1047 == USB_ENDPOINT_XFER_INT) {
Rajkumar Manoharan4a0e8ecc2010-09-14 14:35:55 +05301048 endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
1049 endp->bmAttributes |= USB_ENDPOINT_XFER_BULK;
1050 endp->bInterval = 0;
1051 }
1052 }
1053
Rajkumar Manoharan490b3f42010-11-08 12:49:12 +05301054 /* Alloc URBs */
1055 ret = ath9k_hif_usb_alloc_urbs(hif_dev);
1056 if (ret) {
1057 dev_err(&hif_dev->udev->dev,
1058 "ath9k_htc: Unable to allocate URBs\n");
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301059 return ret;
Rajkumar Manoharan490b3f42010-11-08 12:49:12 +05301060 }
1061
Sujithfb9987d2010-03-17 14:25:25 +05301062 return 0;
Sujithfb9987d2010-03-17 14:25:25 +05301063}
1064
Sujithfb9987d2010-03-17 14:25:25 +05301065static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev)
1066{
1067 ath9k_hif_usb_dealloc_urbs(hif_dev);
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301068}
1069
1070/*
1071 * If initialization fails or the FW cannot be retrieved,
1072 * detach the device.
1073 */
1074static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
1075{
Ming Leie9626102012-09-13 10:33:28 +08001076 struct device *dev = &hif_dev->udev->dev;
1077 struct device *parent = dev->parent;
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301078
1079 complete(&hif_dev->fw_done);
1080
1081 if (parent)
1082 device_lock(parent);
1083
Ming Leie9626102012-09-13 10:33:28 +08001084 device_release_driver(dev);
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301085
1086 if (parent)
1087 device_unlock(parent);
1088}
1089
1090static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
1091{
1092 struct hif_device_usb *hif_dev = context;
1093 int ret;
1094
1095 if (!fw) {
1096 dev_err(&hif_dev->udev->dev,
1097 "ath9k_htc: Failed to get firmware %s\n",
1098 hif_dev->fw_name);
1099 goto err_fw;
1100 }
1101
1102 hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
1103 &hif_dev->udev->dev);
Ming Lei32e31de2012-08-21 16:04:27 +08001104 if (hif_dev->htc_handle == NULL)
1105 goto err_dev_alloc;
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301106
Ming Lei32e31de2012-08-21 16:04:27 +08001107 hif_dev->fw_data = fw->data;
1108 hif_dev->fw_size = fw->size;
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301109
1110 /* Proceed with initialization */
1111
1112 ret = ath9k_hif_usb_dev_init(hif_dev);
1113 if (ret)
1114 goto err_dev_init;
1115
1116 ret = ath9k_htc_hw_init(hif_dev->htc_handle,
1117 &hif_dev->interface->dev,
1118 hif_dev->usb_device_id->idProduct,
1119 hif_dev->udev->product,
1120 hif_dev->usb_device_id->driver_info);
1121 if (ret) {
1122 ret = -EINVAL;
1123 goto err_htc_hw_init;
1124 }
1125
Ming Lei32e31de2012-08-21 16:04:27 +08001126 release_firmware(fw);
1127 hif_dev->flags |= HIF_USB_READY;
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301128 complete(&hif_dev->fw_done);
1129
1130 return;
1131
1132err_htc_hw_init:
1133 ath9k_hif_usb_dev_deinit(hif_dev);
1134err_dev_init:
1135 ath9k_htc_hw_free(hif_dev->htc_handle);
Ming Lei32e31de2012-08-21 16:04:27 +08001136err_dev_alloc:
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301137 release_firmware(fw);
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301138err_fw:
1139 ath9k_hif_usb_firmware_fail(hif_dev);
Sujithfb9987d2010-03-17 14:25:25 +05301140}
1141
Sujith Manoharan36bcce42011-02-21 07:47:52 +05301142/*
1143 * An exact copy of the function from zd1211rw.
1144 */
1145static int send_eject_command(struct usb_interface *interface)
1146{
1147 struct usb_device *udev = interface_to_usbdev(interface);
1148 struct usb_host_interface *iface_desc = &interface->altsetting[0];
1149 struct usb_endpoint_descriptor *endpoint;
1150 unsigned char *cmd;
1151 u8 bulk_out_ep;
1152 int r;
1153
1154 /* Find bulk out endpoint */
1155 for (r = 1; r >= 0; r--) {
1156 endpoint = &iface_desc->endpoint[r].desc;
1157 if (usb_endpoint_dir_out(endpoint) &&
1158 usb_endpoint_xfer_bulk(endpoint)) {
1159 bulk_out_ep = endpoint->bEndpointAddress;
1160 break;
1161 }
1162 }
1163 if (r == -1) {
1164 dev_err(&udev->dev,
1165 "ath9k_htc: Could not find bulk out endpoint\n");
1166 return -ENODEV;
1167 }
1168
1169 cmd = kzalloc(31, GFP_KERNEL);
1170 if (cmd == NULL)
1171 return -ENODEV;
1172
1173 /* USB bulk command block */
1174 cmd[0] = 0x55; /* bulk command signature */
1175 cmd[1] = 0x53; /* bulk command signature */
1176 cmd[2] = 0x42; /* bulk command signature */
1177 cmd[3] = 0x43; /* bulk command signature */
1178 cmd[14] = 6; /* command length */
1179
1180 cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
1181 cmd[19] = 0x2; /* eject disc */
1182
1183 dev_info(&udev->dev, "Ejecting storage device...\n");
1184 r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
1185 cmd, 31, NULL, 2000);
1186 kfree(cmd);
1187 if (r)
1188 return r;
1189
1190 /* At this point, the device disconnects and reconnects with the real
1191 * ID numbers. */
1192
1193 usb_set_intfdata(interface, NULL);
1194 return 0;
1195}
1196
Sujithfb9987d2010-03-17 14:25:25 +05301197static int ath9k_hif_usb_probe(struct usb_interface *interface,
1198 const struct usb_device_id *id)
1199{
1200 struct usb_device *udev = interface_to_usbdev(interface);
1201 struct hif_device_usb *hif_dev;
Sujithfb9987d2010-03-17 14:25:25 +05301202 int ret = 0;
1203
Sujith Manoharan36bcce42011-02-21 07:47:52 +05301204 if (id->driver_info == STORAGE_DEVICE)
1205 return send_eject_command(interface);
1206
Sujithfb9987d2010-03-17 14:25:25 +05301207 hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL);
1208 if (!hif_dev) {
1209 ret = -ENOMEM;
1210 goto err_alloc;
1211 }
1212
1213 usb_get_dev(udev);
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301214
Sujithfb9987d2010-03-17 14:25:25 +05301215 hif_dev->udev = udev;
1216 hif_dev->interface = interface;
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301217 hif_dev->usb_device_id = id;
Sujithfb9987d2010-03-17 14:25:25 +05301218#ifdef CONFIG_PM
1219 udev->reset_resume = 1;
1220#endif
1221 usb_set_intfdata(interface, hif_dev);
1222
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301223 init_completion(&hif_dev->fw_done);
Sujith.Manoharan@atheros.com47fce022010-05-11 16:24:41 +05301224
Sujithce43cee2010-06-02 15:53:30 +05301225 /* Find out which firmware to load */
1226
Sujith Manoharan0b5ead92010-12-07 16:31:38 +05301227 if (IS_AR7010_DEVICE(id->driver_info))
Sujith Manoharan9efabad2011-04-13 11:22:33 +05301228 hif_dev->fw_name = FIRMWARE_AR7010_1_1;
Rajkumar Manoharanfa6e15e2010-11-19 16:53:22 +05301229 else
John W. Linvilled0ee0eb2010-06-23 14:20:45 -04001230 hif_dev->fw_name = FIRMWARE_AR9271;
Sujithce43cee2010-06-02 15:53:30 +05301231
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301232 ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
1233 &hif_dev->udev->dev, GFP_KERNEL,
1234 hif_dev, ath9k_hif_usb_firmware_cb);
Sujithfb9987d2010-03-17 14:25:25 +05301235 if (ret) {
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301236 dev_err(&hif_dev->udev->dev,
1237 "ath9k_htc: Async request for firmware %s failed\n",
1238 hif_dev->fw_name);
1239 goto err_fw_req;
Sujithfb9987d2010-03-17 14:25:25 +05301240 }
1241
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301242 dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
1243 hif_dev->fw_name);
Sujithfb9987d2010-03-17 14:25:25 +05301244
1245 return 0;
1246
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301247err_fw_req:
Sujithfb9987d2010-03-17 14:25:25 +05301248 usb_set_intfdata(interface, NULL);
1249 kfree(hif_dev);
1250 usb_put_dev(udev);
1251err_alloc:
1252 return ret;
1253}
1254
Sujith62e47162010-04-23 10:28:16 +05301255static void ath9k_hif_usb_reboot(struct usb_device *udev)
1256{
1257 u32 reboot_cmd = 0xffffffff;
1258 void *buf;
1259 int ret;
1260
Julia Lawalla465a2c2010-05-15 23:17:19 +02001261 buf = kmemdup(&reboot_cmd, 4, GFP_KERNEL);
Sujith62e47162010-04-23 10:28:16 +05301262 if (!buf)
1263 return;
1264
Sujith62e47162010-04-23 10:28:16 +05301265 ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE),
1266 buf, 4, NULL, HZ);
1267 if (ret)
1268 dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n");
1269
1270 kfree(buf);
1271}
1272
Sujithfb9987d2010-03-17 14:25:25 +05301273static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
1274{
1275 struct usb_device *udev = interface_to_usbdev(interface);
Joe Perchesb2767362010-11-30 13:42:08 -08001276 struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
Sujith Manoharan97dcec52010-12-20 08:02:42 +05301277 bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false;
Sujithfb9987d2010-03-17 14:25:25 +05301278
Sujith Manoharan36bcce42011-02-21 07:47:52 +05301279 if (!hif_dev)
1280 return;
1281
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301282 wait_for_completion(&hif_dev->fw_done);
1283
Ming Lei32e31de2012-08-21 16:04:27 +08001284 if (hif_dev->flags & HIF_USB_READY) {
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301285 ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
1286 ath9k_htc_hw_free(hif_dev->htc_handle);
1287 ath9k_hif_usb_dev_deinit(hif_dev);
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301288 }
1289
Sujith Manoharan36bcce42011-02-21 07:47:52 +05301290 usb_set_intfdata(interface, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301291
Sujith Manoharan97dcec52010-12-20 08:02:42 +05301292 if (!unplugged && (hif_dev->flags & HIF_USB_START))
Sujith62e47162010-04-23 10:28:16 +05301293 ath9k_hif_usb_reboot(udev);
Sujithfb9987d2010-03-17 14:25:25 +05301294
1295 kfree(hif_dev);
1296 dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n");
1297 usb_put_dev(udev);
1298}
1299
1300#ifdef CONFIG_PM
1301static int ath9k_hif_usb_suspend(struct usb_interface *interface,
1302 pm_message_t message)
1303{
Joe Perchesb2767362010-11-30 13:42:08 -08001304 struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
Sujithfb9987d2010-03-17 14:25:25 +05301305
Sujith Manoharanf933ebe2010-12-01 12:30:27 +05301306 /*
1307 * The device has to be set to FULLSLEEP mode in case no
1308 * interface is up.
1309 */
1310 if (!(hif_dev->flags & HIF_USB_START))
1311 ath9k_htc_suspend(hif_dev->htc_handle);
1312
Sujithfb9987d2010-03-17 14:25:25 +05301313 ath9k_hif_usb_dealloc_urbs(hif_dev);
1314
1315 return 0;
1316}
1317
1318static int ath9k_hif_usb_resume(struct usb_interface *interface)
1319{
Joe Perchesb2767362010-11-30 13:42:08 -08001320 struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
Rajkumar Manoharanfa6e15e2010-11-19 16:53:22 +05301321 struct htc_target *htc_handle = hif_dev->htc_handle;
Sujithfb9987d2010-03-17 14:25:25 +05301322 int ret;
Ming Lei32e31de2012-08-21 16:04:27 +08001323 const struct firmware *fw;
Sujithfb9987d2010-03-17 14:25:25 +05301324
1325 ret = ath9k_hif_usb_alloc_urbs(hif_dev);
1326 if (ret)
1327 return ret;
1328
Ming Lei32e31de2012-08-21 16:04:27 +08001329 if (hif_dev->flags & HIF_USB_READY) {
1330 /* request cached firmware during suspend/resume cycle */
1331 ret = request_firmware(&fw, hif_dev->fw_name,
1332 &hif_dev->udev->dev);
1333 if (ret)
1334 goto fail_resume;
1335
1336 hif_dev->fw_data = fw->data;
1337 hif_dev->fw_size = fw->size;
Sujith Manoharan0ed7b932012-01-30 14:17:18 +05301338 ret = ath9k_hif_usb_download_fw(hif_dev);
Ming Lei32e31de2012-08-21 16:04:27 +08001339 release_firmware(fw);
Sujithfb9987d2010-03-17 14:25:25 +05301340 if (ret)
1341 goto fail_resume;
1342 } else {
1343 ath9k_hif_usb_dealloc_urbs(hif_dev);
1344 return -EIO;
1345 }
1346
1347 mdelay(100);
1348
Rajkumar Manoharanfa6e15e2010-11-19 16:53:22 +05301349 ret = ath9k_htc_resume(htc_handle);
Sujithfb9987d2010-03-17 14:25:25 +05301350
1351 if (ret)
1352 goto fail_resume;
1353
1354 return 0;
1355
1356fail_resume:
1357 ath9k_hif_usb_dealloc_urbs(hif_dev);
1358
1359 return ret;
1360}
1361#endif
1362
1363static struct usb_driver ath9k_hif_usb_driver = {
Sujith Manoharan50f68712011-04-11 22:56:55 +05301364 .name = KBUILD_MODNAME,
Sujithfb9987d2010-03-17 14:25:25 +05301365 .probe = ath9k_hif_usb_probe,
1366 .disconnect = ath9k_hif_usb_disconnect,
1367#ifdef CONFIG_PM
1368 .suspend = ath9k_hif_usb_suspend,
1369 .resume = ath9k_hif_usb_resume,
1370 .reset_resume = ath9k_hif_usb_resume,
1371#endif
1372 .id_table = ath9k_hif_usb_ids,
1373 .soft_unbind = 1,
Sarah Sharpe1f12eb2012-04-23 10:08:51 -07001374 .disable_hub_initiated_lpm = 1,
Sujithfb9987d2010-03-17 14:25:25 +05301375};
1376
1377int ath9k_hif_usb_init(void)
1378{
1379 return usb_register(&ath9k_hif_usb_driver);
1380}
1381
1382void ath9k_hif_usb_exit(void)
1383{
1384 usb_deregister(&ath9k_hif_usb_driver);
1385}