aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class/cdc-wdm.c
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2010-02-27 14:54:59 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-19 10:24:15 -0400
commit922a5eadd5a3aa0b806be0c18694b618d41d0784 (patch)
tree25d6a630e5bd92ff0c900d94125481f53e9b377a /drivers/usb/class/cdc-wdm.c
parent860e41a71c1731e79e1920dc42676bafc925af5e (diff)
usb: cdc-wdm: Fix race between autosuspend and reading from the device
While an available response is read the device must not be autosuspended. This requires a flag dedicated to that purpose. 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.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index cf1c5fb918dc..940b17af162c 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
52#define WDM_READ 4 52#define WDM_READ 4
53#define WDM_INT_STALL 5 53#define WDM_INT_STALL 5
54#define WDM_POLL_RUNNING 6 54#define WDM_POLL_RUNNING 6
55#define WDM_RESPONDING 7
55 56
56 57
57#define WDM_MAX 16 58#define WDM_MAX 16
@@ -115,21 +116,22 @@ static void wdm_in_callback(struct urb *urb)
115 int status = urb->status; 116 int status = urb->status;
116 117
117 spin_lock(&desc->iuspin); 118 spin_lock(&desc->iuspin);
119 clear_bit(WDM_RESPONDING, &desc->flags);
118 120
119 if (status) { 121 if (status) {
120 switch (status) { 122 switch (status) {
121 case -ENOENT: 123 case -ENOENT:
122 dev_dbg(&desc->intf->dev, 124 dev_dbg(&desc->intf->dev,
123 "nonzero urb status received: -ENOENT"); 125 "nonzero urb status received: -ENOENT");
124 break; 126 goto skip_error;
125 case -ECONNRESET: 127 case -ECONNRESET:
126 dev_dbg(&desc->intf->dev, 128 dev_dbg(&desc->intf->dev,
127 "nonzero urb status received: -ECONNRESET"); 129 "nonzero urb status received: -ECONNRESET");
128 break; 130 goto skip_error;
129 case -ESHUTDOWN: 131 case -ESHUTDOWN:
130 dev_dbg(&desc->intf->dev, 132 dev_dbg(&desc->intf->dev,
131 "nonzero urb status received: -ESHUTDOWN"); 133 "nonzero urb status received: -ESHUTDOWN");
132 break; 134 goto skip_error;
133 case -EPIPE: 135 case -EPIPE:
134 dev_err(&desc->intf->dev, 136 dev_err(&desc->intf->dev,
135 "nonzero urb status received: -EPIPE\n"); 137 "nonzero urb status received: -EPIPE\n");
@@ -145,6 +147,7 @@ static void wdm_in_callback(struct urb *urb)
145 desc->reslength = urb->actual_length; 147 desc->reslength = urb->actual_length;
146 memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); 148 memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
147 desc->length += desc->reslength; 149 desc->length += desc->reslength;
150skip_error:
148 wake_up(&desc->wait); 151 wake_up(&desc->wait);
149 152
150 set_bit(WDM_READ, &desc->flags); 153 set_bit(WDM_READ, &desc->flags);
@@ -227,6 +230,7 @@ static void wdm_int_callback(struct urb *urb)
227 desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 230 desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
228 spin_lock(&desc->iuspin); 231 spin_lock(&desc->iuspin);
229 clear_bit(WDM_READ, &desc->flags); 232 clear_bit(WDM_READ, &desc->flags);
233 set_bit(WDM_RESPONDING, &desc->flags);
230 if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { 234 if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
231 rv = usb_submit_urb(desc->response, GFP_ATOMIC); 235 rv = usb_submit_urb(desc->response, GFP_ATOMIC);
232 dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", 236 dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
@@ -234,6 +238,7 @@ static void wdm_int_callback(struct urb *urb)
234 } 238 }
235 spin_unlock(&desc->iuspin); 239 spin_unlock(&desc->iuspin);
236 if (rv < 0) { 240 if (rv < 0) {
241 clear_bit(WDM_RESPONDING, &desc->flags);
237 if (rv == -EPERM) 242 if (rv == -EPERM)
238 return; 243 return;
239 if (rv == -ENOMEM) { 244 if (rv == -ENOMEM) {
@@ -795,7 +800,8 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
795 mutex_lock(&desc->lock); 800 mutex_lock(&desc->lock);
796#ifdef CONFIG_PM 801#ifdef CONFIG_PM
797 if ((message.event & PM_EVENT_AUTO) && 802 if ((message.event & PM_EVENT_AUTO) &&
798 test_bit(WDM_IN_USE, &desc->flags)) { 803 (test_bit(WDM_IN_USE, &desc->flags)
804 || test_bit(WDM_RESPONDING, &desc->flags))) {
799 rv = -EBUSY; 805 rv = -EBUSY;
800 } else { 806 } else {
801#endif 807#endif