summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeshendra Gadagottu <sgadagottu@nvidia.com>2011-12-12 23:32:01 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 01:14:46 -0700
commit2a457b42121be3b28f2930e9bf658f3bffb9b6c7 (patch)
tree82681101cb36f72a457e946ade4af0d1663fd425
parentcb07622b366e7b8cdd6302f719ce3b5deb4db757 (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.c28
-rw-r--r--drivers/usb/class/cdc-acm.h1
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