diff options
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 9c014e2ecd68..eb95aecc0015 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c | |||
@@ -261,7 +261,8 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
261 | intfdata->in_flight--; | 261 | intfdata->in_flight--; |
262 | spin_unlock_irqrestore(&intfdata->susp_lock, | 262 | spin_unlock_irqrestore(&intfdata->susp_lock, |
263 | flags); | 263 | flags); |
264 | continue; | 264 | usb_autopm_put_interface_async(port->serial->interface); |
265 | break; | ||
265 | } | 266 | } |
266 | } | 267 | } |
267 | 268 | ||
@@ -308,11 +309,16 @@ static void usb_wwan_indat_callback(struct urb *urb) | |||
308 | /* Resubmit urb so we continue receiving */ | 309 | /* Resubmit urb so we continue receiving */ |
309 | if (status != -ESHUTDOWN) { | 310 | if (status != -ESHUTDOWN) { |
310 | err = usb_submit_urb(urb, GFP_ATOMIC); | 311 | err = usb_submit_urb(urb, GFP_ATOMIC); |
311 | if (err && err != -EPERM) | 312 | if (err) { |
312 | printk(KERN_ERR "%s: resubmit read urb failed. " | 313 | if (err != -EPERM) { |
313 | "(%d)", __func__, err); | 314 | printk(KERN_ERR "%s: resubmit read urb failed. " |
314 | else | 315 | "(%d)", __func__, err); |
316 | /* busy also in error unless we are killed */ | ||
317 | usb_mark_last_busy(port->serial->dev); | ||
318 | } | ||
319 | } else { | ||
315 | usb_mark_last_busy(port->serial->dev); | 320 | usb_mark_last_busy(port->serial->dev); |
321 | } | ||
316 | } | 322 | } |
317 | 323 | ||
318 | } | 324 | } |
@@ -421,6 +427,7 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
421 | spin_lock_irq(&intfdata->susp_lock); | 427 | spin_lock_irq(&intfdata->susp_lock); |
422 | portdata->opened = 1; | 428 | portdata->opened = 1; |
423 | spin_unlock_irq(&intfdata->susp_lock); | 429 | spin_unlock_irq(&intfdata->susp_lock); |
430 | /* this balances a get in the generic USB serial code */ | ||
424 | usb_autopm_put_interface(serial->interface); | 431 | usb_autopm_put_interface(serial->interface); |
425 | 432 | ||
426 | return 0; | 433 | return 0; |
@@ -447,7 +454,8 @@ void usb_wwan_close(struct usb_serial_port *port) | |||
447 | usb_kill_urb(portdata->in_urbs[i]); | 454 | usb_kill_urb(portdata->in_urbs[i]); |
448 | for (i = 0; i < N_OUT_URB; i++) | 455 | for (i = 0; i < N_OUT_URB; i++) |
449 | usb_kill_urb(portdata->out_urbs[i]); | 456 | usb_kill_urb(portdata->out_urbs[i]); |
450 | usb_autopm_get_interface(serial->interface); | 457 | /* balancing - important as an error cannot be handled*/ |
458 | usb_autopm_get_interface_no_resume(serial->interface); | ||
451 | serial->interface->needs_remote_wakeup = 0; | 459 | serial->interface->needs_remote_wakeup = 0; |
452 | } | 460 | } |
453 | } | 461 | } |
@@ -661,6 +669,18 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) | |||
661 | } | 669 | } |
662 | EXPORT_SYMBOL(usb_wwan_suspend); | 670 | EXPORT_SYMBOL(usb_wwan_suspend); |
663 | 671 | ||
672 | static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) | ||
673 | { | ||
674 | int i; | ||
675 | |||
676 | for (i = 0; i < N_OUT_URB; i++) { | ||
677 | if (urb == portdata->out_urbs[i]) { | ||
678 | clear_bit(i, &portdata->out_busy); | ||
679 | break; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | |||
664 | static void play_delayed(struct usb_serial_port *port) | 684 | static void play_delayed(struct usb_serial_port *port) |
665 | { | 685 | { |
666 | struct usb_wwan_intf_private *data; | 686 | struct usb_wwan_intf_private *data; |
@@ -672,8 +692,17 @@ static void play_delayed(struct usb_serial_port *port) | |||
672 | data = port->serial->private; | 692 | data = port->serial->private; |
673 | while ((urb = usb_get_from_anchor(&portdata->delayed))) { | 693 | while ((urb = usb_get_from_anchor(&portdata->delayed))) { |
674 | err = usb_submit_urb(urb, GFP_ATOMIC); | 694 | err = usb_submit_urb(urb, GFP_ATOMIC); |
675 | if (!err) | 695 | if (!err) { |
676 | data->in_flight++; | 696 | data->in_flight++; |
697 | } else { | ||
698 | /* we have to throw away the rest */ | ||
699 | do { | ||
700 | unbusy_queued_urb(urb, portdata); | ||
701 | //extremely dirty | ||
702 | atomic_dec(&port->serial->interface->dev.power.usage_count); | ||
703 | } while ((urb = usb_get_from_anchor(&portdata->delayed))); | ||
704 | break; | ||
705 | } | ||
677 | } | 706 | } |
678 | } | 707 | } |
679 | 708 | ||