aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class/cdc-wdm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/class/cdc-wdm.c')
-rw-r--r--drivers/usb/class/cdc-wdm.c127
1 files changed, 115 insertions, 12 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 731db051070a..7e8e1235e4e5 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -28,8 +28,9 @@
28/* 28/*
29 * Version Information 29 * Version Information
30 */ 30 */
31#define DRIVER_VERSION "v0.02" 31#define DRIVER_VERSION "v0.03"
32#define DRIVER_AUTHOR "Oliver Neukum" 32#define DRIVER_AUTHOR "Oliver Neukum"
33#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
33 34
34static struct usb_device_id wdm_ids[] = { 35static struct usb_device_id wdm_ids[] = {
35 { 36 {
@@ -87,6 +88,7 @@ struct wdm_device {
87 dma_addr_t ihandle; 88 dma_addr_t ihandle;
88 struct mutex wlock; 89 struct mutex wlock;
89 struct mutex rlock; 90 struct mutex rlock;
91 struct mutex plock;
90 wait_queue_head_t wait; 92 wait_queue_head_t wait;
91 struct work_struct rxwork; 93 struct work_struct rxwork;
92 int werr; 94 int werr;
@@ -205,7 +207,7 @@ static void wdm_int_callback(struct urb *urb)
205 req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; 207 req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
206 req->wValue = 0; 208 req->wValue = 0;
207 req->wIndex = desc->inum; 209 req->wIndex = desc->inum;
208 req->wLength = cpu_to_le16(desc->bMaxPacketSize0); 210 req->wLength = cpu_to_le16(desc->wMaxCommand);
209 211
210 usb_fill_control_urb( 212 usb_fill_control_urb(
211 desc->response, 213 desc->response,
@@ -214,7 +216,7 @@ static void wdm_int_callback(struct urb *urb)
214 usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), 216 usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
215 (unsigned char *)req, 217 (unsigned char *)req,
216 desc->inbuf, 218 desc->inbuf,
217 desc->bMaxPacketSize0, 219 desc->wMaxCommand,
218 wdm_in_callback, 220 wdm_in_callback,
219 desc 221 desc
220 ); 222 );
@@ -247,6 +249,7 @@ exit:
247 249
248static void kill_urbs(struct wdm_device *desc) 250static void kill_urbs(struct wdm_device *desc)
249{ 251{
252 /* the order here is essential */
250 usb_kill_urb(desc->command); 253 usb_kill_urb(desc->command);
251 usb_kill_urb(desc->validity); 254 usb_kill_urb(desc->validity);
252 usb_kill_urb(desc->response); 255 usb_kill_urb(desc->response);
@@ -266,7 +269,7 @@ static void cleanup(struct wdm_device *desc)
266 desc->sbuf, 269 desc->sbuf,
267 desc->validity->transfer_dma); 270 desc->validity->transfer_dma);
268 usb_buffer_free(interface_to_usbdev(desc->intf), 271 usb_buffer_free(interface_to_usbdev(desc->intf),
269 desc->wMaxPacketSize, 272 desc->wMaxCommand,
270 desc->inbuf, 273 desc->inbuf,
271 desc->response->transfer_dma); 274 desc->response->transfer_dma);
272 kfree(desc->orq); 275 kfree(desc->orq);
@@ -299,6 +302,9 @@ static ssize_t wdm_write
299 if (r) 302 if (r)
300 goto outnl; 303 goto outnl;
301 304
305 r = usb_autopm_get_interface(desc->intf);
306 if (r < 0)
307 goto outnp;
302 r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, 308 r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
303 &desc->flags)); 309 &desc->flags));
304 if (r < 0) 310 if (r < 0)
@@ -347,11 +353,14 @@ static ssize_t wdm_write
347 if (rv < 0) { 353 if (rv < 0) {
348 kfree(buf); 354 kfree(buf);
349 clear_bit(WDM_IN_USE, &desc->flags); 355 clear_bit(WDM_IN_USE, &desc->flags);
356 err("Tx URB error: %d", rv);
350 } else { 357 } else {
351 dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", 358 dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d",
352 req->wIndex); 359 req->wIndex);
353 } 360 }
354out: 361out:
362 usb_autopm_put_interface(desc->intf);
363outnp:
355 mutex_unlock(&desc->wlock); 364 mutex_unlock(&desc->wlock);
356outnl: 365outnl:
357 return rv < 0 ? rv : count; 366 return rv < 0 ? rv : count;
@@ -376,6 +385,11 @@ retry:
376 rv = wait_event_interruptible(desc->wait, 385 rv = wait_event_interruptible(desc->wait,
377 test_bit(WDM_READ, &desc->flags)); 386 test_bit(WDM_READ, &desc->flags));
378 387
388 if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
389 rv = -ENODEV;
390 goto err;
391 }
392 usb_mark_last_busy(interface_to_usbdev(desc->intf));
379 if (rv < 0) { 393 if (rv < 0) {
380 rv = -ERESTARTSYS; 394 rv = -ERESTARTSYS;
381 goto err; 395 goto err;
@@ -418,6 +432,9 @@ retry:
418 desc->ubuf[i] = desc->ubuf[i + cntr]; 432 desc->ubuf[i] = desc->ubuf[i + cntr];
419 433
420 desc->length -= cntr; 434 desc->length -= cntr;
435 /* in case we had outstanding data */
436 if (!desc->length)
437 clear_bit(WDM_READ, &desc->flags);
421 rv = cntr; 438 rv = cntr;
422 439
423err: 440err:
@@ -480,18 +497,28 @@ static int wdm_open(struct inode *inode, struct file *file)
480 if (test_bit(WDM_DISCONNECTING, &desc->flags)) 497 if (test_bit(WDM_DISCONNECTING, &desc->flags))
481 goto out; 498 goto out;
482 499
483 desc->count++; 500 ;
484 file->private_data = desc; 501 file->private_data = desc;
485 502
486 rv = usb_submit_urb(desc->validity, GFP_KERNEL); 503 rv = usb_autopm_get_interface(desc->intf);
487
488 if (rv < 0) { 504 if (rv < 0) {
489 desc->count--; 505 err("Error autopm - %d", rv);
490 err("Error submitting int urb - %d", rv);
491 goto out; 506 goto out;
492 } 507 }
493 rv = 0; 508 intf->needs_remote_wakeup = 1;
494 509
510 mutex_lock(&desc->plock);
511 if (!desc->count++) {
512 rv = usb_submit_urb(desc->validity, GFP_KERNEL);
513 if (rv < 0) {
514 desc->count--;
515 err("Error submitting int urb - %d", rv);
516 }
517 } else {
518 rv = 0;
519 }
520 mutex_unlock(&desc->plock);
521 usb_autopm_put_interface(desc->intf);
495out: 522out:
496 mutex_unlock(&wdm_mutex); 523 mutex_unlock(&wdm_mutex);
497 return rv; 524 return rv;
@@ -502,10 +529,15 @@ static int wdm_release(struct inode *inode, struct file *file)
502 struct wdm_device *desc = file->private_data; 529 struct wdm_device *desc = file->private_data;
503 530
504 mutex_lock(&wdm_mutex); 531 mutex_lock(&wdm_mutex);
532 mutex_lock(&desc->plock);
505 desc->count--; 533 desc->count--;
534 mutex_unlock(&desc->plock);
535
506 if (!desc->count) { 536 if (!desc->count) {
507 dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); 537 dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
508 kill_urbs(desc); 538 kill_urbs(desc);
539 if (!test_bit(WDM_DISCONNECTING, &desc->flags))
540 desc->intf->needs_remote_wakeup = 0;
509 } 541 }
510 mutex_unlock(&wdm_mutex); 542 mutex_unlock(&wdm_mutex);
511 return 0; 543 return 0;
@@ -597,6 +629,7 @@ next_desc:
597 goto out; 629 goto out;
598 mutex_init(&desc->wlock); 630 mutex_init(&desc->wlock);
599 mutex_init(&desc->rlock); 631 mutex_init(&desc->rlock);
632 mutex_init(&desc->plock);
600 spin_lock_init(&desc->iuspin); 633 spin_lock_init(&desc->iuspin);
601 init_waitqueue_head(&desc->wait); 634 init_waitqueue_head(&desc->wait);
602 desc->wMaxCommand = maxcom; 635 desc->wMaxCommand = maxcom;
@@ -698,6 +731,7 @@ static void wdm_disconnect(struct usb_interface *intf)
698 spin_lock_irqsave(&desc->iuspin, flags); 731 spin_lock_irqsave(&desc->iuspin, flags);
699 set_bit(WDM_DISCONNECTING, &desc->flags); 732 set_bit(WDM_DISCONNECTING, &desc->flags);
700 set_bit(WDM_READ, &desc->flags); 733 set_bit(WDM_READ, &desc->flags);
734 /* to terminate pending flushes */
701 clear_bit(WDM_IN_USE, &desc->flags); 735 clear_bit(WDM_IN_USE, &desc->flags);
702 spin_unlock_irqrestore(&desc->iuspin, flags); 736 spin_unlock_irqrestore(&desc->iuspin, flags);
703 cancel_work_sync(&desc->rxwork); 737 cancel_work_sync(&desc->rxwork);
@@ -708,11 +742,81 @@ static void wdm_disconnect(struct usb_interface *intf)
708 mutex_unlock(&wdm_mutex); 742 mutex_unlock(&wdm_mutex);
709} 743}
710 744
745static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
746{
747 struct wdm_device *desc = usb_get_intfdata(intf);
748 int rv = 0;
749
750 dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
751
752 mutex_lock(&desc->plock);
753#ifdef CONFIG_PM
754 if (interface_to_usbdev(desc->intf)->auto_pm && test_bit(WDM_IN_USE, &desc->flags)) {
755 rv = -EBUSY;
756 } else {
757#endif
758 cancel_work_sync(&desc->rxwork);
759 kill_urbs(desc);
760#ifdef CONFIG_PM
761 }
762#endif
763 mutex_unlock(&desc->plock);
764
765 return rv;
766}
767
768static int recover_from_urb_loss(struct wdm_device *desc)
769{
770 int rv = 0;
771
772 if (desc->count) {
773 rv = usb_submit_urb(desc->validity, GFP_NOIO);
774 if (rv < 0)
775 err("Error resume submitting int urb - %d", rv);
776 }
777 return rv;
778}
779static int wdm_resume(struct usb_interface *intf)
780{
781 struct wdm_device *desc = usb_get_intfdata(intf);
782 int rv;
783
784 dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
785 mutex_lock(&desc->plock);
786 rv = recover_from_urb_loss(desc);
787 mutex_unlock(&desc->plock);
788 return rv;
789}
790
791static int wdm_pre_reset(struct usb_interface *intf)
792{
793 struct wdm_device *desc = usb_get_intfdata(intf);
794
795 mutex_lock(&desc->plock);
796 return 0;
797}
798
799static int wdm_post_reset(struct usb_interface *intf)
800{
801 struct wdm_device *desc = usb_get_intfdata(intf);
802 int rv;
803
804 rv = recover_from_urb_loss(desc);
805 mutex_unlock(&desc->plock);
806 return 0;
807}
808
711static struct usb_driver wdm_driver = { 809static struct usb_driver wdm_driver = {
712 .name = "cdc_wdm", 810 .name = "cdc_wdm",
713 .probe = wdm_probe, 811 .probe = wdm_probe,
714 .disconnect = wdm_disconnect, 812 .disconnect = wdm_disconnect,
813 .suspend = wdm_suspend,
814 .resume = wdm_resume,
815 .reset_resume = wdm_resume,
816 .pre_reset = wdm_pre_reset,
817 .post_reset = wdm_post_reset,
715 .id_table = wdm_ids, 818 .id_table = wdm_ids,
819 .supports_autosuspend = 1,
716}; 820};
717 821
718/* --- low level module stuff --- */ 822/* --- low level module stuff --- */
@@ -735,6 +839,5 @@ module_init(wdm_init);
735module_exit(wdm_exit); 839module_exit(wdm_exit);
736 840
737MODULE_AUTHOR(DRIVER_AUTHOR); 841MODULE_AUTHOR(DRIVER_AUTHOR);
738MODULE_DESCRIPTION("USB Abstract Control Model driver for " 842MODULE_DESCRIPTION(DRIVER_DESC);
739 "USB WCM Device Management");
740MODULE_LICENSE("GPL"); 843MODULE_LICENSE("GPL");