blob: 0a04a8fceaee7f122010af833da68060845ac0f1 [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{
Matthew Garrett0d456192010-04-01 12:31:07 -040044 struct usb_wwan_port_private *portdata;
45
46 struct usb_wwan_intf_private *intfdata;
47
48 dbg("%s", __func__);
49
50 intfdata = port->serial->private;
51
52 if (!intfdata->send_setup)
53 return;
54
55 portdata = usb_get_serial_port_data(port);
Johan Hovold906c9c42013-02-13 17:53:28 +010056 /* FIXME: locking */
Matthew Garrett0d456192010-04-01 12:31:07 -040057 portdata->rts_state = on;
58 portdata->dtr_state = on;
Johan Hovold906c9c42013-02-13 17:53:28 +010059
60 intfdata->send_setup(port);
Matthew Garrett0d456192010-04-01 12:31:07 -040061}
62EXPORT_SYMBOL(usb_wwan_dtr_rts);
63
64void usb_wwan_set_termios(struct tty_struct *tty,
65 struct usb_serial_port *port,
66 struct ktermios *old_termios)
67{
68 struct usb_wwan_intf_private *intfdata = port->serial->private;
69
70 dbg("%s", __func__);
71
72 /* Doesn't support option setting */
73 tty_termios_copy_hw(tty->termios, old_termios);
74
75 if (intfdata->send_setup)
76 intfdata->send_setup(port);
77}
78EXPORT_SYMBOL(usb_wwan_set_termios);
79
Alan Cox60b33c12011-02-14 16:26:14 +000080int usb_wwan_tiocmget(struct tty_struct *tty)
Matthew Garrett0d456192010-04-01 12:31:07 -040081{
82 struct usb_serial_port *port = tty->driver_data;
83 unsigned int value;
84 struct usb_wwan_port_private *portdata;
85
86 portdata = usb_get_serial_port_data(port);
87
88 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
89 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
90 ((portdata->cts_state) ? TIOCM_CTS : 0) |
91 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
92 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
93 ((portdata->ri_state) ? TIOCM_RNG : 0);
94
95 return value;
96}
97EXPORT_SYMBOL(usb_wwan_tiocmget);
98
Alan Cox20b9d172011-02-14 16:26:50 +000099int usb_wwan_tiocmset(struct tty_struct *tty,
Matthew Garrett0d456192010-04-01 12:31:07 -0400100 unsigned int set, unsigned int clear)
101{
102 struct usb_serial_port *port = tty->driver_data;
103 struct usb_wwan_port_private *portdata;
104 struct usb_wwan_intf_private *intfdata;
105
106 portdata = usb_get_serial_port_data(port);
107 intfdata = port->serial->private;
108
109 if (!intfdata->send_setup)
110 return -EINVAL;
111
112 /* FIXME: what locks portdata fields ? */
113 if (set & TIOCM_RTS)
114 portdata->rts_state = 1;
115 if (set & TIOCM_DTR)
116 portdata->dtr_state = 1;
117
118 if (clear & TIOCM_RTS)
119 portdata->rts_state = 0;
120 if (clear & TIOCM_DTR)
121 portdata->dtr_state = 0;
122 return intfdata->send_setup(port);
123}
124EXPORT_SYMBOL(usb_wwan_tiocmset);
125
Dan Williams02303f72010-11-19 16:04:00 -0600126static int get_serial_info(struct usb_serial_port *port,
127 struct serial_struct __user *retinfo)
128{
129 struct serial_struct tmp;
130
131 if (!retinfo)
132 return -EFAULT;
133
134 memset(&tmp, 0, sizeof(tmp));
135 tmp.line = port->serial->minor;
136 tmp.port = port->number;
137 tmp.baud_base = tty_get_baud_rate(port->port.tty);
138 tmp.close_delay = port->port.close_delay / 10;
139 tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
140 ASYNC_CLOSING_WAIT_NONE :
141 port->port.closing_wait / 10;
142
143 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
144 return -EFAULT;
145 return 0;
146}
147
148static int set_serial_info(struct usb_serial_port *port,
149 struct serial_struct __user *newinfo)
150{
151 struct serial_struct new_serial;
152 unsigned int closing_wait, close_delay;
153 int retval = 0;
154
155 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
156 return -EFAULT;
157
158 close_delay = new_serial.close_delay * 10;
159 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
160 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
161
162 mutex_lock(&port->port.mutex);
163
164 if (!capable(CAP_SYS_ADMIN)) {
165 if ((close_delay != port->port.close_delay) ||
166 (closing_wait != port->port.closing_wait))
167 retval = -EPERM;
168 else
169 retval = -EOPNOTSUPP;
170 } else {
171 port->port.close_delay = close_delay;
172 port->port.closing_wait = closing_wait;
173 }
174
175 mutex_unlock(&port->port.mutex);
176 return retval;
177}
178
Alan Cox00a0d0d2011-02-14 16:27:06 +0000179int usb_wwan_ioctl(struct tty_struct *tty,
Dan Williams02303f72010-11-19 16:04:00 -0600180 unsigned int cmd, unsigned long arg)
181{
182 struct usb_serial_port *port = tty->driver_data;
183
184 dbg("%s cmd 0x%04x", __func__, cmd);
185
186 switch (cmd) {
187 case TIOCGSERIAL:
188 return get_serial_info(port,
189 (struct serial_struct __user *) arg);
190 case TIOCSSERIAL:
191 return set_serial_info(port,
192 (struct serial_struct __user *) arg);
193 default:
194 break;
195 }
196
197 dbg("%s arg not supported", __func__);
198
199 return -ENOIOCTLCMD;
200}
201EXPORT_SYMBOL(usb_wwan_ioctl);
202
Matthew Garrett0d456192010-04-01 12:31:07 -0400203/* Write */
204int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
205 const unsigned char *buf, int count)
206{
207 struct usb_wwan_port_private *portdata;
208 struct usb_wwan_intf_private *intfdata;
209 int i;
210 int left, todo;
211 struct urb *this_urb = NULL; /* spurious */
212 int err;
213 unsigned long flags;
214
215 portdata = usb_get_serial_port_data(port);
216 intfdata = port->serial->private;
217
218 dbg("%s: write (%d chars)", __func__, count);
219
220 i = 0;
221 left = count;
222 for (i = 0; left > 0 && i < N_OUT_URB; i++) {
223 todo = left;
224 if (todo > OUT_BUFLEN)
225 todo = OUT_BUFLEN;
226
227 this_urb = portdata->out_urbs[i];
228 if (test_and_set_bit(i, &portdata->out_busy)) {
229 if (time_before(jiffies,
230 portdata->tx_start_time[i] + 10 * HZ))
231 continue;
232 usb_unlink_urb(this_urb);
233 continue;
234 }
235 dbg("%s: endpoint %d buf %d", __func__,
236 usb_pipeendpoint(this_urb->pipe), i);
237
238 err = usb_autopm_get_interface_async(port->serial->interface);
xiao jin640768a2014-05-26 19:23:13 +0200239 if (err < 0) {
240 clear_bit(i, &portdata->out_busy);
Matthew Garrett0d456192010-04-01 12:31:07 -0400241 break;
xiao jin640768a2014-05-26 19:23:13 +0200242 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400243
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);
255 err = usb_submit_urb(this_urb, GFP_ATOMIC);
256 if (err) {
257 dbg("usb_submit_urb %p (write bulk) failed "
258 "(%d)", this_urb, err);
259 clear_bit(i, &portdata->out_busy);
260 spin_lock_irqsave(&intfdata->susp_lock, flags);
261 intfdata->in_flight--;
262 spin_unlock_irqrestore(&intfdata->susp_lock,
263 flags);
Oliver Neukum3d06bf12011-02-10 15:33:17 +0100264 usb_autopm_put_interface_async(port->serial->interface);
Oliver Neukum433508a2011-02-10 15:33:23 +0100265 break;
Matthew Garrett0d456192010-04-01 12:31:07 -0400266 }
267 }
268
269 portdata->tx_start_time[i] = jiffies;
270 buf += todo;
271 left -= todo;
272 }
273
274 count -= left;
275 dbg("%s: wrote (did %d)", __func__, count);
276 return count;
277}
278EXPORT_SYMBOL(usb_wwan_write);
279
280static void usb_wwan_indat_callback(struct urb *urb)
281{
282 int err;
283 int endpoint;
284 struct usb_serial_port *port;
285 struct tty_struct *tty;
286 unsigned char *data = urb->transfer_buffer;
287 int status = urb->status;
288
289 dbg("%s: %p", __func__, urb);
290
291 endpoint = usb_pipeendpoint(urb->pipe);
292 port = urb->context;
293
294 if (status) {
295 dbg("%s: nonzero status: %d on endpoint %02x.",
296 __func__, status, endpoint);
297 } else {
298 tty = tty_port_tty_get(&port->port);
Jiri Slaby38237fd2011-02-15 15:55:07 +0100299 if (tty) {
300 if (urb->actual_length) {
301 tty_insert_flip_string(tty, data,
302 urb->actual_length);
303 tty_flip_buffer_push(tty);
304 } else
305 dbg("%s: empty read urb received", __func__);
306 tty_kref_put(tty);
307 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400308
309 /* Resubmit urb so we continue receiving */
310 if (status != -ESHUTDOWN) {
311 err = usb_submit_urb(urb, GFP_ATOMIC);
Oliver Neukumc9c45582011-02-10 15:33:10 +0100312 if (err) {
313 if (err != -EPERM) {
314 printk(KERN_ERR "%s: resubmit read urb failed. "
315 "(%d)", __func__, err);
316 /* busy also in error unless we are killed */
317 usb_mark_last_busy(port->serial->dev);
318 }
319 } else {
Matthew Garrett0d456192010-04-01 12:31:07 -0400320 usb_mark_last_busy(port->serial->dev);
Oliver Neukumc9c45582011-02-10 15:33:10 +0100321 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400322 }
323
324 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400325}
326
327static void usb_wwan_outdat_callback(struct urb *urb)
328{
329 struct usb_serial_port *port;
330 struct usb_wwan_port_private *portdata;
331 struct usb_wwan_intf_private *intfdata;
332 int i;
333
334 dbg("%s", __func__);
335
336 port = urb->context;
337 intfdata = port->serial->private;
338
339 usb_serial_port_softint(port);
340 usb_autopm_put_interface_async(port->serial->interface);
341 portdata = usb_get_serial_port_data(port);
342 spin_lock(&intfdata->susp_lock);
343 intfdata->in_flight--;
344 spin_unlock(&intfdata->susp_lock);
345
346 for (i = 0; i < N_OUT_URB; ++i) {
347 if (portdata->out_urbs[i] == urb) {
348 smp_mb__before_clear_bit();
349 clear_bit(i, &portdata->out_busy);
350 break;
351 }
352 }
353}
354
355int usb_wwan_write_room(struct tty_struct *tty)
356{
357 struct usb_serial_port *port = tty->driver_data;
358 struct usb_wwan_port_private *portdata;
359 int i;
360 int data_len = 0;
361 struct urb *this_urb;
362
363 portdata = usb_get_serial_port_data(port);
364
365 for (i = 0; i < N_OUT_URB; i++) {
366 this_urb = portdata->out_urbs[i];
367 if (this_urb && !test_bit(i, &portdata->out_busy))
368 data_len += OUT_BUFLEN;
369 }
370
371 dbg("%s: %d", __func__, data_len);
372 return data_len;
373}
374EXPORT_SYMBOL(usb_wwan_write_room);
375
376int usb_wwan_chars_in_buffer(struct tty_struct *tty)
377{
378 struct usb_serial_port *port = tty->driver_data;
379 struct usb_wwan_port_private *portdata;
380 int i;
381 int data_len = 0;
382 struct urb *this_urb;
383
384 portdata = usb_get_serial_port_data(port);
385
386 for (i = 0; i < N_OUT_URB; i++) {
387 this_urb = portdata->out_urbs[i];
388 /* FIXME: This locking is insufficient as this_urb may
389 go unused during the test */
390 if (this_urb && test_bit(i, &portdata->out_busy))
391 data_len += this_urb->transfer_buffer_length;
392 }
393 dbg("%s: %d", __func__, data_len);
394 return data_len;
395}
396EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
397
398int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
399{
400 struct usb_wwan_port_private *portdata;
401 struct usb_wwan_intf_private *intfdata;
402 struct usb_serial *serial = port->serial;
403 int i, err;
404 struct urb *urb;
405
406 portdata = usb_get_serial_port_data(port);
407 intfdata = serial->private;
408
409 dbg("%s", __func__);
410
411 /* Start reading from the IN endpoint */
412 for (i = 0; i < N_IN_URB; i++) {
413 urb = portdata->in_urbs[i];
414 if (!urb)
415 continue;
416 err = usb_submit_urb(urb, GFP_KERNEL);
417 if (err) {
418 dbg("%s: submit urb %d failed (%d) %d",
419 __func__, i, err, urb->transfer_buffer_length);
420 }
421 }
422
423 if (intfdata->send_setup)
424 intfdata->send_setup(port);
425
426 serial->interface->needs_remote_wakeup = 1;
427 spin_lock_irq(&intfdata->susp_lock);
428 portdata->opened = 1;
429 spin_unlock_irq(&intfdata->susp_lock);
Oliver Neukum9a91aed2011-02-10 15:33:37 +0100430 /* this balances a get in the generic USB serial code */
Matthew Garrett0d456192010-04-01 12:31:07 -0400431 usb_autopm_put_interface(serial->interface);
432
433 return 0;
434}
435EXPORT_SYMBOL(usb_wwan_open);
436
Johan Hovoldca913952014-05-26 19:23:16 +0200437static void unbusy_queued_urb(struct urb *urb,
438 struct usb_wwan_port_private *portdata)
439{
440 int i;
441
442 for (i = 0; i < N_OUT_URB; i++) {
443 if (urb == portdata->out_urbs[i]) {
444 clear_bit(i, &portdata->out_busy);
445 break;
446 }
447 }
448}
449
Matthew Garrett0d456192010-04-01 12:31:07 -0400450void usb_wwan_close(struct usb_serial_port *port)
451{
452 int i;
453 struct usb_serial *serial = port->serial;
454 struct usb_wwan_port_private *portdata;
455 struct usb_wwan_intf_private *intfdata = port->serial->private;
Johan Hovoldca913952014-05-26 19:23:16 +0200456 struct urb *urb;
Matthew Garrett0d456192010-04-01 12:31:07 -0400457
458 dbg("%s", __func__);
459 portdata = usb_get_serial_port_data(port);
460
461 if (serial->dev) {
462 /* Stop reading/writing urbs */
463 spin_lock_irq(&intfdata->susp_lock);
464 portdata->opened = 0;
465 spin_unlock_irq(&intfdata->susp_lock);
466
Johan Hovoldca913952014-05-26 19:23:16 +0200467 for (;;) {
468 urb = usb_get_from_anchor(&portdata->delayed);
469 if (!urb)
470 break;
471 unbusy_queued_urb(urb, portdata);
472 usb_autopm_put_interface_async(serial->interface);
473 }
474
Matthew Garrett0d456192010-04-01 12:31:07 -0400475 for (i = 0; i < N_IN_URB; i++)
476 usb_kill_urb(portdata->in_urbs[i]);
477 for (i = 0; i < N_OUT_URB; i++)
478 usb_kill_urb(portdata->out_urbs[i]);
Oliver Neukum9a91aed2011-02-10 15:33:37 +0100479 /* balancing - important as an error cannot be handled*/
480 usb_autopm_get_interface_no_resume(serial->interface);
Matthew Garrett0d456192010-04-01 12:31:07 -0400481 serial->interface->needs_remote_wakeup = 0;
482 }
483}
484EXPORT_SYMBOL(usb_wwan_close);
485
486/* Helper functions used by usb_wwan_setup_urbs */
487static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
488 int dir, void *ctx, char *buf, int len,
489 void (*callback) (struct urb *))
490{
491 struct urb *urb;
492
493 if (endpoint == -1)
494 return NULL; /* endpoint not needed */
495
496 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
497 if (urb == NULL) {
498 dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
499 return NULL;
500 }
501
502 /* Fill URB using supplied data. */
503 usb_fill_bulk_urb(urb, serial->dev,
504 usb_sndbulkpipe(serial->dev, endpoint) | dir,
505 buf, len, callback, ctx);
506
507 return urb;
508}
509
510/* Setup urbs */
511static void usb_wwan_setup_urbs(struct usb_serial *serial)
512{
513 int i, j;
514 struct usb_serial_port *port;
515 struct usb_wwan_port_private *portdata;
516
517 dbg("%s", __func__);
518
519 for (i = 0; i < serial->num_ports; i++) {
520 port = serial->port[i];
521 portdata = usb_get_serial_port_data(port);
522
523 /* Do indat endpoints first */
524 for (j = 0; j < N_IN_URB; ++j) {
525 portdata->in_urbs[j] = usb_wwan_setup_urb(serial,
526 port->
527 bulk_in_endpointAddress,
528 USB_DIR_IN,
529 port,
530 portdata->
531 in_buffer[j],
532 IN_BUFLEN,
533 usb_wwan_indat_callback);
534 }
535
536 /* outdat endpoints */
537 for (j = 0; j < N_OUT_URB; ++j) {
538 portdata->out_urbs[j] = usb_wwan_setup_urb(serial,
539 port->
540 bulk_out_endpointAddress,
541 USB_DIR_OUT,
542 port,
543 portdata->
544 out_buffer
545 [j],
546 OUT_BUFLEN,
547 usb_wwan_outdat_callback);
548 }
549 }
550}
551
552int usb_wwan_startup(struct usb_serial *serial)
553{
554 int i, j, err;
555 struct usb_serial_port *port;
556 struct usb_wwan_port_private *portdata;
557 u8 *buffer;
558
559 dbg("%s", __func__);
560
561 /* Now setup per port private data */
562 for (i = 0; i < serial->num_ports; i++) {
563 port = serial->port[i];
564 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
565 if (!portdata) {
566 dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.",
567 __func__, i);
568 return 1;
569 }
570 init_usb_anchor(&portdata->delayed);
571
572 for (j = 0; j < N_IN_URB; j++) {
573 buffer = (u8 *) __get_free_page(GFP_KERNEL);
574 if (!buffer)
575 goto bail_out_error;
576 portdata->in_buffer[j] = buffer;
577 }
578
579 for (j = 0; j < N_OUT_URB; j++) {
580 buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
581 if (!buffer)
582 goto bail_out_error2;
583 portdata->out_buffer[j] = buffer;
584 }
585
586 usb_set_serial_port_data(port, portdata);
587
588 if (!port->interrupt_in_urb)
589 continue;
590 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
591 if (err)
592 dbg("%s: submit irq_in urb failed %d", __func__, err);
593 }
594 usb_wwan_setup_urbs(serial);
595 return 0;
596
597bail_out_error2:
598 for (j = 0; j < N_OUT_URB; j++)
599 kfree(portdata->out_buffer[j]);
600bail_out_error:
601 for (j = 0; j < N_IN_URB; j++)
602 if (portdata->in_buffer[j])
603 free_page((unsigned long)portdata->in_buffer[j]);
604 kfree(portdata);
605 return 1;
606}
607EXPORT_SYMBOL(usb_wwan_startup);
608
609static void stop_read_write_urbs(struct usb_serial *serial)
610{
611 int i, j;
612 struct usb_serial_port *port;
613 struct usb_wwan_port_private *portdata;
614
615 /* Stop reading/writing urbs */
616 for (i = 0; i < serial->num_ports; ++i) {
617 port = serial->port[i];
618 portdata = usb_get_serial_port_data(port);
619 for (j = 0; j < N_IN_URB; j++)
620 usb_kill_urb(portdata->in_urbs[j]);
621 for (j = 0; j < N_OUT_URB; j++)
622 usb_kill_urb(portdata->out_urbs[j]);
623 }
624}
625
626void usb_wwan_disconnect(struct usb_serial *serial)
627{
628 dbg("%s", __func__);
629
630 stop_read_write_urbs(serial);
631}
632EXPORT_SYMBOL(usb_wwan_disconnect);
633
634void usb_wwan_release(struct usb_serial *serial)
635{
636 int i, j;
637 struct usb_serial_port *port;
638 struct usb_wwan_port_private *portdata;
639
640 dbg("%s", __func__);
641
642 /* Now free them */
643 for (i = 0; i < serial->num_ports; ++i) {
644 port = serial->port[i];
645 portdata = usb_get_serial_port_data(port);
646
647 for (j = 0; j < N_IN_URB; j++) {
648 usb_free_urb(portdata->in_urbs[j]);
649 free_page((unsigned long)
650 portdata->in_buffer[j]);
651 portdata->in_urbs[j] = NULL;
652 }
653 for (j = 0; j < N_OUT_URB; j++) {
654 usb_free_urb(portdata->out_urbs[j]);
655 kfree(portdata->out_buffer[j]);
656 portdata->out_urbs[j] = NULL;
657 }
658 }
659
660 /* Now free per port private data */
661 for (i = 0; i < serial->num_ports; i++) {
662 port = serial->port[i];
663 kfree(usb_get_serial_port_data(port));
664 }
665}
666EXPORT_SYMBOL(usb_wwan_release);
667
668#ifdef CONFIG_PM
669int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
670{
671 struct usb_wwan_intf_private *intfdata = serial->private;
Matthew Garrett0d456192010-04-01 12:31:07 -0400672
673 dbg("%s entered", __func__);
674
Johan Hovold887b3c32014-05-26 19:23:15 +0200675 spin_lock_irq(&intfdata->susp_lock);
Alan Stern5b1b0b82011-08-19 23:49:48 +0200676 if (PMSG_IS_AUTO(message)) {
Johan Hovold887b3c32014-05-26 19:23:15 +0200677 if (intfdata->in_flight) {
678 spin_unlock_irq(&intfdata->susp_lock);
Matthew Garrett0d456192010-04-01 12:31:07 -0400679 return -EBUSY;
Johan Hovold887b3c32014-05-26 19:23:15 +0200680 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400681 }
682
Matthew Garrett0d456192010-04-01 12:31:07 -0400683 intfdata->suspended = 1;
684 spin_unlock_irq(&intfdata->susp_lock);
Johan Hovold887b3c32014-05-26 19:23:15 +0200685
Matthew Garrett0d456192010-04-01 12:31:07 -0400686 stop_read_write_urbs(serial);
687
688 return 0;
689}
690EXPORT_SYMBOL(usb_wwan_suspend);
691
692static void play_delayed(struct usb_serial_port *port)
693{
694 struct usb_wwan_intf_private *data;
695 struct usb_wwan_port_private *portdata;
696 struct urb *urb;
697 int err;
698
699 portdata = usb_get_serial_port_data(port);
700 data = port->serial->private;
701 while ((urb = usb_get_from_anchor(&portdata->delayed))) {
702 err = usb_submit_urb(urb, GFP_ATOMIC);
Oliver Neukum16871dc2011-02-10 15:33:29 +0100703 if (!err) {
Matthew Garrett0d456192010-04-01 12:31:07 -0400704 data->in_flight++;
Oliver Neukum16871dc2011-02-10 15:33:29 +0100705 } else {
706 /* we have to throw away the rest */
707 do {
708 unbusy_queued_urb(urb, portdata);
Oliver Neukum97ac01d2011-03-18 12:44:17 +0100709 usb_autopm_put_interface_no_suspend(port->serial->interface);
Oliver Neukum16871dc2011-02-10 15:33:29 +0100710 } while ((urb = usb_get_from_anchor(&portdata->delayed)));
711 break;
712 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400713 }
714}
715
716int usb_wwan_resume(struct usb_serial *serial)
717{
718 int i, j;
719 struct usb_serial_port *port;
720 struct usb_wwan_intf_private *intfdata = serial->private;
721 struct usb_wwan_port_private *portdata;
722 struct urb *urb;
723 int err = 0;
724
725 dbg("%s entered", __func__);
726 /* get the interrupt URBs resubmitted unconditionally */
727 for (i = 0; i < serial->num_ports; i++) {
728 port = serial->port[i];
729 if (!port->interrupt_in_urb) {
730 dbg("%s: No interrupt URB for port %d", __func__, i);
731 continue;
732 }
733 err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
734 dbg("Submitted interrupt URB for port %d (result %d)", i, err);
735 if (err < 0) {
736 err("%s: Error %d for interrupt URB of port%d",
737 __func__, err, i);
738 goto err_out;
739 }
740 }
741
xiao jin50476ee2014-05-26 19:23:14 +0200742 spin_lock_irq(&intfdata->susp_lock);
Matthew Garrett0d456192010-04-01 12:31:07 -0400743 for (i = 0; i < serial->num_ports; i++) {
744 /* walk all ports */
745 port = serial->port[i];
746 portdata = usb_get_serial_port_data(port);
747
748 /* skip closed ports */
xiao jin50476ee2014-05-26 19:23:14 +0200749 if (!portdata || !portdata->opened)
Matthew Garrett0d456192010-04-01 12:31:07 -0400750 continue;
Matthew Garrett0d456192010-04-01 12:31:07 -0400751
752 for (j = 0; j < N_IN_URB; j++) {
753 urb = portdata->in_urbs[j];
754 err = usb_submit_urb(urb, GFP_ATOMIC);
755 if (err < 0) {
756 err("%s: Error %d for bulk URB %d",
757 __func__, err, i);
758 spin_unlock_irq(&intfdata->susp_lock);
759 goto err_out;
760 }
761 }
762 play_delayed(port);
Matthew Garrett0d456192010-04-01 12:31:07 -0400763 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400764 intfdata->suspended = 0;
765 spin_unlock_irq(&intfdata->susp_lock);
766err_out:
767 return err;
768}
769EXPORT_SYMBOL(usb_wwan_resume);
770#endif
771
772MODULE_AUTHOR(DRIVER_AUTHOR);
773MODULE_DESCRIPTION(DRIVER_DESC);
774MODULE_VERSION(DRIVER_VERSION);
775MODULE_LICENSE("GPL");
776
777module_param(debug, bool, S_IRUGO | S_IWUSR);
778MODULE_PARM_DESC(debug, "Debug messages");