blob: f8788bf0a7d39ed02c284a4f5cb8ea51c8dbae98 [file] [log] [blame]
Sage Ahn247e9cf2012-05-15 13:20:36 +09001/*
2 * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/module.h>
Sage Ahn247e9cf2012-05-15 13:20:36 +090015#include <linux/kernel.h>
16#include <linux/usb.h>
17#include <asm/byteorder.h>
Adnan Aliff5e4a12012-05-31 11:32:48 +010018#include <linux/kthread.h>
Sage Ahn247e9cf2012-05-15 13:20:36 +090019
Sage Ahn247e9cf2012-05-15 13:20:36 +090020#include "gdm_usb.h"
21#include "gdm_wimax.h"
22#include "usb_boot.h"
23#include "hci.h"
24
25#include "usb_ids.h"
26
27MODULE_DEVICE_TABLE(usb, id_table);
28
Macpaul Lin0d660022012-09-12 17:49:24 +080029#define TX_BUF_SIZE 2048
Sage Ahn247e9cf2012-05-15 13:20:36 +090030#if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
Macpaul Lin0d660022012-09-12 17:49:24 +080031#define RX_BUF_SIZE (128*1024) /* For packet aggregation */
Sage Ahn247e9cf2012-05-15 13:20:36 +090032#else
Macpaul Lin0d660022012-09-12 17:49:24 +080033#define RX_BUF_SIZE 2048
Sage Ahn247e9cf2012-05-15 13:20:36 +090034#endif
35
36#define GDM7205_PADDING 256
37
38#define H2B(x) __cpu_to_be16(x)
39#define B2H(x) __be16_to_cpu(x)
40#define DB2H(x) __be32_to_cpu(x)
41
Macpaul Lin0d660022012-09-12 17:49:24 +080042#define DOWNLOAD_CONF_VALUE 0x21
Sage Ahn247e9cf2012-05-15 13:20:36 +090043
44#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
45
46static DECLARE_WAIT_QUEUE_HEAD(k_wait);
47static LIST_HEAD(k_list);
48static DEFINE_SPINLOCK(k_lock);
49static int k_mode_stop;
50
Macpaul Lin0d660022012-09-12 17:49:24 +080051#define K_WAIT_TIME (2 * HZ / 100)
Sage Ahn247e9cf2012-05-15 13:20:36 +090052
53#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
54
55static int init_usb(struct usbwm_dev *udev);
56static void release_usb(struct usbwm_dev *udev);
57
58/*#define DEBUG */
59#ifdef DEBUG
60static void hexdump(char *title, u8 *data, int len)
61{
62 int i;
63
64 printk(KERN_DEBUG "%s: length = %d\n", title, len);
65 for (i = 0; i < len; i++) {
66 printk(KERN_DEBUG "%02x ", data[i]);
67 if ((i & 0xf) == 0xf)
68 printk(KERN_DEBUG "\n");
69 }
70 printk(KERN_DEBUG "\n");
71}
72#endif
73
74static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx)
75{
Ben Chan129575f2012-09-12 11:43:41 -070076 struct usb_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC);
Sage Ahn247e9cf2012-05-15 13:20:36 +090077
Ben Chan129575f2012-09-12 11:43:41 -070078 if (!t)
79 return NULL;
Sage Ahn247e9cf2012-05-15 13:20:36 +090080
Sage Ahn247e9cf2012-05-15 13:20:36 +090081 t->urb = usb_alloc_urb(0, GFP_ATOMIC);
82 t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
Ben Chan129575f2012-09-12 11:43:41 -070083 if (!t->urb || !t->buf) {
84 usb_free_urb(t->urb);
85 kfree(t->buf);
86 kfree(t);
87 return NULL;
88 }
Sage Ahn247e9cf2012-05-15 13:20:36 +090089
90 t->tx_cxt = tx;
91
92 return t;
Sage Ahn247e9cf2012-05-15 13:20:36 +090093}
94
95static void free_tx_struct(struct usb_tx *t)
96{
97 if (t) {
98 usb_free_urb(t->urb);
99 kfree(t->buf);
100 kfree(t);
101 }
102}
103
104static struct usb_rx *alloc_rx_struct(struct rx_cxt *rx)
105{
Ben Chan129575f2012-09-12 11:43:41 -0700106 struct usb_rx *r = kzalloc(sizeof(*r), GFP_ATOMIC);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900107
Ben Chan129575f2012-09-12 11:43:41 -0700108 if (!r)
109 return NULL;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900110
111 r->urb = usb_alloc_urb(0, GFP_ATOMIC);
112 r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC);
Ben Chan129575f2012-09-12 11:43:41 -0700113 if (!r->urb || !r->buf) {
Sage Ahn247e9cf2012-05-15 13:20:36 +0900114 usb_free_urb(r->urb);
115 kfree(r->buf);
116 kfree(r);
Ben Chan129575f2012-09-12 11:43:41 -0700117 return NULL;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900118 }
Ben Chan129575f2012-09-12 11:43:41 -0700119
120 r->rx_cxt = rx;
121 return r;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900122}
123
124static void free_rx_struct(struct usb_rx *r)
125{
126 if (r) {
127 usb_free_urb(r->urb);
128 kfree(r->buf);
129 kfree(r);
130 }
131}
132
133/* Before this function is called, spin lock should be locked. */
134static struct usb_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc)
135{
136 struct usb_tx *t;
137
138 if (list_empty(&tx->free_list)) {
139 *no_spc = 1;
140 return NULL;
141 }
142
143 t = list_entry(tx->free_list.next, struct usb_tx, list);
144 list_del(&t->list);
145
146 *no_spc = list_empty(&tx->free_list) ? 1 : 0;
147
148 return t;
149}
150
151/* Before this function is called, spin lock should be locked. */
152static void put_tx_struct(struct tx_cxt *tx, struct usb_tx *t)
153{
154 list_add_tail(&t->list, &tx->free_list);
155}
156
157/* Before this function is called, spin lock should be locked. */
158static struct usb_rx *get_rx_struct(struct rx_cxt *rx)
159{
160 struct usb_rx *r;
161
162 if (list_empty(&rx->free_list)) {
163 r = alloc_rx_struct(rx);
164 if (r == NULL)
165 return NULL;
166
167 list_add(&r->list, &rx->free_list);
168 }
169
170 r = list_entry(rx->free_list.next, struct usb_rx, list);
Wei Yongjune5d2cb42012-09-05 14:49:15 +0800171 list_move_tail(&r->list, &rx->used_list);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900172
173 return r;
174}
175
176/* Before this function is called, spin lock should be locked. */
177static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r)
178{
Wei Yongjun73295fe2012-09-06 12:36:49 +0800179 list_move(&r->list, &rx->free_list);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900180}
181
182static int init_usb(struct usbwm_dev *udev)
183{
184 int ret = 0, i;
185 struct tx_cxt *tx = &udev->tx;
186 struct rx_cxt *rx = &udev->rx;
187 struct usb_tx *t;
188 struct usb_rx *r;
Ben Chan1a276b82012-11-24 19:35:36 -0800189 unsigned long flags;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900190
191 INIT_LIST_HEAD(&tx->free_list);
192 INIT_LIST_HEAD(&tx->sdu_list);
193 INIT_LIST_HEAD(&tx->hci_list);
194#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
195 INIT_LIST_HEAD(&tx->pending_list);
196#endif
197
198 INIT_LIST_HEAD(&rx->free_list);
199 INIT_LIST_HEAD(&rx->used_list);
200
201 spin_lock_init(&tx->lock);
202 spin_lock_init(&rx->lock);
203
Ben Chan1a276b82012-11-24 19:35:36 -0800204 spin_lock_irqsave(&tx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900205 for (i = 0; i < MAX_NR_SDU_BUF; i++) {
206 t = alloc_tx_struct(tx);
207 if (t == NULL) {
Dan Carpentere143ef82012-11-29 17:17:25 +0300208 spin_unlock_irqrestore(&tx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900209 ret = -ENOMEM;
210 goto fail;
211 }
212 list_add(&t->list, &tx->free_list);
213 }
Ben Chan1a276b82012-11-24 19:35:36 -0800214 spin_unlock_irqrestore(&tx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900215
216 r = alloc_rx_struct(rx);
217 if (r == NULL) {
218 ret = -ENOMEM;
219 goto fail;
220 }
221
Ben Chan1a276b82012-11-24 19:35:36 -0800222 spin_lock_irqsave(&rx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900223 list_add(&r->list, &rx->free_list);
Ben Chan1a276b82012-11-24 19:35:36 -0800224 spin_unlock_irqrestore(&rx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900225 return ret;
226
227fail:
228 release_usb(udev);
229 return ret;
230}
231
232static void release_usb(struct usbwm_dev *udev)
233{
234 struct tx_cxt *tx = &udev->tx;
235 struct rx_cxt *rx = &udev->rx;
236 struct usb_tx *t, *t_next;
237 struct usb_rx *r, *r_next;
Ben Chan1a276b82012-11-24 19:35:36 -0800238 unsigned long flags;
239
240 spin_lock_irqsave(&tx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900241
242 list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) {
243 list_del(&t->list);
244 free_tx_struct(t);
245 }
246
247 list_for_each_entry_safe(t, t_next, &tx->hci_list, list) {
248 list_del(&t->list);
249 free_tx_struct(t);
250 }
251
252 list_for_each_entry_safe(t, t_next, &tx->free_list, list) {
253 list_del(&t->list);
254 free_tx_struct(t);
255 }
256
Ben Chan1a276b82012-11-24 19:35:36 -0800257 spin_unlock_irqrestore(&tx->lock, flags);
258
259 spin_lock_irqsave(&rx->lock, flags);
260
Sage Ahn247e9cf2012-05-15 13:20:36 +0900261 list_for_each_entry_safe(r, r_next, &rx->free_list, list) {
262 list_del(&r->list);
263 free_rx_struct(r);
264 }
265
266 list_for_each_entry_safe(r, r_next, &rx->used_list, list) {
267 list_del(&r->list);
268 free_rx_struct(r);
269 }
Ben Chan1a276b82012-11-24 19:35:36 -0800270
271 spin_unlock_irqrestore(&rx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900272}
273
Ben Chan0c16ae72012-06-12 11:23:32 -0700274static void __gdm_usb_send_complete(struct urb *urb)
Sage Ahn247e9cf2012-05-15 13:20:36 +0900275{
276 struct usb_tx *t = urb->context;
277 struct tx_cxt *tx = t->tx_cxt;
278 u8 *pkt = t->buf;
279 u16 cmd_evt;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900280
281 /* Completion by usb_unlink_urb */
282 if (urb->status == -ECONNRESET)
283 return;
284
Sage Ahn247e9cf2012-05-15 13:20:36 +0900285 if (t->callback)
286 t->callback(t->cb_data);
287
288 /* Delete from sdu list or hci list. */
289 list_del(&t->list);
290
291 cmd_evt = (pkt[0] << 8) | pkt[1];
292 if (cmd_evt == WIMAX_TX_SDU)
293 put_tx_struct(tx, t);
294 else
295 free_tx_struct(t);
Ben Chandd13c862012-06-06 23:01:26 -0700296}
297
298static void gdm_usb_send_complete(struct urb *urb)
299{
Ben Chan0c16ae72012-06-12 11:23:32 -0700300 struct usb_tx *t = urb->context;
301 struct tx_cxt *tx = t->tx_cxt;
302 unsigned long flags;
Ben Chandd13c862012-06-06 23:01:26 -0700303
Ben Chan0c16ae72012-06-12 11:23:32 -0700304 spin_lock_irqsave(&tx->lock, flags);
305 __gdm_usb_send_complete(urb);
306 spin_unlock_irqrestore(&tx->lock, flags);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900307}
308
309static int gdm_usb_send(void *priv_dev, void *data, int len,
310 void (*cb)(void *data), void *cb_data)
311{
312 struct usbwm_dev *udev = priv_dev;
313 struct usb_device *usbdev = udev->usbdev;
314 struct tx_cxt *tx = &udev->tx;
315 struct usb_tx *t;
316 int padding = udev->padding;
317 int no_spc = 0, ret;
318 u8 *pkt = data;
319 u16 cmd_evt;
Ben Chana7e4a982012-11-26 20:18:45 -0800320 unsigned long flags;
321#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
322 unsigned long flags2;
323#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
Sage Ahn247e9cf2012-05-15 13:20:36 +0900324
325 if (!udev->usbdev) {
YAMANE Toshiakia7d46832012-10-29 20:05:43 +0900326 dev_err(&usbdev->dev, "%s: No such device\n", __func__);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900327 return -ENODEV;
328 }
329
330 BUG_ON(len > TX_BUF_SIZE - padding - 1);
331
332 spin_lock_irqsave(&tx->lock, flags);
333
334 cmd_evt = (pkt[0] << 8) | pkt[1];
335 if (cmd_evt == WIMAX_TX_SDU) {
336 t = get_tx_struct(tx, &no_spc);
337 if (t == NULL) {
338 /* This case must not happen. */
339 spin_unlock_irqrestore(&tx->lock, flags);
340 return -ENOSPC;
341 }
342 list_add_tail(&t->list, &tx->sdu_list);
343 } else {
344 t = alloc_tx_struct(tx);
345 if (t == NULL) {
346 spin_unlock_irqrestore(&tx->lock, flags);
347 return -ENOMEM;
348 }
349 list_add_tail(&t->list, &tx->hci_list);
350 }
351
352 memcpy(t->buf + padding, data, len);
353 t->callback = cb;
354 t->cb_data = cb_data;
355
356 /*
357 * In some cases, USB Module of WiMax is blocked when data size is
358 * the multiple of 512. So, increment length by one in that case.
359 */
360 if ((len % 512) == 0)
361 len++;
362
363 usb_fill_bulk_urb(t->urb,
364 usbdev,
365 usb_sndbulkpipe(usbdev, 1),
366 t->buf,
367 len + padding,
368 gdm_usb_send_complete,
369 t);
370
371#ifdef DEBUG
372 hexdump("usb_send", t->buf, len + padding);
373#endif
374#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
375 if (usbdev->state & USB_STATE_SUSPENDED) {
376 list_add_tail(&t->p_list, &tx->pending_list);
377 schedule_work(&udev->pm_ws);
378 goto out;
379 }
380#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
381
382#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
383 if (udev->bw_switch) {
384 list_add_tail(&t->p_list, &tx->pending_list);
385 goto out;
386 } else if (cmd_evt == WIMAX_SCAN) {
387 struct rx_cxt *rx;
388 struct usb_rx *r;
389
390 rx = &udev->rx;
391
Ben Chan1a276b82012-11-24 19:35:36 -0800392 spin_lock_irqsave(&rx->lock, flags2);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900393 list_for_each_entry(r, &rx->used_list, list)
394 usb_unlink_urb(r->urb);
Ben Chan1a276b82012-11-24 19:35:36 -0800395 spin_unlock_irqrestore(&rx->lock, flags2);
396
Sage Ahn247e9cf2012-05-15 13:20:36 +0900397 udev->bw_switch = 1;
398
Ben Chan1a276b82012-11-24 19:35:36 -0800399 spin_lock_irqsave(&k_lock, flags2);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900400 list_add_tail(&udev->list, &k_list);
Ben Chan1a276b82012-11-24 19:35:36 -0800401 spin_unlock_irqrestore(&k_lock, flags2);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900402
403 wake_up(&k_wait);
404 }
405#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
406
407 ret = usb_submit_urb(t->urb, GFP_ATOMIC);
408 if (ret)
409 goto send_fail;
410
411#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
412 usb_mark_last_busy(usbdev);
413#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
414
415#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
416out:
417#endif
418 spin_unlock_irqrestore(&tx->lock, flags);
419
420 if (no_spc)
421 return -ENOSPC;
422
423 return 0;
424
425send_fail:
426 t->callback = NULL;
Ben Chan0c16ae72012-06-12 11:23:32 -0700427 __gdm_usb_send_complete(t->urb);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900428 spin_unlock_irqrestore(&tx->lock, flags);
429 return ret;
430}
431
432static void gdm_usb_rcv_complete(struct urb *urb)
433{
434 struct usb_rx *r = urb->context;
435 struct rx_cxt *rx = r->rx_cxt;
436 struct usbwm_dev *udev = container_of(r->rx_cxt, struct usbwm_dev, rx);
437 struct tx_cxt *tx = &udev->tx;
438 struct usb_tx *t;
439 u16 cmd_evt;
Ben Chan1a276b82012-11-24 19:35:36 -0800440 unsigned long flags, flags2;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900441
442#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
443 struct usb_device *dev = urb->dev;
444#endif
445
446 /* Completion by usb_unlink_urb */
447 if (urb->status == -ECONNRESET)
448 return;
449
450 spin_lock_irqsave(&tx->lock, flags);
451
452 if (!urb->status) {
453 cmd_evt = (r->buf[0] << 8) | (r->buf[1]);
454#ifdef DEBUG
455 hexdump("usb_receive", r->buf, urb->actual_length);
456#endif
457 if (cmd_evt == WIMAX_SDU_TX_FLOW) {
458 if (r->buf[4] == 0) {
459#ifdef DEBUG
460 printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
461#endif
462 list_for_each_entry(t, &tx->sdu_list, list)
463 usb_unlink_urb(t->urb);
464 } else if (r->buf[4] == 1) {
465#ifdef DEBUG
466 printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
467#endif
468 list_for_each_entry(t, &tx->sdu_list, list) {
469 usb_submit_urb(t->urb, GFP_ATOMIC);
470 }
471 /*
472 * If free buffer for sdu tx doesn't
473 * exist, then tx queue should not be
474 * woken. For this reason, don't pass
475 * the command, START_SDU_TX.
476 */
477 if (list_empty(&tx->free_list))
478 urb->actual_length = 0;
479 }
480 }
481 }
482
483 if (!urb->status && r->callback)
484 r->callback(r->cb_data, r->buf, urb->actual_length);
485
Ben Chan1a276b82012-11-24 19:35:36 -0800486 spin_lock_irqsave(&rx->lock, flags2);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900487 put_rx_struct(rx, r);
Ben Chan1a276b82012-11-24 19:35:36 -0800488 spin_unlock_irqrestore(&rx->lock, flags2);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900489
490 spin_unlock_irqrestore(&tx->lock, flags);
491
492#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
493 usb_mark_last_busy(dev);
494#endif
495}
496
497static int gdm_usb_receive(void *priv_dev,
498 void (*cb)(void *cb_data, void *data, int len),
499 void *cb_data)
500{
501 struct usbwm_dev *udev = priv_dev;
502 struct usb_device *usbdev = udev->usbdev;
503 struct rx_cxt *rx = &udev->rx;
504 struct usb_rx *r;
505 unsigned long flags;
506
507 if (!udev->usbdev) {
YAMANE Toshiakia7d46832012-10-29 20:05:43 +0900508 dev_err(&usbdev->dev, "%s: No such device\n", __func__);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900509 return -ENODEV;
510 }
511
512 spin_lock_irqsave(&rx->lock, flags);
513 r = get_rx_struct(rx);
514 spin_unlock_irqrestore(&rx->lock, flags);
515
516 if (r == NULL)
517 return -ENOMEM;
518
519 r->callback = cb;
520 r->cb_data = cb_data;
521
522 usb_fill_bulk_urb(r->urb,
523 usbdev,
524 usb_rcvbulkpipe(usbdev, 0x82),
525 r->buf,
526 RX_BUF_SIZE,
527 gdm_usb_rcv_complete,
528 r);
529
530 return usb_submit_urb(r->urb, GFP_ATOMIC);
531}
532
533#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
534static void do_pm_control(struct work_struct *work)
535{
536 struct usbwm_dev *udev = container_of(work, struct usbwm_dev, pm_ws);
537 struct tx_cxt *tx = &udev->tx;
538 int ret;
539 unsigned long flags;
540
541 ret = usb_autopm_get_interface(udev->intf);
542 if (!ret)
543 usb_autopm_put_interface(udev->intf);
544
545 spin_lock_irqsave(&tx->lock, flags);
546 if (!(udev->usbdev->state & USB_STATE_SUSPENDED)
547 && (!list_empty(&tx->hci_list) || !list_empty(&tx->sdu_list))) {
548 struct usb_tx *t, *temp;
549
550 list_for_each_entry_safe(t, temp, &tx->pending_list, p_list) {
551 list_del(&t->p_list);
552 ret = usb_submit_urb(t->urb, GFP_ATOMIC);
553
554 if (ret) {
555 t->callback = NULL;
Ben Chan0c16ae72012-06-12 11:23:32 -0700556 __gdm_usb_send_complete(t->urb);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900557 }
558 }
559 }
560 spin_unlock_irqrestore(&tx->lock, flags);
561}
562#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
563
564static int gdm_usb_probe(struct usb_interface *intf,
565 const struct usb_device_id *id)
566{
567 int ret = 0;
568 u8 bConfigurationValue;
569 struct phy_dev *phy_dev = NULL;
570 struct usbwm_dev *udev = NULL;
571 u16 idVendor, idProduct, bcdDevice;
572
573 struct usb_device *usbdev = interface_to_usbdev(intf);
574
575 usb_get_dev(usbdev);
576 bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
577
578 /*USB description is set up with Little-Endian*/
579 idVendor = L2H(usbdev->descriptor.idVendor);
580 idProduct = L2H(usbdev->descriptor.idProduct);
581 bcdDevice = L2H(usbdev->descriptor.bcdDevice);
582
YAMANE Toshiakia7d46832012-10-29 20:05:43 +0900583 dev_info(&intf->dev, "Found GDM USB VID = 0x%04x PID = 0x%04x...\n",
584 idVendor, idProduct);
585 dev_info(&intf->dev, "GCT WiMax driver version %s\n", DRIVER_VERSION);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900586
587
588 if (idProduct == EMERGENCY_PID) {
589 ret = usb_emergency(usbdev);
590 goto out;
591 }
592
593 /* Support for EEPROM bootloader */
594 if (bConfigurationValue == DOWNLOAD_CONF_VALUE ||
595 idProduct & B_DOWNLOAD) {
596 ret = usb_boot(usbdev, bcdDevice);
597 goto out;
598 }
599
Devendra Naga7fc03ad2012-07-12 11:56:54 +0545600 phy_dev = kzalloc(sizeof(*phy_dev), GFP_KERNEL);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900601 if (phy_dev == NULL) {
602 ret = -ENOMEM;
603 goto out;
604 }
Devendra Naga7fc03ad2012-07-12 11:56:54 +0545605 udev = kzalloc(sizeof(*udev), GFP_KERNEL);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900606 if (udev == NULL) {
607 ret = -ENOMEM;
608 goto out;
609 }
610
Sage Ahn247e9cf2012-05-15 13:20:36 +0900611 if (idProduct == 0x7205 || idProduct == 0x7206)
612 udev->padding = GDM7205_PADDING;
613 else
614 udev->padding = 0;
615
616 phy_dev->priv_dev = (void *)udev;
617 phy_dev->send_func = gdm_usb_send;
618 phy_dev->rcv_func = gdm_usb_receive;
619
620 ret = init_usb(udev);
621 if (ret < 0)
622 goto out;
623
624 udev->usbdev = usbdev;
625
626#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
627 udev->intf = intf;
628
629 intf->needs_remote_wakeup = 1;
630 device_init_wakeup(&intf->dev, 1);
631
632 pm_runtime_set_autosuspend_delay(&usbdev->dev, 10 * 1000); /* msec */
633
634 INIT_WORK(&udev->pm_ws, do_pm_control);
635#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
636
Paul Stewart54bc1ff2012-05-17 11:15:10 -0700637 ret = register_wimax_device(phy_dev, &intf->dev);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900638
639out:
640 if (ret) {
641 kfree(phy_dev);
642 kfree(udev);
Ben Chan1a276b82012-11-24 19:35:36 -0800643 } else {
644 usb_set_intfdata(intf, phy_dev);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900645 }
Sage Ahn247e9cf2012-05-15 13:20:36 +0900646 return ret;
647}
648
649static void gdm_usb_disconnect(struct usb_interface *intf)
650{
651 u8 bConfigurationValue;
652 struct phy_dev *phy_dev;
653 struct usbwm_dev *udev;
654 u16 idProduct;
655 struct usb_device *usbdev = interface_to_usbdev(intf);
656
657 bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
658 phy_dev = usb_get_intfdata(intf);
659
660 /*USB description is set up with Little-Endian*/
661 idProduct = L2H(usbdev->descriptor.idProduct);
662
663 if (idProduct != EMERGENCY_PID &&
664 bConfigurationValue != DOWNLOAD_CONF_VALUE &&
665 (idProduct & B_DOWNLOAD) == 0) {
666 udev = phy_dev->priv_dev;
667 udev->usbdev = NULL;
668
669 unregister_wimax_device(phy_dev);
670 release_usb(udev);
671 kfree(udev);
672 kfree(phy_dev);
673 }
674
675 usb_put_dev(usbdev);
676}
677
678#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
679static int gdm_suspend(struct usb_interface *intf, pm_message_t pm_msg)
680{
681 struct phy_dev *phy_dev;
682 struct usbwm_dev *udev;
683 struct rx_cxt *rx;
684 struct usb_rx *r;
Ben Chan1a276b82012-11-24 19:35:36 -0800685 unsigned long flags;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900686
687 phy_dev = usb_get_intfdata(intf);
Ben Chan1a276b82012-11-24 19:35:36 -0800688 if (!phy_dev)
689 return 0;
690
Sage Ahn247e9cf2012-05-15 13:20:36 +0900691 udev = phy_dev->priv_dev;
692 rx = &udev->rx;
693
Ben Chan1a276b82012-11-24 19:35:36 -0800694 spin_lock_irqsave(&rx->lock, flags);
695
Sage Ahn247e9cf2012-05-15 13:20:36 +0900696 list_for_each_entry(r, &rx->used_list, list)
697 usb_unlink_urb(r->urb);
698
Ben Chan1a276b82012-11-24 19:35:36 -0800699 spin_unlock_irqrestore(&rx->lock, flags);
700
Sage Ahn247e9cf2012-05-15 13:20:36 +0900701 return 0;
702}
703
704static int gdm_resume(struct usb_interface *intf)
705{
706 struct phy_dev *phy_dev;
707 struct usbwm_dev *udev;
708 struct rx_cxt *rx;
709 struct usb_rx *r;
Ben Chan1a276b82012-11-24 19:35:36 -0800710 unsigned long flags;
Sage Ahn247e9cf2012-05-15 13:20:36 +0900711
712 phy_dev = usb_get_intfdata(intf);
Ben Chan1a276b82012-11-24 19:35:36 -0800713 if (!phy_dev)
714 return 0;
715
Sage Ahn247e9cf2012-05-15 13:20:36 +0900716 udev = phy_dev->priv_dev;
717 rx = &udev->rx;
718
Ben Chan1a276b82012-11-24 19:35:36 -0800719 spin_lock_irqsave(&rx->lock, flags);
720
Sage Ahn247e9cf2012-05-15 13:20:36 +0900721 list_for_each_entry(r, &rx->used_list, list)
722 usb_submit_urb(r->urb, GFP_ATOMIC);
723
Ben Chan1a276b82012-11-24 19:35:36 -0800724 spin_unlock_irqrestore(&rx->lock, flags);
725
Sage Ahn247e9cf2012-05-15 13:20:36 +0900726 return 0;
727}
728
729#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
730
731#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
732static int k_mode_thread(void *arg)
733{
734 struct usbwm_dev *udev;
735 struct tx_cxt *tx;
736 struct rx_cxt *rx;
737 struct usb_tx *t, *temp;
738 struct usb_rx *r;
739 unsigned long flags, flags2, expire;
740 int ret;
741
Sage Ahn247e9cf2012-05-15 13:20:36 +0900742 while (!k_mode_stop) {
743
744 spin_lock_irqsave(&k_lock, flags2);
745 while (!list_empty(&k_list)) {
746
747 udev = list_entry(k_list.next, struct usbwm_dev, list);
748 tx = &udev->tx;
749 rx = &udev->rx;
750
751 list_del(&udev->list);
752 spin_unlock_irqrestore(&k_lock, flags2);
753
754 expire = jiffies + K_WAIT_TIME;
755 while (jiffies < expire)
756 schedule_timeout(K_WAIT_TIME);
757
Ben Chan1a276b82012-11-24 19:35:36 -0800758 spin_lock_irqsave(&rx->lock, flags);
759
Sage Ahn247e9cf2012-05-15 13:20:36 +0900760 list_for_each_entry(r, &rx->used_list, list)
761 usb_submit_urb(r->urb, GFP_ATOMIC);
762
Ben Chan1a276b82012-11-24 19:35:36 -0800763 spin_unlock_irqrestore(&rx->lock, flags);
764
Sage Ahn247e9cf2012-05-15 13:20:36 +0900765 spin_lock_irqsave(&tx->lock, flags);
766
767 list_for_each_entry_safe(t, temp, &tx->pending_list,
768 p_list) {
769 list_del(&t->p_list);
770 ret = usb_submit_urb(t->urb, GFP_ATOMIC);
771
772 if (ret) {
773 t->callback = NULL;
Ben Chan0c16ae72012-06-12 11:23:32 -0700774 __gdm_usb_send_complete(t->urb);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900775 }
776 }
777
778 udev->bw_switch = 0;
779 spin_unlock_irqrestore(&tx->lock, flags);
780
781 spin_lock_irqsave(&k_lock, flags2);
782 }
Arnd Bergmann4b266e52014-01-02 13:07:34 +0100783 wait_event_interruptible_lock_irq(k_wait,
784 !list_empty(&k_list) || k_mode_stop,
785 k_lock);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900786 spin_unlock_irqrestore(&k_lock, flags2);
Sage Ahn247e9cf2012-05-15 13:20:36 +0900787 }
788 return 0;
789}
790#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
791
792static struct usb_driver gdm_usb_driver = {
793 .name = "gdm_wimax",
794 .probe = gdm_usb_probe,
795 .disconnect = gdm_usb_disconnect,
796 .id_table = id_table,
797#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
798 .supports_autosuspend = 1,
799 .suspend = gdm_suspend,
800 .resume = gdm_resume,
801 .reset_resume = gdm_resume,
802#endif
803};
804
805static int __init usb_gdm_wimax_init(void)
806{
807#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
Al Viroc4144672012-10-02 16:34:38 -0400808 kthread_run(k_mode_thread, NULL, "k_mode_wimax");
Sage Ahn247e9cf2012-05-15 13:20:36 +0900809#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
810 return usb_register(&gdm_usb_driver);
811}
812
813static void __exit usb_gdm_wimax_exit(void)
814{
815#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
816 k_mode_stop = 1;
817 wake_up(&k_wait);
818#endif
819 usb_deregister(&gdm_usb_driver);
820}
821
822module_init(usb_gdm_wimax_init);
823module_exit(usb_gdm_wimax_exit);
824
825MODULE_VERSION(DRIVER_VERSION);
826MODULE_DESCRIPTION("GCT WiMax Device Driver");
827MODULE_AUTHOR("Ethan Park");
828MODULE_LICENSE("GPL");