From 87d65e54b6d5ff6ee905c4ade1e28f486ccfce8a Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 19 Jun 2008 14:20:18 +0200 Subject: USB: cdc-wdm cleanup - fixes an error with filling out control requests - increases grepability and error logging - fixes the short read code path Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/usb/class/cdc-wdm.c') diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 731db051070..3a656f8f993 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -28,8 +28,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.02" +#define DRIVER_VERSION "v0.03" #define DRIVER_AUTHOR "Oliver Neukum" +#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" static struct usb_device_id wdm_ids[] = { { @@ -205,7 +206,7 @@ static void wdm_int_callback(struct urb *urb) req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; req->wValue = 0; req->wIndex = desc->inum; - req->wLength = cpu_to_le16(desc->bMaxPacketSize0); + req->wLength = cpu_to_le16(desc->wMaxCommand); usb_fill_control_urb( desc->response, @@ -214,7 +215,7 @@ static void wdm_int_callback(struct urb *urb) usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), (unsigned char *)req, desc->inbuf, - desc->bMaxPacketSize0, + desc->wMaxCommand, wdm_in_callback, desc ); @@ -266,7 +267,7 @@ static void cleanup(struct wdm_device *desc) desc->sbuf, desc->validity->transfer_dma); usb_buffer_free(interface_to_usbdev(desc->intf), - desc->wMaxPacketSize, + desc->wMaxCommand, desc->inbuf, desc->response->transfer_dma); kfree(desc->orq); @@ -347,6 +348,7 @@ static ssize_t wdm_write if (rv < 0) { kfree(buf); clear_bit(WDM_IN_USE, &desc->flags); + err("Tx URB error: %d", rv); } else { dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", req->wIndex); @@ -418,6 +420,9 @@ retry: desc->ubuf[i] = desc->ubuf[i + cntr]; desc->length -= cntr; + /* in case we had outstanding data */ + if (!desc->length) + clear_bit(WDM_READ, &desc->flags); rv = cntr; err: @@ -735,6 +740,5 @@ module_init(wdm_init); module_exit(wdm_exit); MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION("USB Abstract Control Model driver for " - "USB WCM Device Management"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 17d80d562fd78a035e994afde88f354973e76236 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 24 Jun 2008 15:56:10 +0200 Subject: USB: autosuspend for cdc-wdm this patch implements - suspend/resume - aggressive autosuspend for the cdc-wdm driver - pre/post_reset Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 107 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 6 deletions(-) (limited to 'drivers/usb/class/cdc-wdm.c') diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 3a656f8f993..1103ce7016b 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -88,6 +88,7 @@ struct wdm_device { dma_addr_t ihandle; struct mutex wlock; struct mutex rlock; + struct mutex plock; wait_queue_head_t wait; struct work_struct rxwork; int werr; @@ -248,6 +249,7 @@ exit: static void kill_urbs(struct wdm_device *desc) { + /* the order here is essential */ usb_kill_urb(desc->command); usb_kill_urb(desc->validity); usb_kill_urb(desc->response); @@ -300,6 +302,9 @@ static ssize_t wdm_write if (r) goto outnl; + r = usb_autopm_get_interface(desc->intf); + if (r < 0) + goto outnp; r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); if (r < 0) @@ -354,6 +359,8 @@ static ssize_t wdm_write req->wIndex); } out: + usb_autopm_put_interface(desc->intf); +outnp: mutex_unlock(&desc->wlock); outnl: return rv < 0 ? rv : count; @@ -378,6 +385,11 @@ retry: rv = wait_event_interruptible(desc->wait, test_bit(WDM_READ, &desc->flags)); + if (test_bit(WDM_DISCONNECTING, &desc->flags)) { + rv = -ENODEV; + goto err; + } + usb_mark_last_busy(interface_to_usbdev(desc->intf)); if (rv < 0) { rv = -ERESTARTSYS; goto err; @@ -485,18 +497,28 @@ static int wdm_open(struct inode *inode, struct file *file) if (test_bit(WDM_DISCONNECTING, &desc->flags)) goto out; - desc->count++; + ; file->private_data = desc; - rv = usb_submit_urb(desc->validity, GFP_KERNEL); - + rv = usb_autopm_get_interface(desc->intf); if (rv < 0) { - desc->count--; - err("Error submitting int urb - %d", rv); + err("Error autopm - %d", rv); goto out; } - rv = 0; + intf->needs_remote_wakeup = 1; + mutex_lock(&desc->plock); + if (!desc->count++) { + rv = usb_submit_urb(desc->validity, GFP_KERNEL); + if (rv < 0) { + desc->count--; + err("Error submitting int urb - %d", rv); + } + } else { + rv = 0; + } + mutex_unlock(&desc->plock); + usb_autopm_put_interface(desc->intf); out: mutex_unlock(&wdm_mutex); return rv; @@ -507,10 +529,15 @@ static int wdm_release(struct inode *inode, struct file *file) struct wdm_device *desc = file->private_data; mutex_lock(&wdm_mutex); + mutex_lock(&desc->plock); desc->count--; + mutex_unlock(&desc->plock); + if (!desc->count) { dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); kill_urbs(desc); + if (!test_bit(WDM_DISCONNECTING, &desc->flags)) + desc->intf->needs_remote_wakeup = 0; } mutex_unlock(&wdm_mutex); return 0; @@ -602,6 +629,7 @@ next_desc: goto out; mutex_init(&desc->wlock); mutex_init(&desc->rlock); + mutex_init(&desc->plock); spin_lock_init(&desc->iuspin); init_waitqueue_head(&desc->wait); desc->wMaxCommand = maxcom; @@ -703,6 +731,7 @@ static void wdm_disconnect(struct usb_interface *intf) spin_lock_irqsave(&desc->iuspin, flags); set_bit(WDM_DISCONNECTING, &desc->flags); set_bit(WDM_READ, &desc->flags); + /* to terminate pending flushes */ clear_bit(WDM_IN_USE, &desc->flags); spin_unlock_irqrestore(&desc->iuspin, flags); cancel_work_sync(&desc->rxwork); @@ -713,11 +742,77 @@ static void wdm_disconnect(struct usb_interface *intf) mutex_unlock(&wdm_mutex); } +static int wdm_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct wdm_device *desc = usb_get_intfdata(intf); + int rv = 0; + + dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); + + mutex_lock(&desc->plock); + if (interface_to_usbdev(desc->intf)->auto_pm && test_bit(WDM_IN_USE, &desc->flags)) { + rv = -EBUSY; + } else { + cancel_work_sync(&desc->rxwork); + kill_urbs(desc); + } + mutex_unlock(&desc->plock); + + return rv; +} + +static int recover_from_urb_loss(struct wdm_device *desc) +{ + int rv = 0; + + if (desc->count) { + rv = usb_submit_urb(desc->validity, GFP_NOIO); + if (rv < 0) + err("Error resume submitting int urb - %d", rv); + } + return rv; +} +static int wdm_resume(struct usb_interface *intf) +{ + struct wdm_device *desc = usb_get_intfdata(intf); + int rv; + + dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); + mutex_lock(&desc->plock); + rv = recover_from_urb_loss(desc); + mutex_unlock(&desc->plock); + return rv; +} + +static int wdm_pre_reset(struct usb_interface *intf) +{ + struct wdm_device *desc = usb_get_intfdata(intf); + + mutex_lock(&desc->plock); + return 0; +} + +static int wdm_post_reset(struct usb_interface *intf) +{ + struct wdm_device *desc = usb_get_intfdata(intf); + int rv; + + rv = recover_from_urb_loss(desc); + mutex_unlock(&desc->plock); + return 0; +} + static struct usb_driver wdm_driver = { .name = "cdc_wdm", .probe = wdm_probe, .disconnect = wdm_disconnect, + .suspend = wdm_suspend, + .resume = wdm_resume, + .reset_resume = wdm_resume, + .pre_reset = wdm_pre_reset, + .post_reset = wdm_post_reset, .id_table = wdm_ids, + .supports_autosuspend = 1, }; /* --- low level module stuff --- */ -- cgit v1.2.3-70-g09d2 From 357585892e56f7c7bec4a9c8dfaf90257c8756c6 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 1 Jul 2008 19:10:08 +0200 Subject: USB: fix build error in cdc-acm for CONFIG_PM=n Here's the fix. cdc-wdm has the same problem. The fix is the same. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 7 +++++++ drivers/usb/class/cdc-wdm.c | 4 ++++ 2 files changed, 11 insertions(+) (limited to 'drivers/usb/class/cdc-wdm.c') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 93b28ee8e8b..95ae6377d7e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1255,6 +1255,7 @@ static void acm_disconnect(struct usb_interface *intf) tty_hangup(acm->tty); } +#ifdef CONFIG_PM static int acm_suspend(struct usb_interface *intf, pm_message_t message) { struct acm *acm = usb_get_intfdata(intf); @@ -1320,6 +1321,8 @@ err_out: mutex_unlock(&acm->mutex); return rv; } + +#endif /* CONFIG_PM */ /* * USB driver structure. */ @@ -1375,10 +1378,14 @@ static struct usb_driver acm_driver = { .name = "cdc_acm", .probe = acm_probe, .disconnect = acm_disconnect, +#ifdef CONFIG_PM .suspend = acm_suspend, .resume = acm_resume, +#endif .id_table = acm_ids, +#ifdef CONFIG_PM .supports_autosuspend = 1, +#endif }; /* diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 1103ce7016b..7e8e1235e4e 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -750,12 +750,16 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); mutex_lock(&desc->plock); +#ifdef CONFIG_PM if (interface_to_usbdev(desc->intf)->auto_pm && test_bit(WDM_IN_USE, &desc->flags)) { rv = -EBUSY; } else { +#endif cancel_work_sync(&desc->rxwork); kill_urbs(desc); +#ifdef CONFIG_PM } +#endif mutex_unlock(&desc->plock); return rv; -- cgit v1.2.3-70-g09d2