blob: bf30c0bdf6d5a1bbde011bfb909bad403726c393 [file] [log] [blame]
Matthew Garrett0d456192010-04-01 12:31:07 -04001/*
2 USB Driver layer for GSM modems
3
4 Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de>
5
6 This driver is free software; you can redistribute it and/or modify
7 it under the terms of Version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
9
10 Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
11
12 History: see the git log.
13
14 Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
15
16 This driver exists because the "normal" serial driver doesn't work too well
17 with GSM modems. Issues:
18 - data loss -- one single Receive URB is not nearly enough
19 - controlling the baud rate doesn't make sense
20*/
21
22#define DRIVER_VERSION "v0.7.2"
23#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
24#define DRIVER_DESC "USB Driver for GSM modems"
25
26#include <linux/kernel.h>
27#include <linux/jiffies.h>
28#include <linux/errno.h>
29#include <linux/slab.h>
30#include <linux/tty.h>
31#include <linux/tty_flip.h>
32#include <linux/module.h>
33#include <linux/bitops.h>
Peter Huewe66921ed2010-12-09 23:27:35 +010034#include <linux/uaccess.h>
Matthew Garrett0d456192010-04-01 12:31:07 -040035#include <linux/usb.h>
36#include <linux/usb/serial.h>
Dan Williams02303f72010-11-19 16:04:00 -060037#include <linux/serial.h>
Matthew Garrett0d456192010-04-01 12:31:07 -040038#include "usb-wwan.h"
39
Rusty Russell90ab5ee2012-01-13 09:32:20 +103040static bool debug;
Matthew Garrett0d456192010-04-01 12:31:07 -040041
42void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
43{
44 struct usb_serial *serial = port->serial;
45 struct usb_wwan_port_private *portdata;
46
47 struct usb_wwan_intf_private *intfdata;
48
49 dbg("%s", __func__);
50
51 intfdata = port->serial->private;
52
53 if (!intfdata->send_setup)
54 return;
55
56 portdata = usb_get_serial_port_data(port);
57 mutex_lock(&serial->disc_mutex);
58 portdata->rts_state = on;
59 portdata->dtr_state = on;
60 if (serial->dev)
61 intfdata->send_setup(port);
62 mutex_unlock(&serial->disc_mutex);
63}
64EXPORT_SYMBOL(usb_wwan_dtr_rts);
65
66void usb_wwan_set_termios(struct tty_struct *tty,
67 struct usb_serial_port *port,
68 struct ktermios *old_termios)
69{
70 struct usb_wwan_intf_private *intfdata = port->serial->private;
71
72 dbg("%s", __func__);
73
74 /* Doesn't support option setting */
75 tty_termios_copy_hw(tty->termios, old_termios);
76
77 if (intfdata->send_setup)
78 intfdata->send_setup(port);
79}
80EXPORT_SYMBOL(usb_wwan_set_termios);
81
Alan Cox60b33c12011-02-14 16:26:14 +000082int usb_wwan_tiocmget(struct tty_struct *tty)
Matthew Garrett0d456192010-04-01 12:31:07 -040083{
84 struct usb_serial_port *port = tty->driver_data;
85 unsigned int value;
86 struct usb_wwan_port_private *portdata;
87
88 portdata = usb_get_serial_port_data(port);
89
90 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
91 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
92 ((portdata->cts_state) ? TIOCM_CTS : 0) |
93 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
94 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
95 ((portdata->ri_state) ? TIOCM_RNG : 0);
96
97 return value;
98}
99EXPORT_SYMBOL(usb_wwan_tiocmget);
100
Alan Cox20b9d172011-02-14 16:26:50 +0000101int usb_wwan_tiocmset(struct tty_struct *tty,
Matthew Garrett0d456192010-04-01 12:31:07 -0400102 unsigned int set, unsigned int clear)
103{
104 struct usb_serial_port *port = tty->driver_data;
105 struct usb_wwan_port_private *portdata;
106 struct usb_wwan_intf_private *intfdata;
107
108 portdata = usb_get_serial_port_data(port);
109 intfdata = port->serial->private;
110
111 if (!intfdata->send_setup)
112 return -EINVAL;
113
114 /* FIXME: what locks portdata fields ? */
115 if (set & TIOCM_RTS)
116 portdata->rts_state = 1;
117 if (set & TIOCM_DTR)
118 portdata->dtr_state = 1;
119
120 if (clear & TIOCM_RTS)
121 portdata->rts_state = 0;
122 if (clear & TIOCM_DTR)
123 portdata->dtr_state = 0;
124 return intfdata->send_setup(port);
125}
126EXPORT_SYMBOL(usb_wwan_tiocmset);
127
Dan Williams02303f72010-11-19 16:04:00 -0600128static int get_serial_info(struct usb_serial_port *port,
129 struct serial_struct __user *retinfo)
130{
131 struct serial_struct tmp;
132
133 if (!retinfo)
134 return -EFAULT;
135
136 memset(&tmp, 0, sizeof(tmp));
137 tmp.line = port->serial->minor;
138 tmp.port = port->number;
139 tmp.baud_base = tty_get_baud_rate(port->port.tty);
140 tmp.close_delay = port->port.close_delay / 10;
141 tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
142 ASYNC_CLOSING_WAIT_NONE :
143 port->port.closing_wait / 10;
144
145 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
146 return -EFAULT;
147 return 0;
148}
149
150static int set_serial_info(struct usb_serial_port *port,
151 struct serial_struct __user *newinfo)
152{
153 struct serial_struct new_serial;
154 unsigned int closing_wait, close_delay;
155 int retval = 0;
156
157 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
158 return -EFAULT;
159
160 close_delay = new_serial.close_delay * 10;
161 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
162 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
163
164 mutex_lock(&port->port.mutex);
165
166 if (!capable(CAP_SYS_ADMIN)) {
167 if ((close_delay != port->port.close_delay) ||
168 (closing_wait != port->port.closing_wait))
169 retval = -EPERM;
170 else
171 retval = -EOPNOTSUPP;
172 } else {
173 port->port.close_delay = close_delay;
174 port->port.closing_wait = closing_wait;
175 }
176
177 mutex_unlock(&port->port.mutex);
178 return retval;
179}
180
Alan Cox00a0d0d2011-02-14 16:27:06 +0000181int usb_wwan_ioctl(struct tty_struct *tty,
Dan Williams02303f72010-11-19 16:04:00 -0600182 unsigned int cmd, unsigned long arg)
183{
184 struct usb_serial_port *port = tty->driver_data;
185
186 dbg("%s cmd 0x%04x", __func__, cmd);
187
188 switch (cmd) {
189 case TIOCGSERIAL:
190 return get_serial_info(port,
191 (struct serial_struct __user *) arg);
192 case TIOCSSERIAL:
193 return set_serial_info(port,
194 (struct serial_struct __user *) arg);
195 default:
196 break;
197 }
198
199 dbg("%s arg not supported", __func__);
200
201 return -ENOIOCTLCMD;
202}
203EXPORT_SYMBOL(usb_wwan_ioctl);
204
Matthew Garrett0d456192010-04-01 12:31:07 -0400205/* Write */
206int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
207 const unsigned char *buf, int count)
208{
209 struct usb_wwan_port_private *portdata;
210 struct usb_wwan_intf_private *intfdata;
211 int i;
212 int left, todo;
213 struct urb *this_urb = NULL; /* spurious */
214 int err;
215 unsigned long flags;
216
217 portdata = usb_get_serial_port_data(port);
218 intfdata = port->serial->private;
219
220 dbg("%s: write (%d chars)", __func__, count);
221
222 i = 0;
223 left = count;
224 for (i = 0; left > 0 && i < N_OUT_URB; i++) {
225 todo = left;
226 if (todo > OUT_BUFLEN)
227 todo = OUT_BUFLEN;
228
229 this_urb = portdata->out_urbs[i];
230 if (test_and_set_bit(i, &portdata->out_busy)) {
231 if (time_before(jiffies,
232 portdata->tx_start_time[i] + 10 * HZ))
233 continue;
234 usb_unlink_urb(this_urb);
235 continue;
236 }
237 dbg("%s: endpoint %d buf %d", __func__,
238 usb_pipeendpoint(this_urb->pipe), i);
239
240 err = usb_autopm_get_interface_async(port->serial->interface);
241 if (err < 0)
242 break;
243
244 /* send the data */
245 memcpy(this_urb->transfer_buffer, buf, todo);
246 this_urb->transfer_buffer_length = todo;
247
248 spin_lock_irqsave(&intfdata->susp_lock, flags);
249 if (intfdata->suspended) {
250 usb_anchor_urb(this_urb, &portdata->delayed);
251 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
252 } else {
253 intfdata->in_flight++;
254 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700255 usb_anchor_urb(this_urb, &portdata->submitted);
Matthew Garrett0d456192010-04-01 12:31:07 -0400256 err = usb_submit_urb(this_urb, GFP_ATOMIC);
257 if (err) {
258 dbg("usb_submit_urb %p (write bulk) failed "
259 "(%d)", this_urb, err);
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700260 usb_unanchor_urb(this_urb);
Matthew Garrett0d456192010-04-01 12:31:07 -0400261 clear_bit(i, &portdata->out_busy);
262 spin_lock_irqsave(&intfdata->susp_lock, flags);
263 intfdata->in_flight--;
264 spin_unlock_irqrestore(&intfdata->susp_lock,
265 flags);
Oliver Neukum3d06bf12011-02-10 15:33:17 +0100266 usb_autopm_put_interface_async(port->serial->interface);
Oliver Neukum433508a2011-02-10 15:33:23 +0100267 break;
Matthew Garrett0d456192010-04-01 12:31:07 -0400268 }
269 }
270
271 portdata->tx_start_time[i] = jiffies;
272 buf += todo;
273 left -= todo;
274 }
275
276 count -= left;
277 dbg("%s: wrote (did %d)", __func__, count);
278 return count;
279}
280EXPORT_SYMBOL(usb_wwan_write);
281
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700282static void usb_wwan_in_work(struct work_struct *w)
283{
284 struct usb_wwan_port_private *portdata =
285 container_of(w, struct usb_wwan_port_private, in_work);
286 struct list_head *q = &portdata->in_urb_list;
287 struct urb *urb;
288 unsigned char *data;
289 struct tty_struct *tty;
290 struct usb_serial_port *port;
291 int err;
292 ssize_t len;
293 ssize_t count;
294 unsigned long flags;
295
296 spin_lock_irqsave(&portdata->in_lock, flags);
297 while (!list_empty(q)) {
298 urb = list_first_entry(q, struct urb, urb_list);
299 port = urb->context;
300 if (port->throttle_req || port->throttled)
301 break;
302
303 tty = tty_port_tty_get(&port->port);
304 if (!tty)
305 continue;
306
307 list_del_init(&urb->urb_list);
308
309 spin_unlock_irqrestore(&portdata->in_lock, flags);
310
311 len = urb->actual_length - portdata->n_read;
312 data = urb->transfer_buffer + portdata->n_read;
313 count = tty_insert_flip_string(tty, data, len);
314 tty_flip_buffer_push(tty);
315 tty_kref_put(tty);
316
317 if (count < len) {
318 dbg("%s: len:%d count:%d n_read:%d\n", __func__,
319 len, count, portdata->n_read);
320 portdata->n_read += count;
321 port->throttled = true;
322
323 /* add request back to list */
324 spin_lock_irqsave(&portdata->in_lock, flags);
325 list_add(&urb->urb_list, q);
326 spin_unlock_irqrestore(&portdata->in_lock, flags);
327 return;
328 }
329 portdata->n_read = 0;
330
331 usb_anchor_urb(urb, &portdata->submitted);
332 err = usb_submit_urb(urb, GFP_ATOMIC);
333 if (err) {
334 usb_unanchor_urb(urb);
335 if (err != -EPERM)
336 pr_err("%s: submit read urb failed:%d",
337 __func__, err);
338 }
339
340 usb_mark_last_busy(port->serial->dev);
341 spin_lock_irqsave(&portdata->in_lock, flags);
342 }
343 spin_unlock_irqrestore(&portdata->in_lock, flags);
344}
345
Matthew Garrett0d456192010-04-01 12:31:07 -0400346static void usb_wwan_indat_callback(struct urb *urb)
347{
348 int err;
349 int endpoint;
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700350 struct usb_wwan_port_private *portdata;
Matthew Garrett0d456192010-04-01 12:31:07 -0400351 struct usb_serial_port *port;
Matthew Garrett0d456192010-04-01 12:31:07 -0400352 int status = urb->status;
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700353 unsigned long flags;
Matthew Garrett0d456192010-04-01 12:31:07 -0400354
355 dbg("%s: %p", __func__, urb);
356
357 endpoint = usb_pipeendpoint(urb->pipe);
358 port = urb->context;
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700359 portdata = usb_get_serial_port_data(port);
Matthew Garrett0d456192010-04-01 12:31:07 -0400360
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700361 usb_mark_last_busy(port->serial->dev);
Matthew Garrett0d456192010-04-01 12:31:07 -0400362
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700363 if (!status && urb->actual_length) {
364 spin_lock_irqsave(&portdata->in_lock, flags);
365 list_add_tail(&urb->urb_list, &portdata->in_urb_list);
366 spin_unlock_irqrestore(&portdata->in_lock, flags);
Matthew Garrett0d456192010-04-01 12:31:07 -0400367
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700368 schedule_work(&portdata->in_work);
369
370 return;
371 }
372
373 dbg("%s: nonzero status: %d on endpoint %02x.",
374 __func__, status, endpoint);
375
376 if (status != -ESHUTDOWN) {
377 usb_anchor_urb(urb, &portdata->submitted);
378 err = usb_submit_urb(urb, GFP_ATOMIC);
379 if (err) {
380 usb_unanchor_urb(urb);
381 if (err != -EPERM)
382 pr_err("%s: submit read urb failed:%d",
383 __func__, err);
384 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400385 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400386}
387
388static void usb_wwan_outdat_callback(struct urb *urb)
389{
390 struct usb_serial_port *port;
391 struct usb_wwan_port_private *portdata;
392 struct usb_wwan_intf_private *intfdata;
393 int i;
394
395 dbg("%s", __func__);
396
397 port = urb->context;
398 intfdata = port->serial->private;
399
400 usb_serial_port_softint(port);
401 usb_autopm_put_interface_async(port->serial->interface);
402 portdata = usb_get_serial_port_data(port);
403 spin_lock(&intfdata->susp_lock);
404 intfdata->in_flight--;
405 spin_unlock(&intfdata->susp_lock);
406
407 for (i = 0; i < N_OUT_URB; ++i) {
408 if (portdata->out_urbs[i] == urb) {
409 smp_mb__before_clear_bit();
410 clear_bit(i, &portdata->out_busy);
411 break;
412 }
413 }
414}
415
416int usb_wwan_write_room(struct tty_struct *tty)
417{
418 struct usb_serial_port *port = tty->driver_data;
419 struct usb_wwan_port_private *portdata;
420 int i;
421 int data_len = 0;
422 struct urb *this_urb;
423
424 portdata = usb_get_serial_port_data(port);
425
426 for (i = 0; i < N_OUT_URB; i++) {
427 this_urb = portdata->out_urbs[i];
428 if (this_urb && !test_bit(i, &portdata->out_busy))
429 data_len += OUT_BUFLEN;
430 }
431
432 dbg("%s: %d", __func__, data_len);
433 return data_len;
434}
435EXPORT_SYMBOL(usb_wwan_write_room);
436
437int usb_wwan_chars_in_buffer(struct tty_struct *tty)
438{
439 struct usb_serial_port *port = tty->driver_data;
440 struct usb_wwan_port_private *portdata;
441 int i;
442 int data_len = 0;
443 struct urb *this_urb;
444
445 portdata = usb_get_serial_port_data(port);
446
447 for (i = 0; i < N_OUT_URB; i++) {
448 this_urb = portdata->out_urbs[i];
449 /* FIXME: This locking is insufficient as this_urb may
450 go unused during the test */
451 if (this_urb && test_bit(i, &portdata->out_busy))
452 data_len += this_urb->transfer_buffer_length;
453 }
454 dbg("%s: %d", __func__, data_len);
455 return data_len;
456}
457EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
458
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700459void usb_wwan_throttle(struct tty_struct *tty)
460{
461 struct usb_serial_port *port = tty->driver_data;
462
463 port->throttle_req = true;
464
465 dbg("%s:\n", __func__);
466}
467EXPORT_SYMBOL(usb_wwan_throttle);
468
469void usb_wwan_unthrottle(struct tty_struct *tty)
470{
471 struct usb_serial_port *port = tty->driver_data;
472 struct usb_wwan_port_private *portdata;
473
474 portdata = usb_get_serial_port_data(port);
475
476 dbg("%s:\n", __func__);
477 port->throttle_req = false;
478 port->throttled = false;
479
480 schedule_work(&portdata->in_work);
481}
482EXPORT_SYMBOL(usb_wwan_unthrottle);
483
Matthew Garrett0d456192010-04-01 12:31:07 -0400484int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
485{
486 struct usb_wwan_port_private *portdata;
487 struct usb_wwan_intf_private *intfdata;
488 struct usb_serial *serial = port->serial;
489 int i, err;
490 struct urb *urb;
491
492 portdata = usb_get_serial_port_data(port);
493 intfdata = serial->private;
494
Vamsi Krishna68194482011-12-12 18:28:48 -0800495 /* explicitly set the driver mode to raw */
Vamsi Krishnac502ecc2012-01-03 15:44:00 -0800496 tty->raw = 1;
497 tty->real_raw = 1;
Vamsi Krishna68194482011-12-12 18:28:48 -0800498
Vamsi Krishna6ef832f2012-01-27 16:29:21 -0800499 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
Matthew Garrett0d456192010-04-01 12:31:07 -0400500 dbg("%s", __func__);
501
502 /* Start reading from the IN endpoint */
503 for (i = 0; i < N_IN_URB; i++) {
504 urb = portdata->in_urbs[i];
505 if (!urb)
506 continue;
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700507 usb_anchor_urb(urb, &portdata->submitted);
Matthew Garrett0d456192010-04-01 12:31:07 -0400508 err = usb_submit_urb(urb, GFP_KERNEL);
509 if (err) {
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700510 usb_unanchor_urb(urb);
Matthew Garrett0d456192010-04-01 12:31:07 -0400511 dbg("%s: submit urb %d failed (%d) %d",
512 __func__, i, err, urb->transfer_buffer_length);
513 }
514 }
515
516 if (intfdata->send_setup)
517 intfdata->send_setup(port);
518
519 serial->interface->needs_remote_wakeup = 1;
520 spin_lock_irq(&intfdata->susp_lock);
521 portdata->opened = 1;
522 spin_unlock_irq(&intfdata->susp_lock);
Oliver Neukum9a91aed2011-02-10 15:33:37 +0100523 /* this balances a get in the generic USB serial code */
Matthew Garrett0d456192010-04-01 12:31:07 -0400524 usb_autopm_put_interface(serial->interface);
525
526 return 0;
527}
528EXPORT_SYMBOL(usb_wwan_open);
529
530void usb_wwan_close(struct usb_serial_port *port)
531{
532 int i;
533 struct usb_serial *serial = port->serial;
534 struct usb_wwan_port_private *portdata;
535 struct usb_wwan_intf_private *intfdata = port->serial->private;
536
537 dbg("%s", __func__);
538 portdata = usb_get_serial_port_data(port);
539
540 if (serial->dev) {
541 /* Stop reading/writing urbs */
542 spin_lock_irq(&intfdata->susp_lock);
543 portdata->opened = 0;
544 spin_unlock_irq(&intfdata->susp_lock);
545
546 for (i = 0; i < N_IN_URB; i++)
547 usb_kill_urb(portdata->in_urbs[i]);
548 for (i = 0; i < N_OUT_URB; i++)
549 usb_kill_urb(portdata->out_urbs[i]);
Oliver Neukum9a91aed2011-02-10 15:33:37 +0100550 /* balancing - important as an error cannot be handled*/
551 usb_autopm_get_interface_no_resume(serial->interface);
Matthew Garrett0d456192010-04-01 12:31:07 -0400552 serial->interface->needs_remote_wakeup = 0;
553 }
554}
555EXPORT_SYMBOL(usb_wwan_close);
556
557/* Helper functions used by usb_wwan_setup_urbs */
558static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
559 int dir, void *ctx, char *buf, int len,
560 void (*callback) (struct urb *))
561{
562 struct urb *urb;
563
564 if (endpoint == -1)
565 return NULL; /* endpoint not needed */
566
567 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
568 if (urb == NULL) {
569 dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
570 return NULL;
571 }
572
573 /* Fill URB using supplied data. */
574 usb_fill_bulk_urb(urb, serial->dev,
575 usb_sndbulkpipe(serial->dev, endpoint) | dir,
576 buf, len, callback, ctx);
577
578 return urb;
579}
580
581/* Setup urbs */
582static void usb_wwan_setup_urbs(struct usb_serial *serial)
583{
584 int i, j;
585 struct usb_serial_port *port;
586 struct usb_wwan_port_private *portdata;
587
588 dbg("%s", __func__);
589
590 for (i = 0; i < serial->num_ports; i++) {
591 port = serial->port[i];
592 portdata = usb_get_serial_port_data(port);
593
594 /* Do indat endpoints first */
595 for (j = 0; j < N_IN_URB; ++j) {
596 portdata->in_urbs[j] = usb_wwan_setup_urb(serial,
597 port->
598 bulk_in_endpointAddress,
599 USB_DIR_IN,
600 port,
601 portdata->
602 in_buffer[j],
603 IN_BUFLEN,
604 usb_wwan_indat_callback);
605 }
606
607 /* outdat endpoints */
608 for (j = 0; j < N_OUT_URB; ++j) {
609 portdata->out_urbs[j] = usb_wwan_setup_urb(serial,
610 port->
611 bulk_out_endpointAddress,
612 USB_DIR_OUT,
613 port,
614 portdata->
615 out_buffer
616 [j],
617 OUT_BUFLEN,
618 usb_wwan_outdat_callback);
619 }
620 }
621}
622
623int usb_wwan_startup(struct usb_serial *serial)
624{
625 int i, j, err;
626 struct usb_serial_port *port;
627 struct usb_wwan_port_private *portdata;
628 u8 *buffer;
629
630 dbg("%s", __func__);
631
632 /* Now setup per port private data */
633 for (i = 0; i < serial->num_ports; i++) {
634 port = serial->port[i];
635 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
636 if (!portdata) {
637 dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.",
638 __func__, i);
639 return 1;
640 }
641 init_usb_anchor(&portdata->delayed);
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700642 init_usb_anchor(&portdata->submitted);
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700643 INIT_WORK(&portdata->in_work, usb_wwan_in_work);
644 INIT_LIST_HEAD(&portdata->in_urb_list);
645 spin_lock_init(&portdata->in_lock);
Matthew Garrett0d456192010-04-01 12:31:07 -0400646
647 for (j = 0; j < N_IN_URB; j++) {
Vamsi Krishna6ef832f2012-01-27 16:29:21 -0800648 buffer = kmalloc(IN_BUFLEN, GFP_KERNEL);
Matthew Garrett0d456192010-04-01 12:31:07 -0400649 if (!buffer)
650 goto bail_out_error;
651 portdata->in_buffer[j] = buffer;
652 }
653
654 for (j = 0; j < N_OUT_URB; j++) {
655 buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
656 if (!buffer)
657 goto bail_out_error2;
658 portdata->out_buffer[j] = buffer;
659 }
660
661 usb_set_serial_port_data(port, portdata);
662
663 if (!port->interrupt_in_urb)
664 continue;
665 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
666 if (err)
667 dbg("%s: submit irq_in urb failed %d", __func__, err);
668 }
669 usb_wwan_setup_urbs(serial);
670 return 0;
671
672bail_out_error2:
673 for (j = 0; j < N_OUT_URB; j++)
674 kfree(portdata->out_buffer[j]);
675bail_out_error:
676 for (j = 0; j < N_IN_URB; j++)
Vamsi Krishna6ef832f2012-01-27 16:29:21 -0800677 kfree(portdata->in_buffer[j]);
Matthew Garrett0d456192010-04-01 12:31:07 -0400678 kfree(portdata);
679 return 1;
680}
681EXPORT_SYMBOL(usb_wwan_startup);
682
683static void stop_read_write_urbs(struct usb_serial *serial)
684{
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700685 int i;
Matthew Garrett0d456192010-04-01 12:31:07 -0400686 struct usb_serial_port *port;
687 struct usb_wwan_port_private *portdata;
688
689 /* Stop reading/writing urbs */
690 for (i = 0; i < serial->num_ports; ++i) {
691 port = serial->port[i];
692 portdata = usb_get_serial_port_data(port);
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700693 usb_kill_anchored_urbs(&portdata->submitted);
Matthew Garrett0d456192010-04-01 12:31:07 -0400694 }
695}
696
697void usb_wwan_disconnect(struct usb_serial *serial)
698{
699 dbg("%s", __func__);
700
701 stop_read_write_urbs(serial);
702}
703EXPORT_SYMBOL(usb_wwan_disconnect);
704
705void usb_wwan_release(struct usb_serial *serial)
706{
707 int i, j;
708 struct usb_serial_port *port;
709 struct usb_wwan_port_private *portdata;
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700710 struct urb *urb;
711 struct list_head *q;
712 unsigned long flags;
Matthew Garrett0d456192010-04-01 12:31:07 -0400713
714 /* Now free them */
715 for (i = 0; i < serial->num_ports; ++i) {
716 port = serial->port[i];
717 portdata = usb_get_serial_port_data(port);
718
Vamsi Krishna6f806b82012-05-07 16:29:08 -0700719 cancel_work_sync(&portdata->in_work);
720 /* TBD: do we really need this */
721 spin_lock_irqsave(&portdata->in_lock, flags);
722 q = &portdata->in_urb_list;
723 while (!list_empty(q)) {
724 urb = list_first_entry(q, struct urb, urb_list);
725 list_del_init(&urb->urb_list);
726 }
727 spin_unlock_irqrestore(&portdata->in_lock, flags);
728
Matthew Garrett0d456192010-04-01 12:31:07 -0400729 for (j = 0; j < N_IN_URB; j++) {
730 usb_free_urb(portdata->in_urbs[j]);
Vamsi Krishna6ef832f2012-01-27 16:29:21 -0800731 kfree(portdata->in_buffer[j]);
Matthew Garrett0d456192010-04-01 12:31:07 -0400732 portdata->in_urbs[j] = NULL;
733 }
734 for (j = 0; j < N_OUT_URB; j++) {
735 usb_free_urb(portdata->out_urbs[j]);
736 kfree(portdata->out_buffer[j]);
737 portdata->out_urbs[j] = NULL;
738 }
739 }
740
741 /* Now free per port private data */
742 for (i = 0; i < serial->num_ports; i++) {
743 port = serial->port[i];
744 kfree(usb_get_serial_port_data(port));
745 }
746}
747EXPORT_SYMBOL(usb_wwan_release);
748
749#ifdef CONFIG_PM
750int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
751{
752 struct usb_wwan_intf_private *intfdata = serial->private;
753 int b;
754
755 dbg("%s entered", __func__);
756
Alan Stern5b1b0b82011-08-19 23:49:48 +0200757 if (PMSG_IS_AUTO(message)) {
Matthew Garrett0d456192010-04-01 12:31:07 -0400758 spin_lock_irq(&intfdata->susp_lock);
759 b = intfdata->in_flight;
760 spin_unlock_irq(&intfdata->susp_lock);
761
762 if (b)
763 return -EBUSY;
764 }
765
766 spin_lock_irq(&intfdata->susp_lock);
767 intfdata->suspended = 1;
768 spin_unlock_irq(&intfdata->susp_lock);
769 stop_read_write_urbs(serial);
770
771 return 0;
772}
773EXPORT_SYMBOL(usb_wwan_suspend);
774
Oliver Neukum16871dc2011-02-10 15:33:29 +0100775static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
776{
777 int i;
778
779 for (i = 0; i < N_OUT_URB; i++) {
780 if (urb == portdata->out_urbs[i]) {
781 clear_bit(i, &portdata->out_busy);
782 break;
783 }
784 }
785}
786
Matthew Garrett0d456192010-04-01 12:31:07 -0400787static void play_delayed(struct usb_serial_port *port)
788{
789 struct usb_wwan_intf_private *data;
790 struct usb_wwan_port_private *portdata;
791 struct urb *urb;
792 int err;
793
794 portdata = usb_get_serial_port_data(port);
795 data = port->serial->private;
796 while ((urb = usb_get_from_anchor(&portdata->delayed))) {
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700797 usb_anchor_urb(urb, &portdata->submitted);
Matthew Garrett0d456192010-04-01 12:31:07 -0400798 err = usb_submit_urb(urb, GFP_ATOMIC);
Oliver Neukum16871dc2011-02-10 15:33:29 +0100799 if (!err) {
Matthew Garrett0d456192010-04-01 12:31:07 -0400800 data->in_flight++;
Oliver Neukum16871dc2011-02-10 15:33:29 +0100801 } else {
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700802 usb_unanchor_urb(urb);
Oliver Neukum16871dc2011-02-10 15:33:29 +0100803 /* we have to throw away the rest */
804 do {
805 unbusy_queued_urb(urb, portdata);
Oliver Neukum97ac01d2011-03-18 12:44:17 +0100806 usb_autopm_put_interface_no_suspend(port->serial->interface);
Oliver Neukum16871dc2011-02-10 15:33:29 +0100807 } while ((urb = usb_get_from_anchor(&portdata->delayed)));
808 break;
809 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400810 }
811}
812
813int usb_wwan_resume(struct usb_serial *serial)
814{
815 int i, j;
816 struct usb_serial_port *port;
817 struct usb_wwan_intf_private *intfdata = serial->private;
818 struct usb_wwan_port_private *portdata;
819 struct urb *urb;
820 int err = 0;
821
822 dbg("%s entered", __func__);
823 /* get the interrupt URBs resubmitted unconditionally */
824 for (i = 0; i < serial->num_ports; i++) {
825 port = serial->port[i];
826 if (!port->interrupt_in_urb) {
827 dbg("%s: No interrupt URB for port %d", __func__, i);
828 continue;
829 }
830 err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
831 dbg("Submitted interrupt URB for port %d (result %d)", i, err);
832 if (err < 0) {
833 err("%s: Error %d for interrupt URB of port%d",
834 __func__, err, i);
835 goto err_out;
836 }
837 }
838
Hemant Kumar8e52b122012-05-15 12:18:12 -0700839 spin_lock_irq(&intfdata->susp_lock);
840 intfdata->suspended = 0;
Matthew Garrett0d456192010-04-01 12:31:07 -0400841 for (i = 0; i < serial->num_ports; i++) {
842 /* walk all ports */
843 port = serial->port[i];
844 portdata = usb_get_serial_port_data(port);
845
846 /* skip closed ports */
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700847 if (!portdata->opened)
Matthew Garrett0d456192010-04-01 12:31:07 -0400848 continue;
Matthew Garrett0d456192010-04-01 12:31:07 -0400849
850 for (j = 0; j < N_IN_URB; j++) {
851 urb = portdata->in_urbs[j];
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700852 usb_anchor_urb(urb, &portdata->submitted);
Matthew Garrett0d456192010-04-01 12:31:07 -0400853 err = usb_submit_urb(urb, GFP_ATOMIC);
854 if (err < 0) {
855 err("%s: Error %d for bulk URB %d",
856 __func__, err, i);
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700857 usb_unanchor_urb(urb);
858 intfdata->suspended = 1;
Matthew Garrett0d456192010-04-01 12:31:07 -0400859 spin_unlock_irq(&intfdata->susp_lock);
860 goto err_out;
861 }
862 }
863 play_delayed(port);
Matthew Garrett0d456192010-04-01 12:31:07 -0400864 }
Hemant Kumar1ffb0392012-06-14 16:00:24 -0700865 spin_unlock_irq(&intfdata->susp_lock);
866
Matthew Garrett0d456192010-04-01 12:31:07 -0400867err_out:
868 return err;
869}
870EXPORT_SYMBOL(usb_wwan_resume);
871#endif
872
873MODULE_AUTHOR(DRIVER_AUTHOR);
874MODULE_DESCRIPTION(DRIVER_DESC);
875MODULE_VERSION(DRIVER_VERSION);
876MODULE_LICENSE("GPL");
877
878module_param(debug, bool, S_IRUGO | S_IWUSR);
879MODULE_PARM_DESC(debug, "Debug messages");