diff options
Diffstat (limited to 'drivers/usb/class')
| -rw-r--r-- | drivers/usb/class/cdc-wdm.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 5f0cb417b736..122d056d96d5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
| @@ -56,6 +56,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); | |||
| 56 | #define WDM_RESPONDING 7 | 56 | #define WDM_RESPONDING 7 |
| 57 | #define WDM_SUSPENDING 8 | 57 | #define WDM_SUSPENDING 8 |
| 58 | #define WDM_RESETTING 9 | 58 | #define WDM_RESETTING 9 |
| 59 | #define WDM_OVERFLOW 10 | ||
| 59 | 60 | ||
| 60 | #define WDM_MAX 16 | 61 | #define WDM_MAX 16 |
| 61 | 62 | ||
| @@ -155,6 +156,7 @@ static void wdm_in_callback(struct urb *urb) | |||
| 155 | { | 156 | { |
| 156 | struct wdm_device *desc = urb->context; | 157 | struct wdm_device *desc = urb->context; |
| 157 | int status = urb->status; | 158 | int status = urb->status; |
| 159 | int length = urb->actual_length; | ||
| 158 | 160 | ||
| 159 | spin_lock(&desc->iuspin); | 161 | spin_lock(&desc->iuspin); |
| 160 | clear_bit(WDM_RESPONDING, &desc->flags); | 162 | clear_bit(WDM_RESPONDING, &desc->flags); |
| @@ -185,9 +187,17 @@ static void wdm_in_callback(struct urb *urb) | |||
| 185 | } | 187 | } |
| 186 | 188 | ||
| 187 | desc->rerr = status; | 189 | desc->rerr = status; |
| 188 | desc->reslength = urb->actual_length; | 190 | if (length + desc->length > desc->wMaxCommand) { |
| 189 | memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); | 191 | /* The buffer would overflow */ |
| 190 | desc->length += desc->reslength; | 192 | set_bit(WDM_OVERFLOW, &desc->flags); |
| 193 | } else { | ||
| 194 | /* we may already be in overflow */ | ||
| 195 | if (!test_bit(WDM_OVERFLOW, &desc->flags)) { | ||
| 196 | memmove(desc->ubuf + desc->length, desc->inbuf, length); | ||
| 197 | desc->length += length; | ||
| 198 | desc->reslength = length; | ||
| 199 | } | ||
| 200 | } | ||
| 191 | skip_error: | 201 | skip_error: |
| 192 | wake_up(&desc->wait); | 202 | wake_up(&desc->wait); |
| 193 | 203 | ||
| @@ -435,6 +445,11 @@ retry: | |||
| 435 | rv = -ENODEV; | 445 | rv = -ENODEV; |
| 436 | goto err; | 446 | goto err; |
| 437 | } | 447 | } |
| 448 | if (test_bit(WDM_OVERFLOW, &desc->flags)) { | ||
| 449 | clear_bit(WDM_OVERFLOW, &desc->flags); | ||
| 450 | rv = -ENOBUFS; | ||
| 451 | goto err; | ||
| 452 | } | ||
| 438 | i++; | 453 | i++; |
| 439 | if (file->f_flags & O_NONBLOCK) { | 454 | if (file->f_flags & O_NONBLOCK) { |
| 440 | if (!test_bit(WDM_READ, &desc->flags)) { | 455 | if (!test_bit(WDM_READ, &desc->flags)) { |
| @@ -478,6 +493,7 @@ retry: | |||
| 478 | spin_unlock_irq(&desc->iuspin); | 493 | spin_unlock_irq(&desc->iuspin); |
| 479 | goto retry; | 494 | goto retry; |
| 480 | } | 495 | } |
| 496 | |||
| 481 | if (!desc->reslength) { /* zero length read */ | 497 | if (!desc->reslength) { /* zero length read */ |
| 482 | dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); | 498 | dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); |
| 483 | clear_bit(WDM_READ, &desc->flags); | 499 | clear_bit(WDM_READ, &desc->flags); |
| @@ -1004,6 +1020,7 @@ static int wdm_post_reset(struct usb_interface *intf) | |||
| 1004 | struct wdm_device *desc = wdm_find_device(intf); | 1020 | struct wdm_device *desc = wdm_find_device(intf); |
| 1005 | int rv; | 1021 | int rv; |
| 1006 | 1022 | ||
| 1023 | clear_bit(WDM_OVERFLOW, &desc->flags); | ||
| 1007 | clear_bit(WDM_RESETTING, &desc->flags); | 1024 | clear_bit(WDM_RESETTING, &desc->flags); |
| 1008 | rv = recover_from_urb_loss(desc); | 1025 | rv = recover_from_urb_loss(desc); |
| 1009 | mutex_unlock(&desc->wlock); | 1026 | mutex_unlock(&desc->wlock); |
