diff options
author | Bjørn Mork <bjorn@mork.no> | 2012-01-16 06:41:48 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2012-01-24 15:17:29 -0500 |
commit | e8537bd2c4f325a4796da33564ddcef9489b7feb (patch) | |
tree | 50d5d643591ed620197c0d7bba8263acb1afba7f /drivers/usb/class | |
parent | c428b70c1e115c5649707a602742e34130d19428 (diff) |
USB: cdc-wdm: use two mutexes to allow simultaneous read and write
using a separate read and write mutex for locking is sufficient to make the
driver accept simultaneous read and write. This improves useability a lot.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Cc: stable <stable@vger.kernel.org>
Cc: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/cdc-wdm.c | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 1f6b5c8394b4..023d271c2614 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
@@ -88,7 +88,8 @@ struct wdm_device { | |||
88 | int count; | 88 | int count; |
89 | dma_addr_t shandle; | 89 | dma_addr_t shandle; |
90 | dma_addr_t ihandle; | 90 | dma_addr_t ihandle; |
91 | struct mutex lock; | 91 | struct mutex wlock; |
92 | struct mutex rlock; | ||
92 | wait_queue_head_t wait; | 93 | wait_queue_head_t wait; |
93 | struct work_struct rxwork; | 94 | struct work_struct rxwork; |
94 | int werr; | 95 | int werr; |
@@ -323,7 +324,7 @@ static ssize_t wdm_write | |||
323 | } | 324 | } |
324 | 325 | ||
325 | /* concurrent writes and disconnect */ | 326 | /* concurrent writes and disconnect */ |
326 | r = mutex_lock_interruptible(&desc->lock); | 327 | r = mutex_lock_interruptible(&desc->wlock); |
327 | rv = -ERESTARTSYS; | 328 | rv = -ERESTARTSYS; |
328 | if (r) { | 329 | if (r) { |
329 | kfree(buf); | 330 | kfree(buf); |
@@ -386,7 +387,7 @@ static ssize_t wdm_write | |||
386 | out: | 387 | out: |
387 | usb_autopm_put_interface(desc->intf); | 388 | usb_autopm_put_interface(desc->intf); |
388 | outnp: | 389 | outnp: |
389 | mutex_unlock(&desc->lock); | 390 | mutex_unlock(&desc->wlock); |
390 | outnl: | 391 | outnl: |
391 | return rv < 0 ? rv : count; | 392 | return rv < 0 ? rv : count; |
392 | } | 393 | } |
@@ -399,7 +400,7 @@ static ssize_t wdm_read | |||
399 | struct wdm_device *desc = file->private_data; | 400 | struct wdm_device *desc = file->private_data; |
400 | 401 | ||
401 | 402 | ||
402 | rv = mutex_lock_interruptible(&desc->lock); /*concurrent reads */ | 403 | rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ |
403 | if (rv < 0) | 404 | if (rv < 0) |
404 | return -ERESTARTSYS; | 405 | return -ERESTARTSYS; |
405 | 406 | ||
@@ -476,7 +477,7 @@ retry: | |||
476 | rv = cntr; | 477 | rv = cntr; |
477 | 478 | ||
478 | err: | 479 | err: |
479 | mutex_unlock(&desc->lock); | 480 | mutex_unlock(&desc->rlock); |
480 | return rv; | 481 | return rv; |
481 | } | 482 | } |
482 | 483 | ||
@@ -542,7 +543,8 @@ static int wdm_open(struct inode *inode, struct file *file) | |||
542 | } | 543 | } |
543 | intf->needs_remote_wakeup = 1; | 544 | intf->needs_remote_wakeup = 1; |
544 | 545 | ||
545 | mutex_lock(&desc->lock); | 546 | /* using write lock to protect desc->count */ |
547 | mutex_lock(&desc->wlock); | ||
546 | if (!desc->count++) { | 548 | if (!desc->count++) { |
547 | desc->werr = 0; | 549 | desc->werr = 0; |
548 | desc->rerr = 0; | 550 | desc->rerr = 0; |
@@ -555,7 +557,7 @@ static int wdm_open(struct inode *inode, struct file *file) | |||
555 | } else { | 557 | } else { |
556 | rv = 0; | 558 | rv = 0; |
557 | } | 559 | } |
558 | mutex_unlock(&desc->lock); | 560 | mutex_unlock(&desc->wlock); |
559 | usb_autopm_put_interface(desc->intf); | 561 | usb_autopm_put_interface(desc->intf); |
560 | out: | 562 | out: |
561 | mutex_unlock(&wdm_mutex); | 563 | mutex_unlock(&wdm_mutex); |
@@ -567,9 +569,11 @@ static int wdm_release(struct inode *inode, struct file *file) | |||
567 | struct wdm_device *desc = file->private_data; | 569 | struct wdm_device *desc = file->private_data; |
568 | 570 | ||
569 | mutex_lock(&wdm_mutex); | 571 | mutex_lock(&wdm_mutex); |
570 | mutex_lock(&desc->lock); | 572 | |
573 | /* using write lock to protect desc->count */ | ||
574 | mutex_lock(&desc->wlock); | ||
571 | desc->count--; | 575 | desc->count--; |
572 | mutex_unlock(&desc->lock); | 576 | mutex_unlock(&desc->wlock); |
573 | 577 | ||
574 | if (!desc->count) { | 578 | if (!desc->count) { |
575 | dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); | 579 | dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); |
@@ -667,7 +671,8 @@ next_desc: | |||
667 | desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); | 671 | desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); |
668 | if (!desc) | 672 | if (!desc) |
669 | goto out; | 673 | goto out; |
670 | mutex_init(&desc->lock); | 674 | mutex_init(&desc->rlock); |
675 | mutex_init(&desc->wlock); | ||
671 | spin_lock_init(&desc->iuspin); | 676 | spin_lock_init(&desc->iuspin); |
672 | init_waitqueue_head(&desc->wait); | 677 | init_waitqueue_head(&desc->wait); |
673 | desc->wMaxCommand = maxcom; | 678 | desc->wMaxCommand = maxcom; |
@@ -781,10 +786,12 @@ static void wdm_disconnect(struct usb_interface *intf) | |||
781 | /* to terminate pending flushes */ | 786 | /* to terminate pending flushes */ |
782 | clear_bit(WDM_IN_USE, &desc->flags); | 787 | clear_bit(WDM_IN_USE, &desc->flags); |
783 | spin_unlock_irqrestore(&desc->iuspin, flags); | 788 | spin_unlock_irqrestore(&desc->iuspin, flags); |
784 | mutex_lock(&desc->lock); | 789 | mutex_lock(&desc->rlock); |
790 | mutex_lock(&desc->wlock); | ||
785 | kill_urbs(desc); | 791 | kill_urbs(desc); |
786 | cancel_work_sync(&desc->rxwork); | 792 | cancel_work_sync(&desc->rxwork); |
787 | mutex_unlock(&desc->lock); | 793 | mutex_unlock(&desc->wlock); |
794 | mutex_unlock(&desc->rlock); | ||
788 | wake_up_all(&desc->wait); | 795 | wake_up_all(&desc->wait); |
789 | if (!desc->count) | 796 | if (!desc->count) |
790 | cleanup(desc); | 797 | cleanup(desc); |
@@ -800,8 +807,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) | |||
800 | dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); | 807 | dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); |
801 | 808 | ||
802 | /* if this is an autosuspend the caller does the locking */ | 809 | /* if this is an autosuspend the caller does the locking */ |
803 | if (!PMSG_IS_AUTO(message)) | 810 | if (!PMSG_IS_AUTO(message)) { |
804 | mutex_lock(&desc->lock); | 811 | mutex_lock(&desc->rlock); |
812 | mutex_lock(&desc->wlock); | ||
813 | } | ||
805 | spin_lock_irq(&desc->iuspin); | 814 | spin_lock_irq(&desc->iuspin); |
806 | 815 | ||
807 | if (PMSG_IS_AUTO(message) && | 816 | if (PMSG_IS_AUTO(message) && |
@@ -817,8 +826,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) | |||
817 | kill_urbs(desc); | 826 | kill_urbs(desc); |
818 | cancel_work_sync(&desc->rxwork); | 827 | cancel_work_sync(&desc->rxwork); |
819 | } | 828 | } |
820 | if (!PMSG_IS_AUTO(message)) | 829 | if (!PMSG_IS_AUTO(message)) { |
821 | mutex_unlock(&desc->lock); | 830 | mutex_unlock(&desc->wlock); |
831 | mutex_unlock(&desc->rlock); | ||
832 | } | ||
822 | 833 | ||
823 | return rv; | 834 | return rv; |
824 | } | 835 | } |
@@ -856,7 +867,8 @@ static int wdm_pre_reset(struct usb_interface *intf) | |||
856 | { | 867 | { |
857 | struct wdm_device *desc = usb_get_intfdata(intf); | 868 | struct wdm_device *desc = usb_get_intfdata(intf); |
858 | 869 | ||
859 | mutex_lock(&desc->lock); | 870 | mutex_lock(&desc->rlock); |
871 | mutex_lock(&desc->wlock); | ||
860 | kill_urbs(desc); | 872 | kill_urbs(desc); |
861 | 873 | ||
862 | /* | 874 | /* |
@@ -878,7 +890,8 @@ static int wdm_post_reset(struct usb_interface *intf) | |||
878 | int rv; | 890 | int rv; |
879 | 891 | ||
880 | rv = recover_from_urb_loss(desc); | 892 | rv = recover_from_urb_loss(desc); |
881 | mutex_unlock(&desc->lock); | 893 | mutex_unlock(&desc->wlock); |
894 | mutex_unlock(&desc->rlock); | ||
882 | return 0; | 895 | return 0; |
883 | } | 896 | } |
884 | 897 | ||