aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class/cdc-wdm.c
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2010-02-27 14:56:47 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-19 10:24:17 -0400
commitd93d16e9aa58887feadd999ea26b7b8139e98b56 (patch)
tree47cd5e95bee9ccd52aa5ccfff4c87af78d605ad7 /drivers/usb/class/cdc-wdm.c
parent62e6685470fb04fb7688ecef96c39160498721d5 (diff)
usb: cdc-wdm: Fix order in disconnect and fix locking
- as the callback can schedule work, URBs must be killed first - if the driver causes an autoresume, the caller must handle locking Signed-off-by: Oliver Neukum <neukum@b1-systems.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/class/cdc-wdm.c')
-rw-r--r--drivers/usb/class/cdc-wdm.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 07c12974fe14..b57490508860 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -776,9 +776,9 @@ static void wdm_disconnect(struct usb_interface *intf)
776 /* to terminate pending flushes */ 776 /* to terminate pending flushes */
777 clear_bit(WDM_IN_USE, &desc->flags); 777 clear_bit(WDM_IN_USE, &desc->flags);
778 spin_unlock_irqrestore(&desc->iuspin, flags); 778 spin_unlock_irqrestore(&desc->iuspin, flags);
779 cancel_work_sync(&desc->rxwork);
780 mutex_lock(&desc->lock); 779 mutex_lock(&desc->lock);
781 kill_urbs(desc); 780 kill_urbs(desc);
781 cancel_work_sync(&desc->rxwork);
782 mutex_unlock(&desc->lock); 782 mutex_unlock(&desc->lock);
783 wake_up_all(&desc->wait); 783 wake_up_all(&desc->wait);
784 if (!desc->count) 784 if (!desc->count)
@@ -786,6 +786,7 @@ static void wdm_disconnect(struct usb_interface *intf)
786 mutex_unlock(&wdm_mutex); 786 mutex_unlock(&wdm_mutex);
787} 787}
788 788
789#ifdef CONFIG_PM
789static int wdm_suspend(struct usb_interface *intf, pm_message_t message) 790static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
790{ 791{
791 struct wdm_device *desc = usb_get_intfdata(intf); 792 struct wdm_device *desc = usb_get_intfdata(intf);
@@ -793,27 +794,30 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
793 794
794 dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); 795 dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
795 796
796 mutex_lock(&desc->lock); 797 /* if this is an autosuspend the caller does the locking */
798 if (!(message.event & PM_EVENT_AUTO))
799 mutex_lock(&desc->lock);
797 spin_lock_irq(&desc->iuspin); 800 spin_lock_irq(&desc->iuspin);
798#ifdef CONFIG_PM 801
799 if ((message.event & PM_EVENT_AUTO) && 802 if ((message.event & PM_EVENT_AUTO) &&
800 (test_bit(WDM_IN_USE, &desc->flags) 803 (test_bit(WDM_IN_USE, &desc->flags)
801 || test_bit(WDM_RESPONDING, &desc->flags))) { 804 || test_bit(WDM_RESPONDING, &desc->flags))) {
802 spin_unlock_irq(&desc->iuspin); 805 spin_unlock_irq(&desc->iuspin);
803 rv = -EBUSY; 806 rv = -EBUSY;
804 } else { 807 } else {
805#endif 808
806 set_bit(WDM_SUSPENDING, &desc->flags); 809 set_bit(WDM_SUSPENDING, &desc->flags);
807 spin_unlock_irq(&desc->iuspin); 810 spin_unlock_irq(&desc->iuspin);
808 cancel_work_sync(&desc->rxwork); 811 /* callback submits work - order is essential */
809 kill_urbs(desc); 812 kill_urbs(desc);
810#ifdef CONFIG_PM 813 cancel_work_sync(&desc->rxwork);
811 } 814 }
812#endif 815 if (!(message.event & PM_EVENT_AUTO))
813 mutex_unlock(&desc->lock); 816 mutex_unlock(&desc->lock);
814 817
815 return rv; 818 return rv;
816} 819}
820#endif
817 821
818static int recover_from_urb_loss(struct wdm_device *desc) 822static int recover_from_urb_loss(struct wdm_device *desc)
819{ 823{
@@ -827,6 +831,8 @@ static int recover_from_urb_loss(struct wdm_device *desc)
827 } 831 }
828 return rv; 832 return rv;
829} 833}
834
835#ifdef CONFIG_PM
830static int wdm_resume(struct usb_interface *intf) 836static int wdm_resume(struct usb_interface *intf)
831{ 837{
832 struct wdm_device *desc = usb_get_intfdata(intf); 838 struct wdm_device *desc = usb_get_intfdata(intf);
@@ -839,6 +845,7 @@ static int wdm_resume(struct usb_interface *intf)
839 mutex_unlock(&desc->lock); 845 mutex_unlock(&desc->lock);
840 return rv; 846 return rv;
841} 847}
848#endif
842 849
843static int wdm_pre_reset(struct usb_interface *intf) 850static int wdm_pre_reset(struct usb_interface *intf)
844{ 851{
@@ -862,9 +869,11 @@ static struct usb_driver wdm_driver = {
862 .name = "cdc_wdm", 869 .name = "cdc_wdm",
863 .probe = wdm_probe, 870 .probe = wdm_probe,
864 .disconnect = wdm_disconnect, 871 .disconnect = wdm_disconnect,
872#ifdef CONFIG_PM
865 .suspend = wdm_suspend, 873 .suspend = wdm_suspend,
866 .resume = wdm_resume, 874 .resume = wdm_resume,
867 .reset_resume = wdm_resume, 875 .reset_resume = wdm_resume,
876#endif
868 .pre_reset = wdm_pre_reset, 877 .pre_reset = wdm_pre_reset,
869 .post_reset = wdm_post_reset, 878 .post_reset = wdm_post_reset,
870 .id_table = wdm_ids, 879 .id_table = wdm_ids,