summaryrefslogtreecommitdiff
path: root/drivers/usb/class
diff options
context:
space:
mode:
authorSeshendra Gadagottu <sgadagottu@nvidia.com>2011-12-12 23:32:01 +0530
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-21 12:06:27 +0530
commit7c43ad504033d90c14c13fef72c924a74d6db981 (patch)
tree7f48da63bf1e57e8501467f1bde357f5c77e485c /drivers/usb/class
parent924cfdbab3f683b3c3210c950e5efe70734ebfdd (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>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r--drivers/usb/class/cdc-acm.c30
-rw-r--r--drivers/usb/class/cdc-acm.h1
2 files changed, 28 insertions, 3 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 991089eee117..3d149f359a70 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -155,7 +155,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,
@@ -183,6 +182,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
@@ -476,7 +484,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
if (usb_autopm_get_interface(acm->control) < 0)
goto early_bail;
else
- acm->control->needs_remote_wakeup = 1;
+ acm->control->needs_remote_wakeup = 0;
mutex_lock(&acm->mutex);
if (acm->port.count++) {
@@ -1080,6 +1088,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);
@@ -1349,6 +1360,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);
@@ -1359,10 +1371,21 @@ static int acm_resume(struct usb_interface *intf)
if (cnt)
return 0;
+
mutex_lock(&acm->mutex);
+
+#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 (acm->port.count) {
rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
-
spin_lock_irq(&acm->write_lock);
if (acm->delayed_wb) {
wb = acm->delayed_wb;
@@ -1373,6 +1396,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 7d6a4e29563d..ec59fda787fe 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -118,6 +118,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