diff options
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 236 |
1 files changed, 117 insertions, 119 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index b078440e822f..2f805cb386a5 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c | |||
@@ -41,7 +41,7 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) | |||
41 | struct usb_wwan_port_private *portdata; | 41 | struct usb_wwan_port_private *portdata; |
42 | struct usb_wwan_intf_private *intfdata; | 42 | struct usb_wwan_intf_private *intfdata; |
43 | 43 | ||
44 | intfdata = port->serial->private; | 44 | intfdata = usb_get_serial_data(port->serial); |
45 | 45 | ||
46 | if (!intfdata->send_setup) | 46 | if (!intfdata->send_setup) |
47 | return; | 47 | return; |
@@ -55,20 +55,6 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) | |||
55 | } | 55 | } |
56 | EXPORT_SYMBOL(usb_wwan_dtr_rts); | 56 | EXPORT_SYMBOL(usb_wwan_dtr_rts); |
57 | 57 | ||
58 | void usb_wwan_set_termios(struct tty_struct *tty, | ||
59 | struct usb_serial_port *port, | ||
60 | struct ktermios *old_termios) | ||
61 | { | ||
62 | struct usb_wwan_intf_private *intfdata = port->serial->private; | ||
63 | |||
64 | /* Doesn't support option setting */ | ||
65 | tty_termios_copy_hw(&tty->termios, old_termios); | ||
66 | |||
67 | if (intfdata->send_setup) | ||
68 | intfdata->send_setup(port); | ||
69 | } | ||
70 | EXPORT_SYMBOL(usb_wwan_set_termios); | ||
71 | |||
72 | int usb_wwan_tiocmget(struct tty_struct *tty) | 58 | int usb_wwan_tiocmget(struct tty_struct *tty) |
73 | { | 59 | { |
74 | struct usb_serial_port *port = tty->driver_data; | 60 | struct usb_serial_port *port = tty->driver_data; |
@@ -96,7 +82,7 @@ int usb_wwan_tiocmset(struct tty_struct *tty, | |||
96 | struct usb_wwan_intf_private *intfdata; | 82 | struct usb_wwan_intf_private *intfdata; |
97 | 83 | ||
98 | portdata = usb_get_serial_port_data(port); | 84 | portdata = usb_get_serial_port_data(port); |
99 | intfdata = port->serial->private; | 85 | intfdata = usb_get_serial_data(port->serial); |
100 | 86 | ||
101 | if (!intfdata->send_setup) | 87 | if (!intfdata->send_setup) |
102 | return -EINVAL; | 88 | return -EINVAL; |
@@ -192,7 +178,6 @@ int usb_wwan_ioctl(struct tty_struct *tty, | |||
192 | } | 178 | } |
193 | EXPORT_SYMBOL(usb_wwan_ioctl); | 179 | EXPORT_SYMBOL(usb_wwan_ioctl); |
194 | 180 | ||
195 | /* Write */ | ||
196 | int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | 181 | int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, |
197 | const unsigned char *buf, int count) | 182 | const unsigned char *buf, int count) |
198 | { | 183 | { |
@@ -205,7 +190,7 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
205 | unsigned long flags; | 190 | unsigned long flags; |
206 | 191 | ||
207 | portdata = usb_get_serial_port_data(port); | 192 | portdata = usb_get_serial_port_data(port); |
208 | intfdata = port->serial->private; | 193 | intfdata = usb_get_serial_data(port->serial); |
209 | 194 | ||
210 | dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count); | 195 | dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count); |
211 | 196 | ||
@@ -228,8 +213,10 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
228 | usb_pipeendpoint(this_urb->pipe), i); | 213 | usb_pipeendpoint(this_urb->pipe), i); |
229 | 214 | ||
230 | err = usb_autopm_get_interface_async(port->serial->interface); | 215 | err = usb_autopm_get_interface_async(port->serial->interface); |
231 | if (err < 0) | 216 | if (err < 0) { |
217 | clear_bit(i, &portdata->out_busy); | ||
232 | break; | 218 | break; |
219 | } | ||
233 | 220 | ||
234 | /* send the data */ | 221 | /* send the data */ |
235 | memcpy(this_urb->transfer_buffer, buf, todo); | 222 | memcpy(this_urb->transfer_buffer, buf, todo); |
@@ -244,9 +231,9 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
244 | spin_unlock_irqrestore(&intfdata->susp_lock, flags); | 231 | spin_unlock_irqrestore(&intfdata->susp_lock, flags); |
245 | err = usb_submit_urb(this_urb, GFP_ATOMIC); | 232 | err = usb_submit_urb(this_urb, GFP_ATOMIC); |
246 | if (err) { | 233 | if (err) { |
247 | dev_dbg(&port->dev, | 234 | dev_err(&port->dev, |
248 | "usb_submit_urb %p (write bulk) failed (%d)\n", | 235 | "%s: submit urb %d failed: %d\n", |
249 | this_urb, err); | 236 | __func__, i, err); |
250 | clear_bit(i, &portdata->out_busy); | 237 | clear_bit(i, &portdata->out_busy); |
251 | spin_lock_irqsave(&intfdata->susp_lock, flags); | 238 | spin_lock_irqsave(&intfdata->susp_lock, flags); |
252 | intfdata->in_flight--; | 239 | intfdata->in_flight--; |
@@ -314,7 +301,7 @@ static void usb_wwan_outdat_callback(struct urb *urb) | |||
314 | int i; | 301 | int i; |
315 | 302 | ||
316 | port = urb->context; | 303 | port = urb->context; |
317 | intfdata = port->serial->private; | 304 | intfdata = usb_get_serial_data(port->serial); |
318 | 305 | ||
319 | usb_serial_port_softint(port); | 306 | usb_serial_port_softint(port); |
320 | usb_autopm_put_interface_async(port->serial->interface); | 307 | usb_autopm_put_interface_async(port->serial->interface); |
@@ -325,7 +312,7 @@ static void usb_wwan_outdat_callback(struct urb *urb) | |||
325 | 312 | ||
326 | for (i = 0; i < N_OUT_URB; ++i) { | 313 | for (i = 0; i < N_OUT_URB; ++i) { |
327 | if (portdata->out_urbs[i] == urb) { | 314 | if (portdata->out_urbs[i] == urb) { |
328 | smp_mb__before_clear_bit(); | 315 | smp_mb__before_atomic(); |
329 | clear_bit(i, &portdata->out_busy); | 316 | clear_bit(i, &portdata->out_busy); |
330 | break; | 317 | break; |
331 | } | 318 | } |
@@ -384,7 +371,15 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
384 | struct urb *urb; | 371 | struct urb *urb; |
385 | 372 | ||
386 | portdata = usb_get_serial_port_data(port); | 373 | portdata = usb_get_serial_port_data(port); |
387 | intfdata = serial->private; | 374 | intfdata = usb_get_serial_data(serial); |
375 | |||
376 | if (port->interrupt_in_urb) { | ||
377 | err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); | ||
378 | if (err) { | ||
379 | dev_err(&port->dev, "%s: submit int urb failed: %d\n", | ||
380 | __func__, err); | ||
381 | } | ||
382 | } | ||
388 | 383 | ||
389 | /* Start reading from the IN endpoint */ | 384 | /* Start reading from the IN endpoint */ |
390 | for (i = 0; i < N_IN_URB; i++) { | 385 | for (i = 0; i < N_IN_URB; i++) { |
@@ -393,17 +388,15 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
393 | continue; | 388 | continue; |
394 | err = usb_submit_urb(urb, GFP_KERNEL); | 389 | err = usb_submit_urb(urb, GFP_KERNEL); |
395 | if (err) { | 390 | if (err) { |
396 | dev_dbg(&port->dev, "%s: submit urb %d failed (%d) %d\n", | 391 | dev_err(&port->dev, |
397 | __func__, i, err, urb->transfer_buffer_length); | 392 | "%s: submit read urb %d failed: %d\n", |
393 | __func__, i, err); | ||
398 | } | 394 | } |
399 | } | 395 | } |
400 | 396 | ||
401 | if (intfdata->send_setup) | ||
402 | intfdata->send_setup(port); | ||
403 | |||
404 | serial->interface->needs_remote_wakeup = 1; | ||
405 | spin_lock_irq(&intfdata->susp_lock); | 397 | spin_lock_irq(&intfdata->susp_lock); |
406 | portdata->opened = 1; | 398 | if (++intfdata->open_ports == 1) |
399 | serial->interface->needs_remote_wakeup = 1; | ||
407 | spin_unlock_irq(&intfdata->susp_lock); | 400 | spin_unlock_irq(&intfdata->susp_lock); |
408 | /* this balances a get in the generic USB serial code */ | 401 | /* this balances a get in the generic USB serial code */ |
409 | usb_autopm_put_interface(serial->interface); | 402 | usb_autopm_put_interface(serial->interface); |
@@ -412,32 +405,56 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
412 | } | 405 | } |
413 | EXPORT_SYMBOL(usb_wwan_open); | 406 | EXPORT_SYMBOL(usb_wwan_open); |
414 | 407 | ||
408 | static void unbusy_queued_urb(struct urb *urb, | ||
409 | struct usb_wwan_port_private *portdata) | ||
410 | { | ||
411 | int i; | ||
412 | |||
413 | for (i = 0; i < N_OUT_URB; i++) { | ||
414 | if (urb == portdata->out_urbs[i]) { | ||
415 | clear_bit(i, &portdata->out_busy); | ||
416 | break; | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | |||
415 | void usb_wwan_close(struct usb_serial_port *port) | 421 | void usb_wwan_close(struct usb_serial_port *port) |
416 | { | 422 | { |
417 | int i; | 423 | int i; |
418 | struct usb_serial *serial = port->serial; | 424 | struct usb_serial *serial = port->serial; |
419 | struct usb_wwan_port_private *portdata; | 425 | struct usb_wwan_port_private *portdata; |
420 | struct usb_wwan_intf_private *intfdata = port->serial->private; | 426 | struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); |
427 | struct urb *urb; | ||
421 | 428 | ||
422 | portdata = usb_get_serial_port_data(port); | 429 | portdata = usb_get_serial_port_data(port); |
423 | 430 | ||
424 | /* Stop reading/writing urbs */ | 431 | /* |
432 | * Need to take susp_lock to make sure port is not already being | ||
433 | * resumed, but no need to hold it due to ASYNC_INITIALIZED. | ||
434 | */ | ||
425 | spin_lock_irq(&intfdata->susp_lock); | 435 | spin_lock_irq(&intfdata->susp_lock); |
426 | portdata->opened = 0; | 436 | if (--intfdata->open_ports == 0) |
437 | serial->interface->needs_remote_wakeup = 0; | ||
427 | spin_unlock_irq(&intfdata->susp_lock); | 438 | spin_unlock_irq(&intfdata->susp_lock); |
428 | 439 | ||
440 | for (;;) { | ||
441 | urb = usb_get_from_anchor(&portdata->delayed); | ||
442 | if (!urb) | ||
443 | break; | ||
444 | unbusy_queued_urb(urb, portdata); | ||
445 | usb_autopm_put_interface_async(serial->interface); | ||
446 | } | ||
447 | |||
429 | for (i = 0; i < N_IN_URB; i++) | 448 | for (i = 0; i < N_IN_URB; i++) |
430 | usb_kill_urb(portdata->in_urbs[i]); | 449 | usb_kill_urb(portdata->in_urbs[i]); |
431 | for (i = 0; i < N_OUT_URB; i++) | 450 | for (i = 0; i < N_OUT_URB; i++) |
432 | usb_kill_urb(portdata->out_urbs[i]); | 451 | usb_kill_urb(portdata->out_urbs[i]); |
452 | usb_kill_urb(port->interrupt_in_urb); | ||
433 | 453 | ||
434 | /* balancing - important as an error cannot be handled*/ | ||
435 | usb_autopm_get_interface_no_resume(serial->interface); | 454 | usb_autopm_get_interface_no_resume(serial->interface); |
436 | serial->interface->needs_remote_wakeup = 0; | ||
437 | } | 455 | } |
438 | EXPORT_SYMBOL(usb_wwan_close); | 456 | EXPORT_SYMBOL(usb_wwan_close); |
439 | 457 | ||
440 | /* Helper functions used by usb_wwan_setup_urbs */ | ||
441 | static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, | 458 | static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, |
442 | int endpoint, | 459 | int endpoint, |
443 | int dir, void *ctx, char *buf, int len, | 460 | int dir, void *ctx, char *buf, int len, |
@@ -450,7 +467,6 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, | |||
450 | if (!urb) | 467 | if (!urb) |
451 | return NULL; | 468 | return NULL; |
452 | 469 | ||
453 | /* Fill URB using supplied data. */ | ||
454 | usb_fill_bulk_urb(urb, serial->dev, | 470 | usb_fill_bulk_urb(urb, serial->dev, |
455 | usb_sndbulkpipe(serial->dev, endpoint) | dir, | 471 | usb_sndbulkpipe(serial->dev, endpoint) | dir, |
456 | buf, len, callback, ctx); | 472 | buf, len, callback, ctx); |
@@ -463,7 +479,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port) | |||
463 | struct usb_wwan_port_private *portdata; | 479 | struct usb_wwan_port_private *portdata; |
464 | struct urb *urb; | 480 | struct urb *urb; |
465 | u8 *buffer; | 481 | u8 *buffer; |
466 | int err; | ||
467 | int i; | 482 | int i; |
468 | 483 | ||
469 | if (!port->bulk_in_size || !port->bulk_out_size) | 484 | if (!port->bulk_in_size || !port->bulk_out_size) |
@@ -503,13 +518,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port) | |||
503 | 518 | ||
504 | usb_set_serial_port_data(port, portdata); | 519 | usb_set_serial_port_data(port, portdata); |
505 | 520 | ||
506 | if (port->interrupt_in_urb) { | ||
507 | err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); | ||
508 | if (err) | ||
509 | dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n", | ||
510 | __func__, err); | ||
511 | } | ||
512 | |||
513 | return 0; | 521 | return 0; |
514 | 522 | ||
515 | bail_out_error2: | 523 | bail_out_error2: |
@@ -536,32 +544,28 @@ int usb_wwan_port_remove(struct usb_serial_port *port) | |||
536 | portdata = usb_get_serial_port_data(port); | 544 | portdata = usb_get_serial_port_data(port); |
537 | usb_set_serial_port_data(port, NULL); | 545 | usb_set_serial_port_data(port, NULL); |
538 | 546 | ||
539 | /* Stop reading/writing urbs and free them */ | ||
540 | for (i = 0; i < N_IN_URB; i++) { | 547 | for (i = 0; i < N_IN_URB; i++) { |
541 | usb_kill_urb(portdata->in_urbs[i]); | ||
542 | usb_free_urb(portdata->in_urbs[i]); | 548 | usb_free_urb(portdata->in_urbs[i]); |
543 | free_page((unsigned long)portdata->in_buffer[i]); | 549 | free_page((unsigned long)portdata->in_buffer[i]); |
544 | } | 550 | } |
545 | for (i = 0; i < N_OUT_URB; i++) { | 551 | for (i = 0; i < N_OUT_URB; i++) { |
546 | usb_kill_urb(portdata->out_urbs[i]); | ||
547 | usb_free_urb(portdata->out_urbs[i]); | 552 | usb_free_urb(portdata->out_urbs[i]); |
548 | kfree(portdata->out_buffer[i]); | 553 | kfree(portdata->out_buffer[i]); |
549 | } | 554 | } |
550 | 555 | ||
551 | /* Now free port private data */ | ||
552 | kfree(portdata); | 556 | kfree(portdata); |
557 | |||
553 | return 0; | 558 | return 0; |
554 | } | 559 | } |
555 | EXPORT_SYMBOL(usb_wwan_port_remove); | 560 | EXPORT_SYMBOL(usb_wwan_port_remove); |
556 | 561 | ||
557 | #ifdef CONFIG_PM | 562 | #ifdef CONFIG_PM |
558 | static void stop_read_write_urbs(struct usb_serial *serial) | 563 | static void stop_urbs(struct usb_serial *serial) |
559 | { | 564 | { |
560 | int i, j; | 565 | int i, j; |
561 | struct usb_serial_port *port; | 566 | struct usb_serial_port *port; |
562 | struct usb_wwan_port_private *portdata; | 567 | struct usb_wwan_port_private *portdata; |
563 | 568 | ||
564 | /* Stop reading/writing urbs */ | ||
565 | for (i = 0; i < serial->num_ports; ++i) { | 569 | for (i = 0; i < serial->num_ports; ++i) { |
566 | port = serial->port[i]; | 570 | port = serial->port[i]; |
567 | portdata = usb_get_serial_port_data(port); | 571 | portdata = usb_get_serial_port_data(port); |
@@ -571,123 +575,117 @@ static void stop_read_write_urbs(struct usb_serial *serial) | |||
571 | usb_kill_urb(portdata->in_urbs[j]); | 575 | usb_kill_urb(portdata->in_urbs[j]); |
572 | for (j = 0; j < N_OUT_URB; j++) | 576 | for (j = 0; j < N_OUT_URB; j++) |
573 | usb_kill_urb(portdata->out_urbs[j]); | 577 | usb_kill_urb(portdata->out_urbs[j]); |
578 | usb_kill_urb(port->interrupt_in_urb); | ||
574 | } | 579 | } |
575 | } | 580 | } |
576 | 581 | ||
577 | int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) | 582 | int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) |
578 | { | 583 | { |
579 | struct usb_wwan_intf_private *intfdata = serial->private; | 584 | struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); |
580 | int b; | ||
581 | 585 | ||
586 | spin_lock_irq(&intfdata->susp_lock); | ||
582 | if (PMSG_IS_AUTO(message)) { | 587 | if (PMSG_IS_AUTO(message)) { |
583 | spin_lock_irq(&intfdata->susp_lock); | 588 | if (intfdata->in_flight) { |
584 | b = intfdata->in_flight; | 589 | spin_unlock_irq(&intfdata->susp_lock); |
585 | spin_unlock_irq(&intfdata->susp_lock); | ||
586 | |||
587 | if (b) | ||
588 | return -EBUSY; | 590 | return -EBUSY; |
591 | } | ||
589 | } | 592 | } |
590 | |||
591 | spin_lock_irq(&intfdata->susp_lock); | ||
592 | intfdata->suspended = 1; | 593 | intfdata->suspended = 1; |
593 | spin_unlock_irq(&intfdata->susp_lock); | 594 | spin_unlock_irq(&intfdata->susp_lock); |
594 | stop_read_write_urbs(serial); | 595 | |
596 | stop_urbs(serial); | ||
595 | 597 | ||
596 | return 0; | 598 | return 0; |
597 | } | 599 | } |
598 | EXPORT_SYMBOL(usb_wwan_suspend); | 600 | EXPORT_SYMBOL(usb_wwan_suspend); |
599 | 601 | ||
600 | static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) | 602 | /* Caller must hold susp_lock. */ |
603 | static int usb_wwan_submit_delayed_urbs(struct usb_serial_port *port) | ||
601 | { | 604 | { |
602 | int i; | 605 | struct usb_serial *serial = port->serial; |
603 | 606 | struct usb_wwan_intf_private *data = usb_get_serial_data(serial); | |
604 | for (i = 0; i < N_OUT_URB; i++) { | ||
605 | if (urb == portdata->out_urbs[i]) { | ||
606 | clear_bit(i, &portdata->out_busy); | ||
607 | break; | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | |||
612 | static void play_delayed(struct usb_serial_port *port) | ||
613 | { | ||
614 | struct usb_wwan_intf_private *data; | ||
615 | struct usb_wwan_port_private *portdata; | 607 | struct usb_wwan_port_private *portdata; |
616 | struct urb *urb; | 608 | struct urb *urb; |
609 | int err_count = 0; | ||
617 | int err; | 610 | int err; |
618 | 611 | ||
619 | portdata = usb_get_serial_port_data(port); | 612 | portdata = usb_get_serial_port_data(port); |
620 | data = port->serial->private; | 613 | |
621 | while ((urb = usb_get_from_anchor(&portdata->delayed))) { | 614 | for (;;) { |
622 | err = usb_submit_urb(urb, GFP_ATOMIC); | 615 | urb = usb_get_from_anchor(&portdata->delayed); |
623 | if (!err) { | 616 | if (!urb) |
624 | data->in_flight++; | ||
625 | } else { | ||
626 | /* we have to throw away the rest */ | ||
627 | do { | ||
628 | unbusy_queued_urb(urb, portdata); | ||
629 | usb_autopm_put_interface_no_suspend(port->serial->interface); | ||
630 | } while ((urb = usb_get_from_anchor(&portdata->delayed))); | ||
631 | break; | 617 | break; |
618 | |||
619 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
620 | if (err) { | ||
621 | dev_err(&port->dev, "%s: submit urb failed: %d\n", | ||
622 | __func__, err); | ||
623 | err_count++; | ||
624 | unbusy_queued_urb(urb, portdata); | ||
625 | usb_autopm_put_interface_async(serial->interface); | ||
626 | continue; | ||
632 | } | 627 | } |
628 | data->in_flight++; | ||
633 | } | 629 | } |
630 | |||
631 | if (err_count) | ||
632 | return -EIO; | ||
633 | |||
634 | return 0; | ||
634 | } | 635 | } |
635 | 636 | ||
636 | int usb_wwan_resume(struct usb_serial *serial) | 637 | int usb_wwan_resume(struct usb_serial *serial) |
637 | { | 638 | { |
638 | int i, j; | 639 | int i, j; |
639 | struct usb_serial_port *port; | 640 | struct usb_serial_port *port; |
640 | struct usb_wwan_intf_private *intfdata = serial->private; | 641 | struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); |
641 | struct usb_wwan_port_private *portdata; | 642 | struct usb_wwan_port_private *portdata; |
642 | struct urb *urb; | 643 | struct urb *urb; |
643 | int err = 0; | 644 | int err; |
645 | int err_count = 0; | ||
644 | 646 | ||
645 | /* get the interrupt URBs resubmitted unconditionally */ | 647 | spin_lock_irq(&intfdata->susp_lock); |
646 | for (i = 0; i < serial->num_ports; i++) { | 648 | for (i = 0; i < serial->num_ports; i++) { |
647 | port = serial->port[i]; | 649 | port = serial->port[i]; |
648 | if (!port->interrupt_in_urb) { | 650 | |
649 | dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__); | 651 | if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) |
650 | continue; | 652 | continue; |
651 | } | ||
652 | err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); | ||
653 | dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err); | ||
654 | if (err < 0) { | ||
655 | dev_err(&port->dev, "%s: Error %d for interrupt URB\n", | ||
656 | __func__, err); | ||
657 | goto err_out; | ||
658 | } | ||
659 | } | ||
660 | 653 | ||
661 | for (i = 0; i < serial->num_ports; i++) { | ||
662 | /* walk all ports */ | ||
663 | port = serial->port[i]; | ||
664 | portdata = usb_get_serial_port_data(port); | 654 | portdata = usb_get_serial_port_data(port); |
665 | 655 | ||
666 | /* skip closed ports */ | 656 | if (port->interrupt_in_urb) { |
667 | spin_lock_irq(&intfdata->susp_lock); | 657 | err = usb_submit_urb(port->interrupt_in_urb, |
668 | if (!portdata || !portdata->opened) { | 658 | GFP_ATOMIC); |
669 | spin_unlock_irq(&intfdata->susp_lock); | 659 | if (err) { |
670 | continue; | 660 | dev_err(&port->dev, |
661 | "%s: submit int urb failed: %d\n", | ||
662 | __func__, err); | ||
663 | err_count++; | ||
664 | } | ||
671 | } | 665 | } |
672 | 666 | ||
667 | err = usb_wwan_submit_delayed_urbs(port); | ||
668 | if (err) | ||
669 | err_count++; | ||
670 | |||
673 | for (j = 0; j < N_IN_URB; j++) { | 671 | for (j = 0; j < N_IN_URB; j++) { |
674 | urb = portdata->in_urbs[j]; | 672 | urb = portdata->in_urbs[j]; |
675 | err = usb_submit_urb(urb, GFP_ATOMIC); | 673 | err = usb_submit_urb(urb, GFP_ATOMIC); |
676 | if (err < 0) { | 674 | if (err < 0) { |
677 | dev_err(&port->dev, "%s: Error %d for bulk URB %d\n", | 675 | dev_err(&port->dev, |
678 | __func__, err, i); | 676 | "%s: submit read urb %d failed: %d\n", |
679 | spin_unlock_irq(&intfdata->susp_lock); | 677 | __func__, i, err); |
680 | goto err_out; | 678 | err_count++; |
681 | } | 679 | } |
682 | } | 680 | } |
683 | play_delayed(port); | ||
684 | spin_unlock_irq(&intfdata->susp_lock); | ||
685 | } | 681 | } |
686 | spin_lock_irq(&intfdata->susp_lock); | ||
687 | intfdata->suspended = 0; | 682 | intfdata->suspended = 0; |
688 | spin_unlock_irq(&intfdata->susp_lock); | 683 | spin_unlock_irq(&intfdata->susp_lock); |
689 | err_out: | 684 | |
690 | return err; | 685 | if (err_count) |
686 | return -EIO; | ||
687 | |||
688 | return 0; | ||
691 | } | 689 | } |
692 | EXPORT_SYMBOL(usb_wwan_resume); | 690 | EXPORT_SYMBOL(usb_wwan_resume); |
693 | #endif | 691 | #endif |