diff options
author | Seshendra Gadagottu <sgadagottu@nvidia.com> | 2011-12-12 23:32:01 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 01:14:46 -0700 |
commit | 2a457b42121be3b28f2930e9bf658f3bffb9b6c7 (patch) | |
tree | 82681101cb36f72a457e946ade4af0d1663fd425 | |
parent | cb07622b366e7b8cdd6302f719ce3b5deb4db757 (diff) |
arm: usb: cdc: Fix cdc-acm auto pm issues
Buffer usb urb request during suspend/resuming and send
it after resume is done. Make "needs_remote_wakeup = 0"
to pass auto suspend check.
BUG 909614
Change-Id: Ia966a8dc8ab6f808220562f08b072c66bb4678a1
Reviewed-on: http://git-master/r/70166
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>
Rebase-Id: Rafd8bfdf2db05f3eb2ff0bab95d331a3a37add03
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 28 | ||||
-rw-r--r-- | drivers/usb/class/cdc-acm.h | 1 |
2 files changed, 26 insertions, 3 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3cc7f1bb89b1..4d5c176636d7 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -205,7 +205,6 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb) wb->urb->transfer_dma = wb->dmah; wb->urb->transfer_buffer_length = wb->len; wb->urb->dev = acm->dev; - rc = usb_submit_urb(wb->urb, GFP_ATOMIC); if (rc < 0) { dev_err(&acm->data->dev, @@ -233,6 +232,15 @@ static int acm_write_start(struct acm *acm, int wbn) acm->susp_count); usb_autopm_get_interface_async(acm->control); if (acm->susp_count) { +#ifdef CONFIG_PM + printk("%s buffer urb\n", __func__); + acm->transmitting++; + wb->urb->transfer_buffer = wb->buf; + wb->urb->transfer_dma = wb->dmah; + wb->urb->transfer_buffer_length = wb->len; + wb->urb->dev = acm->dev; + usb_anchor_urb(wb->urb, &acm->deferred); +#endif if (!acm->delayed_wb) acm->delayed_wb = wb; else @@ -532,7 +540,7 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) * memory is really nasty... */ set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); - acm->control->needs_remote_wakeup = 1; + acm->control->needs_remote_wakeup = 0; acm->ctrlurb->dev = acm->dev; if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { @@ -1181,6 +1189,9 @@ made_compressed_probe: acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; INIT_WORK(&acm->work, acm_softint); + init_usb_anchor(&acm->deferred); + init_waitqueue_head(&acm->drain_wait); + spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); @@ -1466,6 +1477,7 @@ static int acm_resume(struct usb_interface *intf) struct acm *acm = usb_get_intfdata(intf); struct acm_wb *wb; int rv = 0; + struct urb *res; int cnt; spin_lock_irq(&acm->read_lock); @@ -1476,9 +1488,18 @@ static int acm_resume(struct usb_interface *intf) if (cnt) return 0; +#ifdef CONFIG_PM + while ((res = usb_get_from_anchor(&acm->deferred))) { + printk("%s process buffered request \n", __func__); + rv = usb_submit_urb(res, GFP_ATOMIC); + if (rv < 0) { + dbg("usb_submit_urb(pending request) failed: %d", rv); + } + } +#endif + if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); - spin_lock_irq(&acm->write_lock); if (acm->delayed_wb) { wb = acm->delayed_wb; @@ -1489,6 +1510,7 @@ static int acm_resume(struct usb_interface *intf) spin_unlock_irq(&acm->write_lock); } + /* * delayed error checking because we must * do the write path at all cost diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index fd5ba0145333..603c8725c153 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -119,6 +119,7 @@ struct acm { unsigned int no_hangup_in_reset_resume:1; /* do not call tty_hangup in acm_reset_resume */ u8 bInterval; struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ + struct usb_anchor deferred; }; #define CDC_DATA_INTERFACE_TYPE 0x0a |