blob: 660b7caef78429614baf723a3711160be7853cf2 [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>
34#include <linux/usb.h>
35#include <linux/usb/serial.h>
Dan Williams02303f72010-11-19 16:04:00 -060036#include <linux/serial.h>
Matthew Garrett0d456192010-04-01 12:31:07 -040037#include "usb-wwan.h"
38
39static int debug;
40
41void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
42{
43 struct usb_serial *serial = port->serial;
44 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);
56 mutex_lock(&serial->disc_mutex);
57 portdata->rts_state = on;
58 portdata->dtr_state = on;
59 if (serial->dev)
60 intfdata->send_setup(port);
61 mutex_unlock(&serial->disc_mutex);
62}
63EXPORT_SYMBOL(usb_wwan_dtr_rts);
64
65void usb_wwan_set_termios(struct tty_struct *tty,
66 struct usb_serial_port *port,
67 struct ktermios *old_termios)
68{
69 struct usb_wwan_intf_private *intfdata = port->serial->private;
70
71 dbg("%s", __func__);
72
73 /* Doesn't support option setting */
74 tty_termios_copy_hw(tty->termios, old_termios);
75
76 if (intfdata->send_setup)
77 intfdata->send_setup(port);
78}
79EXPORT_SYMBOL(usb_wwan_set_termios);
80
81int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file)
82{
83 struct usb_serial_port *port = tty->driver_data;
84 unsigned int value;
85 struct usb_wwan_port_private *portdata;
86
87 portdata = usb_get_serial_port_data(port);
88
89 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
90 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
91 ((portdata->cts_state) ? TIOCM_CTS : 0) |
92 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
93 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
94 ((portdata->ri_state) ? TIOCM_RNG : 0);
95
96 return value;
97}
98EXPORT_SYMBOL(usb_wwan_tiocmget);
99
100int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
101 unsigned int set, unsigned int clear)
102{
103 struct usb_serial_port *port = tty->driver_data;
104 struct usb_wwan_port_private *portdata;
105 struct usb_wwan_intf_private *intfdata;
106
107 portdata = usb_get_serial_port_data(port);
108 intfdata = port->serial->private;
109
110 if (!intfdata->send_setup)
111 return -EINVAL;
112
113 /* FIXME: what locks portdata fields ? */
114 if (set & TIOCM_RTS)
115 portdata->rts_state = 1;
116 if (set & TIOCM_DTR)
117 portdata->dtr_state = 1;
118
119 if (clear & TIOCM_RTS)
120 portdata->rts_state = 0;
121 if (clear & TIOCM_DTR)
122 portdata->dtr_state = 0;
123 return intfdata->send_setup(port);
124}
125EXPORT_SYMBOL(usb_wwan_tiocmset);
126
Dan Williams02303f72010-11-19 16:04:00 -0600127static int get_serial_info(struct usb_serial_port *port,
128 struct serial_struct __user *retinfo)
129{
130 struct serial_struct tmp;
131
132 if (!retinfo)
133 return -EFAULT;
134
135 memset(&tmp, 0, sizeof(tmp));
136 tmp.line = port->serial->minor;
137 tmp.port = port->number;
138 tmp.baud_base = tty_get_baud_rate(port->port.tty);
139 tmp.close_delay = port->port.close_delay / 10;
140 tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
141 ASYNC_CLOSING_WAIT_NONE :
142 port->port.closing_wait / 10;
143
144 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
145 return -EFAULT;
146 return 0;
147}
148
149static int set_serial_info(struct usb_serial_port *port,
150 struct serial_struct __user *newinfo)
151{
152 struct serial_struct new_serial;
153 unsigned int closing_wait, close_delay;
154 int retval = 0;
155
156 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
157 return -EFAULT;
158
159 close_delay = new_serial.close_delay * 10;
160 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
161 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
162
163 mutex_lock(&port->port.mutex);
164
165 if (!capable(CAP_SYS_ADMIN)) {
166 if ((close_delay != port->port.close_delay) ||
167 (closing_wait != port->port.closing_wait))
168 retval = -EPERM;
169 else
170 retval = -EOPNOTSUPP;
171 } else {
172 port->port.close_delay = close_delay;
173 port->port.closing_wait = closing_wait;
174 }
175
176 mutex_unlock(&port->port.mutex);
177 return retval;
178}
179
180int usb_wwan_ioctl(struct tty_struct *tty, struct file *file,
181 unsigned int cmd, unsigned long arg)
182{
183 struct usb_serial_port *port = tty->driver_data;
184
185 dbg("%s cmd 0x%04x", __func__, cmd);
186
187 switch (cmd) {
188 case TIOCGSERIAL:
189 return get_serial_info(port,
190 (struct serial_struct __user *) arg);
191 case TIOCSSERIAL:
192 return set_serial_info(port,
193 (struct serial_struct __user *) arg);
194 default:
195 break;
196 }
197
198 dbg("%s arg not supported", __func__);
199
200 return -ENOIOCTLCMD;
201}
202EXPORT_SYMBOL(usb_wwan_ioctl);
203
Matthew Garrett0d456192010-04-01 12:31:07 -0400204/* Write */
205int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
206 const unsigned char *buf, int count)
207{
208 struct usb_wwan_port_private *portdata;
209 struct usb_wwan_intf_private *intfdata;
210 int i;
211 int left, todo;
212 struct urb *this_urb = NULL; /* spurious */
213 int err;
214 unsigned long flags;
215
216 portdata = usb_get_serial_port_data(port);
217 intfdata = port->serial->private;
218
219 dbg("%s: write (%d chars)", __func__, count);
220
221 i = 0;
222 left = count;
223 for (i = 0; left > 0 && i < N_OUT_URB; i++) {
224 todo = left;
225 if (todo > OUT_BUFLEN)
226 todo = OUT_BUFLEN;
227
228 this_urb = portdata->out_urbs[i];
229 if (test_and_set_bit(i, &portdata->out_busy)) {
230 if (time_before(jiffies,
231 portdata->tx_start_time[i] + 10 * HZ))
232 continue;
233 usb_unlink_urb(this_urb);
234 continue;
235 }
236 dbg("%s: endpoint %d buf %d", __func__,
237 usb_pipeendpoint(this_urb->pipe), i);
238
239 err = usb_autopm_get_interface_async(port->serial->interface);
240 if (err < 0)
241 break;
242
243 /* send the data */
244 memcpy(this_urb->transfer_buffer, buf, todo);
245 this_urb->transfer_buffer_length = todo;
246
247 spin_lock_irqsave(&intfdata->susp_lock, flags);
248 if (intfdata->suspended) {
249 usb_anchor_urb(this_urb, &portdata->delayed);
250 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
251 } else {
252 intfdata->in_flight++;
253 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
254 err = usb_submit_urb(this_urb, GFP_ATOMIC);
255 if (err) {
256 dbg("usb_submit_urb %p (write bulk) failed "
257 "(%d)", this_urb, err);
258 clear_bit(i, &portdata->out_busy);
259 spin_lock_irqsave(&intfdata->susp_lock, flags);
260 intfdata->in_flight--;
261 spin_unlock_irqrestore(&intfdata->susp_lock,
262 flags);
263 continue;
264 }
265 }
266
267 portdata->tx_start_time[i] = jiffies;
268 buf += todo;
269 left -= todo;
270 }
271
272 count -= left;
273 dbg("%s: wrote (did %d)", __func__, count);
274 return count;
275}
276EXPORT_SYMBOL(usb_wwan_write);
277
278static void usb_wwan_indat_callback(struct urb *urb)
279{
280 int err;
281 int endpoint;
282 struct usb_serial_port *port;
283 struct tty_struct *tty;
284 unsigned char *data = urb->transfer_buffer;
285 int status = urb->status;
286
287 dbg("%s: %p", __func__, urb);
288
289 endpoint = usb_pipeendpoint(urb->pipe);
290 port = urb->context;
291
292 if (status) {
293 dbg("%s: nonzero status: %d on endpoint %02x.",
294 __func__, status, endpoint);
295 } else {
296 tty = tty_port_tty_get(&port->port);
297 if (urb->actual_length) {
298 tty_insert_flip_string(tty, data, urb->actual_length);
299 tty_flip_buffer_push(tty);
300 } else
301 dbg("%s: empty read urb received", __func__);
302 tty_kref_put(tty);
303
304 /* Resubmit urb so we continue receiving */
305 if (status != -ESHUTDOWN) {
306 err = usb_submit_urb(urb, GFP_ATOMIC);
307 if (err && err != -EPERM)
308 printk(KERN_ERR "%s: resubmit read urb failed. "
309 "(%d)", __func__, err);
310 else
311 usb_mark_last_busy(port->serial->dev);
312 }
313
314 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400315}
316
317static void usb_wwan_outdat_callback(struct urb *urb)
318{
319 struct usb_serial_port *port;
320 struct usb_wwan_port_private *portdata;
321 struct usb_wwan_intf_private *intfdata;
322 int i;
323
324 dbg("%s", __func__);
325
326 port = urb->context;
327 intfdata = port->serial->private;
328
329 usb_serial_port_softint(port);
330 usb_autopm_put_interface_async(port->serial->interface);
331 portdata = usb_get_serial_port_data(port);
332 spin_lock(&intfdata->susp_lock);
333 intfdata->in_flight--;
334 spin_unlock(&intfdata->susp_lock);
335
336 for (i = 0; i < N_OUT_URB; ++i) {
337 if (portdata->out_urbs[i] == urb) {
338 smp_mb__before_clear_bit();
339 clear_bit(i, &portdata->out_busy);
340 break;
341 }
342 }
343}
344
345int usb_wwan_write_room(struct tty_struct *tty)
346{
347 struct usb_serial_port *port = tty->driver_data;
348 struct usb_wwan_port_private *portdata;
349 int i;
350 int data_len = 0;
351 struct urb *this_urb;
352
353 portdata = usb_get_serial_port_data(port);
354
355 for (i = 0; i < N_OUT_URB; i++) {
356 this_urb = portdata->out_urbs[i];
357 if (this_urb && !test_bit(i, &portdata->out_busy))
358 data_len += OUT_BUFLEN;
359 }
360
361 dbg("%s: %d", __func__, data_len);
362 return data_len;
363}
364EXPORT_SYMBOL(usb_wwan_write_room);
365
366int usb_wwan_chars_in_buffer(struct tty_struct *tty)
367{
368 struct usb_serial_port *port = tty->driver_data;
369 struct usb_wwan_port_private *portdata;
370 int i;
371 int data_len = 0;
372 struct urb *this_urb;
373
374 portdata = usb_get_serial_port_data(port);
375
376 for (i = 0; i < N_OUT_URB; i++) {
377 this_urb = portdata->out_urbs[i];
378 /* FIXME: This locking is insufficient as this_urb may
379 go unused during the test */
380 if (this_urb && test_bit(i, &portdata->out_busy))
381 data_len += this_urb->transfer_buffer_length;
382 }
383 dbg("%s: %d", __func__, data_len);
384 return data_len;
385}
386EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
387
388int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
389{
390 struct usb_wwan_port_private *portdata;
391 struct usb_wwan_intf_private *intfdata;
392 struct usb_serial *serial = port->serial;
393 int i, err;
394 struct urb *urb;
395
396 portdata = usb_get_serial_port_data(port);
397 intfdata = serial->private;
398
399 dbg("%s", __func__);
400
401 /* Start reading from the IN endpoint */
402 for (i = 0; i < N_IN_URB; i++) {
403 urb = portdata->in_urbs[i];
404 if (!urb)
405 continue;
406 err = usb_submit_urb(urb, GFP_KERNEL);
407 if (err) {
408 dbg("%s: submit urb %d failed (%d) %d",
409 __func__, i, err, urb->transfer_buffer_length);
410 }
411 }
412
413 if (intfdata->send_setup)
414 intfdata->send_setup(port);
415
416 serial->interface->needs_remote_wakeup = 1;
417 spin_lock_irq(&intfdata->susp_lock);
418 portdata->opened = 1;
419 spin_unlock_irq(&intfdata->susp_lock);
420 usb_autopm_put_interface(serial->interface);
421
422 return 0;
423}
424EXPORT_SYMBOL(usb_wwan_open);
425
426void usb_wwan_close(struct usb_serial_port *port)
427{
428 int i;
429 struct usb_serial *serial = port->serial;
430 struct usb_wwan_port_private *portdata;
431 struct usb_wwan_intf_private *intfdata = port->serial->private;
432
433 dbg("%s", __func__);
434 portdata = usb_get_serial_port_data(port);
435
436 if (serial->dev) {
437 /* Stop reading/writing urbs */
438 spin_lock_irq(&intfdata->susp_lock);
439 portdata->opened = 0;
440 spin_unlock_irq(&intfdata->susp_lock);
441
442 for (i = 0; i < N_IN_URB; i++)
443 usb_kill_urb(portdata->in_urbs[i]);
444 for (i = 0; i < N_OUT_URB; i++)
445 usb_kill_urb(portdata->out_urbs[i]);
446 usb_autopm_get_interface(serial->interface);
447 serial->interface->needs_remote_wakeup = 0;
448 }
449}
450EXPORT_SYMBOL(usb_wwan_close);
451
452/* Helper functions used by usb_wwan_setup_urbs */
453static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
454 int dir, void *ctx, char *buf, int len,
455 void (*callback) (struct urb *))
456{
457 struct urb *urb;
458
459 if (endpoint == -1)
460 return NULL; /* endpoint not needed */
461
462 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
463 if (urb == NULL) {
464 dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
465 return NULL;
466 }
467
468 /* Fill URB using supplied data. */
469 usb_fill_bulk_urb(urb, serial->dev,
470 usb_sndbulkpipe(serial->dev, endpoint) | dir,
471 buf, len, callback, ctx);
472
473 return urb;
474}
475
476/* Setup urbs */
477static void usb_wwan_setup_urbs(struct usb_serial *serial)
478{
479 int i, j;
480 struct usb_serial_port *port;
481 struct usb_wwan_port_private *portdata;
482
483 dbg("%s", __func__);
484
485 for (i = 0; i < serial->num_ports; i++) {
486 port = serial->port[i];
487 portdata = usb_get_serial_port_data(port);
488
489 /* Do indat endpoints first */
490 for (j = 0; j < N_IN_URB; ++j) {
491 portdata->in_urbs[j] = usb_wwan_setup_urb(serial,
492 port->
493 bulk_in_endpointAddress,
494 USB_DIR_IN,
495 port,
496 portdata->
497 in_buffer[j],
498 IN_BUFLEN,
499 usb_wwan_indat_callback);
500 }
501
502 /* outdat endpoints */
503 for (j = 0; j < N_OUT_URB; ++j) {
504 portdata->out_urbs[j] = usb_wwan_setup_urb(serial,
505 port->
506 bulk_out_endpointAddress,
507 USB_DIR_OUT,
508 port,
509 portdata->
510 out_buffer
511 [j],
512 OUT_BUFLEN,
513 usb_wwan_outdat_callback);
514 }
515 }
516}
517
518int usb_wwan_startup(struct usb_serial *serial)
519{
520 int i, j, err;
521 struct usb_serial_port *port;
522 struct usb_wwan_port_private *portdata;
523 u8 *buffer;
524
525 dbg("%s", __func__);
526
527 /* Now setup per port private data */
528 for (i = 0; i < serial->num_ports; i++) {
529 port = serial->port[i];
530 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
531 if (!portdata) {
532 dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.",
533 __func__, i);
534 return 1;
535 }
536 init_usb_anchor(&portdata->delayed);
537
538 for (j = 0; j < N_IN_URB; j++) {
539 buffer = (u8 *) __get_free_page(GFP_KERNEL);
540 if (!buffer)
541 goto bail_out_error;
542 portdata->in_buffer[j] = buffer;
543 }
544
545 for (j = 0; j < N_OUT_URB; j++) {
546 buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
547 if (!buffer)
548 goto bail_out_error2;
549 portdata->out_buffer[j] = buffer;
550 }
551
552 usb_set_serial_port_data(port, portdata);
553
554 if (!port->interrupt_in_urb)
555 continue;
556 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
557 if (err)
558 dbg("%s: submit irq_in urb failed %d", __func__, err);
559 }
560 usb_wwan_setup_urbs(serial);
561 return 0;
562
563bail_out_error2:
564 for (j = 0; j < N_OUT_URB; j++)
565 kfree(portdata->out_buffer[j]);
566bail_out_error:
567 for (j = 0; j < N_IN_URB; j++)
568 if (portdata->in_buffer[j])
569 free_page((unsigned long)portdata->in_buffer[j]);
570 kfree(portdata);
571 return 1;
572}
573EXPORT_SYMBOL(usb_wwan_startup);
574
575static void stop_read_write_urbs(struct usb_serial *serial)
576{
577 int i, j;
578 struct usb_serial_port *port;
579 struct usb_wwan_port_private *portdata;
580
581 /* Stop reading/writing urbs */
582 for (i = 0; i < serial->num_ports; ++i) {
583 port = serial->port[i];
584 portdata = usb_get_serial_port_data(port);
585 for (j = 0; j < N_IN_URB; j++)
586 usb_kill_urb(portdata->in_urbs[j]);
587 for (j = 0; j < N_OUT_URB; j++)
588 usb_kill_urb(portdata->out_urbs[j]);
589 }
590}
591
592void usb_wwan_disconnect(struct usb_serial *serial)
593{
594 dbg("%s", __func__);
595
596 stop_read_write_urbs(serial);
597}
598EXPORT_SYMBOL(usb_wwan_disconnect);
599
600void usb_wwan_release(struct usb_serial *serial)
601{
602 int i, j;
603 struct usb_serial_port *port;
604 struct usb_wwan_port_private *portdata;
605
606 dbg("%s", __func__);
607
608 /* Now free them */
609 for (i = 0; i < serial->num_ports; ++i) {
610 port = serial->port[i];
611 portdata = usb_get_serial_port_data(port);
612
613 for (j = 0; j < N_IN_URB; j++) {
614 usb_free_urb(portdata->in_urbs[j]);
615 free_page((unsigned long)
616 portdata->in_buffer[j]);
617 portdata->in_urbs[j] = NULL;
618 }
619 for (j = 0; j < N_OUT_URB; j++) {
620 usb_free_urb(portdata->out_urbs[j]);
621 kfree(portdata->out_buffer[j]);
622 portdata->out_urbs[j] = NULL;
623 }
624 }
625
626 /* Now free per port private data */
627 for (i = 0; i < serial->num_ports; i++) {
628 port = serial->port[i];
629 kfree(usb_get_serial_port_data(port));
630 }
631}
632EXPORT_SYMBOL(usb_wwan_release);
633
634#ifdef CONFIG_PM
635int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
636{
637 struct usb_wwan_intf_private *intfdata = serial->private;
638 int b;
639
640 dbg("%s entered", __func__);
641
642 if (message.event & PM_EVENT_AUTO) {
643 spin_lock_irq(&intfdata->susp_lock);
644 b = intfdata->in_flight;
645 spin_unlock_irq(&intfdata->susp_lock);
646
647 if (b)
648 return -EBUSY;
649 }
650
651 spin_lock_irq(&intfdata->susp_lock);
652 intfdata->suspended = 1;
653 spin_unlock_irq(&intfdata->susp_lock);
654 stop_read_write_urbs(serial);
655
656 return 0;
657}
658EXPORT_SYMBOL(usb_wwan_suspend);
659
660static void play_delayed(struct usb_serial_port *port)
661{
662 struct usb_wwan_intf_private *data;
663 struct usb_wwan_port_private *portdata;
664 struct urb *urb;
665 int err;
666
667 portdata = usb_get_serial_port_data(port);
668 data = port->serial->private;
669 while ((urb = usb_get_from_anchor(&portdata->delayed))) {
670 err = usb_submit_urb(urb, GFP_ATOMIC);
671 if (!err)
672 data->in_flight++;
673 }
674}
675
676int usb_wwan_resume(struct usb_serial *serial)
677{
678 int i, j;
679 struct usb_serial_port *port;
680 struct usb_wwan_intf_private *intfdata = serial->private;
681 struct usb_wwan_port_private *portdata;
682 struct urb *urb;
683 int err = 0;
684
685 dbg("%s entered", __func__);
686 /* get the interrupt URBs resubmitted unconditionally */
687 for (i = 0; i < serial->num_ports; i++) {
688 port = serial->port[i];
689 if (!port->interrupt_in_urb) {
690 dbg("%s: No interrupt URB for port %d", __func__, i);
691 continue;
692 }
693 err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
694 dbg("Submitted interrupt URB for port %d (result %d)", i, err);
695 if (err < 0) {
696 err("%s: Error %d for interrupt URB of port%d",
697 __func__, err, i);
698 goto err_out;
699 }
700 }
701
702 for (i = 0; i < serial->num_ports; i++) {
703 /* walk all ports */
704 port = serial->port[i];
705 portdata = usb_get_serial_port_data(port);
706
707 /* skip closed ports */
708 spin_lock_irq(&intfdata->susp_lock);
709 if (!portdata->opened) {
710 spin_unlock_irq(&intfdata->susp_lock);
711 continue;
712 }
713
714 for (j = 0; j < N_IN_URB; j++) {
715 urb = portdata->in_urbs[j];
716 err = usb_submit_urb(urb, GFP_ATOMIC);
717 if (err < 0) {
718 err("%s: Error %d for bulk URB %d",
719 __func__, err, i);
720 spin_unlock_irq(&intfdata->susp_lock);
721 goto err_out;
722 }
723 }
724 play_delayed(port);
725 spin_unlock_irq(&intfdata->susp_lock);
726 }
727 spin_lock_irq(&intfdata->susp_lock);
728 intfdata->suspended = 0;
729 spin_unlock_irq(&intfdata->susp_lock);
730err_out:
731 return err;
732}
733EXPORT_SYMBOL(usb_wwan_resume);
734#endif
735
736MODULE_AUTHOR(DRIVER_AUTHOR);
737MODULE_DESCRIPTION(DRIVER_DESC);
738MODULE_VERSION(DRIVER_VERSION);
739MODULE_LICENSE("GPL");
740
741module_param(debug, bool, S_IRUGO | S_IWUSR);
742MODULE_PARM_DESC(debug, "Debug messages");