diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e78720b59d67..3e15add665e2 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -360,7 +360,7 @@ static void acm_ctrl_irq(struct urb *urb) | |||
| 360 | } | 360 | } |
| 361 | exit: | 361 | exit: |
| 362 | retval = usb_submit_urb(urb, GFP_ATOMIC); | 362 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
| 363 | if (retval) | 363 | if (retval && retval != -EPERM) |
| 364 | dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n", | 364 | dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n", |
| 365 | __func__, retval); | 365 | __func__, retval); |
| 366 | } | 366 | } |
| @@ -417,25 +417,33 @@ static void acm_read_bulk_callback(struct urb *urb) | |||
| 417 | struct acm_rb *rb = urb->context; | 417 | struct acm_rb *rb = urb->context; |
| 418 | struct acm *acm = rb->instance; | 418 | struct acm *acm = rb->instance; |
| 419 | unsigned long flags; | 419 | unsigned long flags; |
| 420 | int status = urb->status; | ||
| 420 | 421 | ||
| 421 | dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__, | 422 | dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__, |
| 422 | rb->index, urb->actual_length); | 423 | rb->index, urb->actual_length); |
| 423 | set_bit(rb->index, &acm->read_urbs_free); | ||
| 424 | 424 | ||
| 425 | if (!acm->dev) { | 425 | if (!acm->dev) { |
| 426 | set_bit(rb->index, &acm->read_urbs_free); | ||
| 426 | dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); | 427 | dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); |
| 427 | return; | 428 | return; |
| 428 | } | 429 | } |
| 429 | 430 | ||
| 430 | if (urb->status) { | 431 | if (status) { |
| 432 | set_bit(rb->index, &acm->read_urbs_free); | ||
| 431 | dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", | 433 | dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", |
| 432 | __func__, urb->status); | 434 | __func__, status); |
| 433 | return; | 435 | return; |
| 434 | } | 436 | } |
| 435 | 437 | ||
| 436 | usb_mark_last_busy(acm->dev); | 438 | usb_mark_last_busy(acm->dev); |
| 437 | 439 | ||
| 438 | acm_process_read_urb(acm, urb); | 440 | acm_process_read_urb(acm, urb); |
| 441 | /* | ||
| 442 | * Unthrottle may run on another CPU which needs to see events | ||
| 443 | * in the same order. Submission has an implict barrier | ||
| 444 | */ | ||
| 445 | smp_mb__before_atomic(); | ||
| 446 | set_bit(rb->index, &acm->read_urbs_free); | ||
| 439 | 447 | ||
| 440 | /* throttle device if requested by tty */ | 448 | /* throttle device if requested by tty */ |
| 441 | spin_lock_irqsave(&acm->read_lock, flags); | 449 | spin_lock_irqsave(&acm->read_lock, flags); |
| @@ -454,13 +462,14 @@ static void acm_write_bulk(struct urb *urb) | |||
| 454 | struct acm_wb *wb = urb->context; | 462 | struct acm_wb *wb = urb->context; |
| 455 | struct acm *acm = wb->instance; | 463 | struct acm *acm = wb->instance; |
| 456 | unsigned long flags; | 464 | unsigned long flags; |
| 465 | int status = urb->status; | ||
| 457 | 466 | ||
| 458 | if (urb->status || (urb->actual_length != urb->transfer_buffer_length)) | 467 | if (status || (urb->actual_length != urb->transfer_buffer_length)) |
| 459 | dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n", | 468 | dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n", |
| 460 | __func__, | 469 | __func__, |
| 461 | urb->actual_length, | 470 | urb->actual_length, |
| 462 | urb->transfer_buffer_length, | 471 | urb->transfer_buffer_length, |
| 463 | urb->status); | 472 | status); |
| 464 | 473 | ||
| 465 | spin_lock_irqsave(&acm->write_lock, flags); | 474 | spin_lock_irqsave(&acm->write_lock, flags); |
| 466 | acm_write_done(acm, wb); | 475 | acm_write_done(acm, wb); |
| @@ -1650,6 +1659,8 @@ static int acm_reset_resume(struct usb_interface *intf) | |||
| 1650 | 1659 | ||
| 1651 | static const struct usb_device_id acm_ids[] = { | 1660 | static const struct usb_device_id acm_ids[] = { |
| 1652 | /* quirky and broken devices */ | 1661 | /* quirky and broken devices */ |
| 1662 | { USB_DEVICE(0x076d, 0x0006), /* Denso Cradle CU-321 */ | ||
| 1663 | .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */ | ||
| 1653 | { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */ | 1664 | { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */ |
| 1654 | .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */ | 1665 | .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */ |
| 1655 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ | 1666 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ |
