aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usb_wwan.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 18:04:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 18:04:26 -0400
commit971f115a50afbe409825c9f3399d5a3b9aca4381 (patch)
treecb42dc07a032e325f22b64d961587c081225c6d6 /drivers/usb/serial/usb_wwan.c
parent2e270d84223262a38d4755c61d55f5c73ea89e56 (diff)
parent500132a0f26ad7d9916102193cbc6c1b1becb373 (diff)
Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (172 commits) USB: Add support for SuperSpeed isoc endpoints xhci: Clean up cycle bit math used during stalls. xhci: Fix cycle bit calculation during stall handling. xhci: Update internal dequeue pointers after stalls. USB: Disable auto-suspend for USB 3.0 hubs. USB: Remove bogus USB_PORT_STAT_SUPER_SPEED symbol. xhci: Return canceled URBs immediately when host is halted. xhci: Fixes for suspend/resume of shared HCDs. xhci: Fix re-init on power loss after resume. xhci: Make roothub functions deal with device removal. xhci: Limit roothub ports to 15 USB3 & 31 USB2 ports. xhci: Return a USB 3.0 hub descriptor for USB3 roothub. xhci: Register second xHCI roothub. xhci: Change xhci_find_slot_id_by_port() API. xhci: Refactor bus suspend state into a struct. xhci: Index with a port array instead of PORTSC addresses. USB: Set usb_hcd->state and flags for shared roothubs. usb: Make core allocate resources per PCI-device. usb: Store bus type in usb_hcd, not in driver flags. usb: Change usb_hcd->bandwidth_mutex to a pointer. ...
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r--drivers/usb/serial/usb_wwan.c43
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}
662EXPORT_SYMBOL(usb_wwan_suspend); 670EXPORT_SYMBOL(usb_wwan_suspend);
663 671
672static 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
664static void play_delayed(struct usb_serial_port *port) 684static 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