blob: 3520effb3aa3f2f441dc70bf41910011f15ebc27 [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;
Matthew Garrett0d456192010-04-01 12:31:07 -040046 struct usb_wwan_intf_private *intfdata;
47
Matthew Garrett0d456192010-04-01 12:31:07 -040048 intfdata = port->serial->private;
49
50 if (!intfdata->send_setup)
51 return;
52
53 portdata = usb_get_serial_port_data(port);
54 mutex_lock(&serial->disc_mutex);
55 portdata->rts_state = on;
56 portdata->dtr_state = on;
57 if (serial->dev)
58 intfdata->send_setup(port);
59 mutex_unlock(&serial->disc_mutex);
60}
61EXPORT_SYMBOL(usb_wwan_dtr_rts);
62
63void usb_wwan_set_termios(struct tty_struct *tty,
64 struct usb_serial_port *port,
65 struct ktermios *old_termios)
66{
67 struct usb_wwan_intf_private *intfdata = port->serial->private;
68
Matthew Garrett0d456192010-04-01 12:31:07 -040069 /* Doesn't support option setting */
70 tty_termios_copy_hw(tty->termios, old_termios);
71
72 if (intfdata->send_setup)
73 intfdata->send_setup(port);
74}
75EXPORT_SYMBOL(usb_wwan_set_termios);
76
Alan Cox60b33c12011-02-14 16:26:14 +000077int usb_wwan_tiocmget(struct tty_struct *tty)
Matthew Garrett0d456192010-04-01 12:31:07 -040078{
79 struct usb_serial_port *port = tty->driver_data;
80 unsigned int value;
81 struct usb_wwan_port_private *portdata;
82
83 portdata = usb_get_serial_port_data(port);
84
85 value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
86 ((portdata->dtr_state) ? TIOCM_DTR : 0) |
87 ((portdata->cts_state) ? TIOCM_CTS : 0) |
88 ((portdata->dsr_state) ? TIOCM_DSR : 0) |
89 ((portdata->dcd_state) ? TIOCM_CAR : 0) |
90 ((portdata->ri_state) ? TIOCM_RNG : 0);
91
92 return value;
93}
94EXPORT_SYMBOL(usb_wwan_tiocmget);
95
Alan Cox20b9d172011-02-14 16:26:50 +000096int usb_wwan_tiocmset(struct tty_struct *tty,
Matthew Garrett0d456192010-04-01 12:31:07 -040097 unsigned int set, unsigned int clear)
98{
99 struct usb_serial_port *port = tty->driver_data;
100 struct usb_wwan_port_private *portdata;
101 struct usb_wwan_intf_private *intfdata;
102
103 portdata = usb_get_serial_port_data(port);
104 intfdata = port->serial->private;
105
106 if (!intfdata->send_setup)
107 return -EINVAL;
108
109 /* FIXME: what locks portdata fields ? */
110 if (set & TIOCM_RTS)
111 portdata->rts_state = 1;
112 if (set & TIOCM_DTR)
113 portdata->dtr_state = 1;
114
115 if (clear & TIOCM_RTS)
116 portdata->rts_state = 0;
117 if (clear & TIOCM_DTR)
118 portdata->dtr_state = 0;
119 return intfdata->send_setup(port);
120}
121EXPORT_SYMBOL(usb_wwan_tiocmset);
122
Dan Williams02303f72010-11-19 16:04:00 -0600123static int get_serial_info(struct usb_serial_port *port,
124 struct serial_struct __user *retinfo)
125{
126 struct serial_struct tmp;
127
128 if (!retinfo)
129 return -EFAULT;
130
131 memset(&tmp, 0, sizeof(tmp));
132 tmp.line = port->serial->minor;
133 tmp.port = port->number;
134 tmp.baud_base = tty_get_baud_rate(port->port.tty);
135 tmp.close_delay = port->port.close_delay / 10;
136 tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
137 ASYNC_CLOSING_WAIT_NONE :
138 port->port.closing_wait / 10;
139
140 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
141 return -EFAULT;
142 return 0;
143}
144
145static int set_serial_info(struct usb_serial_port *port,
146 struct serial_struct __user *newinfo)
147{
148 struct serial_struct new_serial;
149 unsigned int closing_wait, close_delay;
150 int retval = 0;
151
152 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
153 return -EFAULT;
154
155 close_delay = new_serial.close_delay * 10;
156 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
157 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
158
159 mutex_lock(&port->port.mutex);
160
161 if (!capable(CAP_SYS_ADMIN)) {
162 if ((close_delay != port->port.close_delay) ||
163 (closing_wait != port->port.closing_wait))
164 retval = -EPERM;
165 else
166 retval = -EOPNOTSUPP;
167 } else {
168 port->port.close_delay = close_delay;
169 port->port.closing_wait = closing_wait;
170 }
171
172 mutex_unlock(&port->port.mutex);
173 return retval;
174}
175
Alan Cox00a0d0d2011-02-14 16:27:06 +0000176int usb_wwan_ioctl(struct tty_struct *tty,
Dan Williams02303f72010-11-19 16:04:00 -0600177 unsigned int cmd, unsigned long arg)
178{
179 struct usb_serial_port *port = tty->driver_data;
180
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700181 dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
Dan Williams02303f72010-11-19 16:04:00 -0600182
183 switch (cmd) {
184 case TIOCGSERIAL:
185 return get_serial_info(port,
186 (struct serial_struct __user *) arg);
187 case TIOCSSERIAL:
188 return set_serial_info(port,
189 (struct serial_struct __user *) arg);
190 default:
191 break;
192 }
193
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700194 dev_dbg(&port->dev, "%s arg not supported\n", __func__);
Dan Williams02303f72010-11-19 16:04:00 -0600195
196 return -ENOIOCTLCMD;
197}
198EXPORT_SYMBOL(usb_wwan_ioctl);
199
Matthew Garrett0d456192010-04-01 12:31:07 -0400200/* Write */
201int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
202 const unsigned char *buf, int count)
203{
204 struct usb_wwan_port_private *portdata;
205 struct usb_wwan_intf_private *intfdata;
206 int i;
207 int left, todo;
208 struct urb *this_urb = NULL; /* spurious */
209 int err;
210 unsigned long flags;
211
212 portdata = usb_get_serial_port_data(port);
213 intfdata = port->serial->private;
214
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700215 dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count);
Matthew Garrett0d456192010-04-01 12:31:07 -0400216
217 i = 0;
218 left = count;
219 for (i = 0; left > 0 && i < N_OUT_URB; i++) {
220 todo = left;
221 if (todo > OUT_BUFLEN)
222 todo = OUT_BUFLEN;
223
224 this_urb = portdata->out_urbs[i];
225 if (test_and_set_bit(i, &portdata->out_busy)) {
226 if (time_before(jiffies,
227 portdata->tx_start_time[i] + 10 * HZ))
228 continue;
229 usb_unlink_urb(this_urb);
230 continue;
231 }
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700232 dev_dbg(&port->dev, "%s: endpoint %d buf %d\n", __func__,
233 usb_pipeendpoint(this_urb->pipe), i);
Matthew Garrett0d456192010-04-01 12:31:07 -0400234
235 err = usb_autopm_get_interface_async(port->serial->interface);
236 if (err < 0)
237 break;
238
239 /* send the data */
240 memcpy(this_urb->transfer_buffer, buf, todo);
241 this_urb->transfer_buffer_length = todo;
242
243 spin_lock_irqsave(&intfdata->susp_lock, flags);
244 if (intfdata->suspended) {
245 usb_anchor_urb(this_urb, &portdata->delayed);
246 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
247 } else {
248 intfdata->in_flight++;
249 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
250 err = usb_submit_urb(this_urb, GFP_ATOMIC);
251 if (err) {
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700252 dev_dbg(&port->dev,
253 "usb_submit_urb %p (write bulk) failed (%d)\n",
254 this_urb, err);
Matthew Garrett0d456192010-04-01 12:31:07 -0400255 clear_bit(i, &portdata->out_busy);
256 spin_lock_irqsave(&intfdata->susp_lock, flags);
257 intfdata->in_flight--;
258 spin_unlock_irqrestore(&intfdata->susp_lock,
259 flags);
Oliver Neukum3d06bf12011-02-10 15:33:17 +0100260 usb_autopm_put_interface_async(port->serial->interface);
Oliver Neukum433508a2011-02-10 15:33:23 +0100261 break;
Matthew Garrett0d456192010-04-01 12:31:07 -0400262 }
263 }
264
265 portdata->tx_start_time[i] = jiffies;
266 buf += todo;
267 left -= todo;
268 }
269
270 count -= left;
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700271 dev_dbg(&port->dev, "%s: wrote (did %d)\n", __func__, count);
Matthew Garrett0d456192010-04-01 12:31:07 -0400272 return count;
273}
274EXPORT_SYMBOL(usb_wwan_write);
275
276static void usb_wwan_indat_callback(struct urb *urb)
277{
278 int err;
279 int endpoint;
280 struct usb_serial_port *port;
281 struct tty_struct *tty;
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700282 struct device *dev;
Matthew Garrett0d456192010-04-01 12:31:07 -0400283 unsigned char *data = urb->transfer_buffer;
284 int status = urb->status;
285
Matthew Garrett0d456192010-04-01 12:31:07 -0400286 endpoint = usb_pipeendpoint(urb->pipe);
287 port = urb->context;
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700288 dev = &port->dev;
Matthew Garrett0d456192010-04-01 12:31:07 -0400289
290 if (status) {
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700291 dev_dbg(dev, "%s: nonzero status: %d on endpoint %02x.\n",
292 __func__, status, endpoint);
Matthew Garrett0d456192010-04-01 12:31:07 -0400293 } else {
294 tty = tty_port_tty_get(&port->port);
Jiri Slaby38237fd2011-02-15 15:55:07 +0100295 if (tty) {
296 if (urb->actual_length) {
297 tty_insert_flip_string(tty, data,
298 urb->actual_length);
299 tty_flip_buffer_push(tty);
300 } else
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700301 dev_dbg(dev, "%s: empty read urb received\n", __func__);
Jiri Slaby38237fd2011-02-15 15:55:07 +0100302 tty_kref_put(tty);
303 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400304
305 /* Resubmit urb so we continue receiving */
Dan Carpenterec428992012-04-20 09:33:31 +0300306 err = usb_submit_urb(urb, GFP_ATOMIC);
307 if (err) {
308 if (err != -EPERM) {
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700309 dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err);
Dan Carpenterec428992012-04-20 09:33:31 +0300310 /* busy also in error unless we are killed */
Matthew Garrett0d456192010-04-01 12:31:07 -0400311 usb_mark_last_busy(port->serial->dev);
Oliver Neukumc9c45582011-02-10 15:33:10 +0100312 }
Dan Carpenterec428992012-04-20 09:33:31 +0300313 } else {
314 usb_mark_last_busy(port->serial->dev);
Matthew Garrett0d456192010-04-01 12:31:07 -0400315 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400316 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400317}
318
319static void usb_wwan_outdat_callback(struct urb *urb)
320{
321 struct usb_serial_port *port;
322 struct usb_wwan_port_private *portdata;
323 struct usb_wwan_intf_private *intfdata;
324 int i;
325
Matthew Garrett0d456192010-04-01 12:31:07 -0400326 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
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700361 dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
Matthew Garrett0d456192010-04-01 12:31:07 -0400362 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 }
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700383 dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
Matthew Garrett0d456192010-04-01 12:31:07 -0400384 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
Matthew Garrett0d456192010-04-01 12:31:07 -0400399 /* Start reading from the IN endpoint */
400 for (i = 0; i < N_IN_URB; i++) {
401 urb = portdata->in_urbs[i];
402 if (!urb)
403 continue;
404 err = usb_submit_urb(urb, GFP_KERNEL);
405 if (err) {
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700406 dev_dbg(&port->dev, "%s: submit urb %d failed (%d) %d\n",
407 __func__, i, err, urb->transfer_buffer_length);
Matthew Garrett0d456192010-04-01 12:31:07 -0400408 }
409 }
410
411 if (intfdata->send_setup)
412 intfdata->send_setup(port);
413
414 serial->interface->needs_remote_wakeup = 1;
415 spin_lock_irq(&intfdata->susp_lock);
416 portdata->opened = 1;
417 spin_unlock_irq(&intfdata->susp_lock);
Oliver Neukum9a91aed2011-02-10 15:33:37 +0100418 /* this balances a get in the generic USB serial code */
Matthew Garrett0d456192010-04-01 12:31:07 -0400419 usb_autopm_put_interface(serial->interface);
420
421 return 0;
422}
423EXPORT_SYMBOL(usb_wwan_open);
424
425void usb_wwan_close(struct usb_serial_port *port)
426{
427 int i;
428 struct usb_serial *serial = port->serial;
429 struct usb_wwan_port_private *portdata;
430 struct usb_wwan_intf_private *intfdata = port->serial->private;
431
Matthew Garrett0d456192010-04-01 12:31:07 -0400432 portdata = usb_get_serial_port_data(port);
433
434 if (serial->dev) {
435 /* Stop reading/writing urbs */
436 spin_lock_irq(&intfdata->susp_lock);
437 portdata->opened = 0;
438 spin_unlock_irq(&intfdata->susp_lock);
439
440 for (i = 0; i < N_IN_URB; i++)
441 usb_kill_urb(portdata->in_urbs[i]);
442 for (i = 0; i < N_OUT_URB; i++)
443 usb_kill_urb(portdata->out_urbs[i]);
Oliver Neukum9a91aed2011-02-10 15:33:37 +0100444 /* balancing - important as an error cannot be handled*/
445 usb_autopm_get_interface_no_resume(serial->interface);
Matthew Garrett0d456192010-04-01 12:31:07 -0400446 serial->interface->needs_remote_wakeup = 0;
447 }
448}
449EXPORT_SYMBOL(usb_wwan_close);
450
451/* Helper functions used by usb_wwan_setup_urbs */
452static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
453 int dir, void *ctx, char *buf, int len,
454 void (*callback) (struct urb *))
455{
456 struct urb *urb;
457
458 if (endpoint == -1)
459 return NULL; /* endpoint not needed */
460
461 urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
462 if (urb == NULL) {
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700463 dev_dbg(&serial->interface->dev,
464 "%s: alloc for endpoint %d failed.\n", __func__,
465 endpoint);
Matthew Garrett0d456192010-04-01 12:31:07 -0400466 return NULL;
467 }
468
469 /* Fill URB using supplied data. */
470 usb_fill_bulk_urb(urb, serial->dev,
471 usb_sndbulkpipe(serial->dev, endpoint) | dir,
472 buf, len, callback, ctx);
473
474 return urb;
475}
476
477/* Setup urbs */
478static void usb_wwan_setup_urbs(struct usb_serial *serial)
479{
480 int i, j;
481 struct usb_serial_port *port;
482 struct usb_wwan_port_private *portdata;
483
Matthew Garrett0d456192010-04-01 12:31:07 -0400484 for (i = 0; i < serial->num_ports; i++) {
485 port = serial->port[i];
486 portdata = usb_get_serial_port_data(port);
487
488 /* Do indat endpoints first */
489 for (j = 0; j < N_IN_URB; ++j) {
490 portdata->in_urbs[j] = usb_wwan_setup_urb(serial,
491 port->
492 bulk_in_endpointAddress,
493 USB_DIR_IN,
494 port,
495 portdata->
496 in_buffer[j],
497 IN_BUFLEN,
498 usb_wwan_indat_callback);
499 }
500
501 /* outdat endpoints */
502 for (j = 0; j < N_OUT_URB; ++j) {
503 portdata->out_urbs[j] = usb_wwan_setup_urb(serial,
504 port->
505 bulk_out_endpointAddress,
506 USB_DIR_OUT,
507 port,
508 portdata->
509 out_buffer
510 [j],
511 OUT_BUFLEN,
512 usb_wwan_outdat_callback);
513 }
514 }
515}
516
517int usb_wwan_startup(struct usb_serial *serial)
518{
519 int i, j, err;
520 struct usb_serial_port *port;
521 struct usb_wwan_port_private *portdata;
522 u8 *buffer;
523
Matthew Garrett0d456192010-04-01 12:31:07 -0400524 /* Now setup per port private data */
525 for (i = 0; i < serial->num_ports; i++) {
526 port = serial->port[i];
527 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
528 if (!portdata) {
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700529 dev_dbg(&port->dev, "%s: kmalloc for usb_wwan_port_private (%d) failed!.\n",
530 __func__, i);
Matthew Garrett0d456192010-04-01 12:31:07 -0400531 return 1;
532 }
533 init_usb_anchor(&portdata->delayed);
534
535 for (j = 0; j < N_IN_URB; j++) {
536 buffer = (u8 *) __get_free_page(GFP_KERNEL);
537 if (!buffer)
538 goto bail_out_error;
539 portdata->in_buffer[j] = buffer;
540 }
541
542 for (j = 0; j < N_OUT_URB; j++) {
543 buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
544 if (!buffer)
545 goto bail_out_error2;
546 portdata->out_buffer[j] = buffer;
547 }
548
549 usb_set_serial_port_data(port, portdata);
550
551 if (!port->interrupt_in_urb)
552 continue;
553 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
554 if (err)
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700555 dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n",
556 __func__, err);
Matthew Garrett0d456192010-04-01 12:31:07 -0400557 }
558 usb_wwan_setup_urbs(serial);
559 return 0;
560
561bail_out_error2:
562 for (j = 0; j < N_OUT_URB; j++)
563 kfree(portdata->out_buffer[j]);
564bail_out_error:
565 for (j = 0; j < N_IN_URB; j++)
566 if (portdata->in_buffer[j])
567 free_page((unsigned long)portdata->in_buffer[j]);
568 kfree(portdata);
569 return 1;
570}
571EXPORT_SYMBOL(usb_wwan_startup);
572
Bjørn Morka1028f02012-07-27 01:11:41 +0200573int usb_wwan_port_remove(struct usb_serial_port *port)
574{
575 int i;
576 struct usb_wwan_port_private *portdata;
577
578 portdata = usb_get_serial_port_data(port);
579 usb_set_serial_port_data(port, NULL);
580
581 /* Stop reading/writing urbs and free them */
582 for (i = 0; i < N_IN_URB; i++) {
583 usb_kill_urb(portdata->in_urbs[i]);
584 usb_free_urb(portdata->in_urbs[i]);
585 free_page((unsigned long)portdata->in_buffer[i]);
586 }
587 for (i = 0; i < N_OUT_URB; i++) {
588 usb_kill_urb(portdata->out_urbs[i]);
589 usb_free_urb(portdata->out_urbs[i]);
590 kfree(portdata->out_buffer[i]);
591 }
592
593 /* Now free port private data */
594 kfree(portdata);
595 return 0;
596}
597EXPORT_SYMBOL(usb_wwan_port_remove);
598
599#ifdef CONFIG_PM
Matthew Garrett0d456192010-04-01 12:31:07 -0400600static void stop_read_write_urbs(struct usb_serial *serial)
601{
602 int i, j;
603 struct usb_serial_port *port;
604 struct usb_wwan_port_private *portdata;
605
606 /* Stop reading/writing urbs */
607 for (i = 0; i < serial->num_ports; ++i) {
608 port = serial->port[i];
609 portdata = usb_get_serial_port_data(port);
Bjørn Mork032129c2012-07-27 01:11:43 +0200610 if (!portdata)
611 continue;
Matthew Garrett0d456192010-04-01 12:31:07 -0400612 for (j = 0; j < N_IN_URB; j++)
613 usb_kill_urb(portdata->in_urbs[j]);
614 for (j = 0; j < N_OUT_URB; j++)
615 usb_kill_urb(portdata->out_urbs[j]);
616 }
617}
618
Matthew Garrett0d456192010-04-01 12:31:07 -0400619int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
620{
621 struct usb_wwan_intf_private *intfdata = serial->private;
622 int b;
623
Alan Stern5b1b0b82011-08-19 23:49:48 +0200624 if (PMSG_IS_AUTO(message)) {
Matthew Garrett0d456192010-04-01 12:31:07 -0400625 spin_lock_irq(&intfdata->susp_lock);
626 b = intfdata->in_flight;
627 spin_unlock_irq(&intfdata->susp_lock);
628
629 if (b)
630 return -EBUSY;
631 }
632
633 spin_lock_irq(&intfdata->susp_lock);
634 intfdata->suspended = 1;
635 spin_unlock_irq(&intfdata->susp_lock);
636 stop_read_write_urbs(serial);
637
638 return 0;
639}
640EXPORT_SYMBOL(usb_wwan_suspend);
641
Oliver Neukum16871dc2011-02-10 15:33:29 +0100642static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
643{
644 int i;
645
646 for (i = 0; i < N_OUT_URB; i++) {
647 if (urb == portdata->out_urbs[i]) {
648 clear_bit(i, &portdata->out_busy);
649 break;
650 }
651 }
652}
653
Matthew Garrett0d456192010-04-01 12:31:07 -0400654static void play_delayed(struct usb_serial_port *port)
655{
656 struct usb_wwan_intf_private *data;
657 struct usb_wwan_port_private *portdata;
658 struct urb *urb;
659 int err;
660
661 portdata = usb_get_serial_port_data(port);
662 data = port->serial->private;
663 while ((urb = usb_get_from_anchor(&portdata->delayed))) {
664 err = usb_submit_urb(urb, GFP_ATOMIC);
Oliver Neukum16871dc2011-02-10 15:33:29 +0100665 if (!err) {
Matthew Garrett0d456192010-04-01 12:31:07 -0400666 data->in_flight++;
Oliver Neukum16871dc2011-02-10 15:33:29 +0100667 } else {
668 /* we have to throw away the rest */
669 do {
670 unbusy_queued_urb(urb, portdata);
Oliver Neukum97ac01d2011-03-18 12:44:17 +0100671 usb_autopm_put_interface_no_suspend(port->serial->interface);
Oliver Neukum16871dc2011-02-10 15:33:29 +0100672 } while ((urb = usb_get_from_anchor(&portdata->delayed)));
673 break;
674 }
Matthew Garrett0d456192010-04-01 12:31:07 -0400675 }
676}
677
678int usb_wwan_resume(struct usb_serial *serial)
679{
680 int i, j;
681 struct usb_serial_port *port;
682 struct usb_wwan_intf_private *intfdata = serial->private;
683 struct usb_wwan_port_private *portdata;
684 struct urb *urb;
685 int err = 0;
686
Matthew Garrett0d456192010-04-01 12:31:07 -0400687 /* get the interrupt URBs resubmitted unconditionally */
688 for (i = 0; i < serial->num_ports; i++) {
689 port = serial->port[i];
690 if (!port->interrupt_in_urb) {
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700691 dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__);
Matthew Garrett0d456192010-04-01 12:31:07 -0400692 continue;
693 }
694 err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
Greg Kroah-Hartmana80be972012-09-13 17:41:50 -0700695 dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err);
Matthew Garrett0d456192010-04-01 12:31:07 -0400696 if (err < 0) {
Greg Kroah-Hartman3a1c2a82012-04-20 16:54:01 -0700697 dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
698 __func__, err);
Matthew Garrett0d456192010-04-01 12:31:07 -0400699 goto err_out;
700 }
701 }
702
703 for (i = 0; i < serial->num_ports; i++) {
704 /* walk all ports */
705 port = serial->port[i];
706 portdata = usb_get_serial_port_data(port);
707
708 /* skip closed ports */
709 spin_lock_irq(&intfdata->susp_lock);
Bjørn Mork032129c2012-07-27 01:11:43 +0200710 if (!portdata || !portdata->opened) {
Matthew Garrett0d456192010-04-01 12:31:07 -0400711 spin_unlock_irq(&intfdata->susp_lock);
712 continue;
713 }
714
715 for (j = 0; j < N_IN_URB; j++) {
716 urb = portdata->in_urbs[j];
717 err = usb_submit_urb(urb, GFP_ATOMIC);
718 if (err < 0) {
Greg Kroah-Hartman3a1c2a82012-04-20 16:54:01 -0700719 dev_err(&port->dev, "%s: Error %d for bulk URB %d\n",
720 __func__, err, i);
Matthew Garrett0d456192010-04-01 12:31:07 -0400721 spin_unlock_irq(&intfdata->susp_lock);
722 goto err_out;
723 }
724 }
725 play_delayed(port);
726 spin_unlock_irq(&intfdata->susp_lock);
727 }
728 spin_lock_irq(&intfdata->susp_lock);
729 intfdata->suspended = 0;
730 spin_unlock_irq(&intfdata->susp_lock);
731err_out:
732 return err;
733}
734EXPORT_SYMBOL(usb_wwan_resume);
735#endif
736
737MODULE_AUTHOR(DRIVER_AUTHOR);
738MODULE_DESCRIPTION(DRIVER_DESC);
739MODULE_VERSION(DRIVER_VERSION);
740MODULE_LICENSE("GPL");
741
742module_param(debug, bool, S_IRUGO | S_IWUSR);
743MODULE_PARM_DESC(debug, "Debug messages");