diff options
| author | Johan Hovold <jhovold@gmail.com> | 2011-03-25 06:06:02 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-04-13 19:18:34 -0400 |
| commit | 088c64f812847b3623b03d167ed329f90f3e38a4 (patch) | |
| tree | 2c76790cf12fddf227b4ab21d43002713837c948 | |
| parent | 74f5e1babde76149c2bb35ca5dbf4d0b9b38f161 (diff) | |
USB: cdc-acm: re-write read processing
Kill rx tasklet, which is no longer needed, and re-write read processing.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 295 | ||||
| -rw-r--r-- | drivers/usb/class/cdc-acm.h | 22 |
2 files changed, 120 insertions, 197 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 519c7b933508..58754b508a0f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> | 7 | * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> |
| 8 | * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name> | 8 | * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name> |
| 9 | * Copyright (c) 2005 David Kubicek <dave@awk.cz> | 9 | * Copyright (c) 2005 David Kubicek <dave@awk.cz> |
| 10 | * Copyright (c) 2011 Johan Hovold <jhovold@gmail.com> | ||
| 10 | * | 11 | * |
| 11 | * USB Abstract Control Model driver for USB modems and ISDN adapters | 12 | * USB Abstract Control Model driver for USB modems and ISDN adapters |
| 12 | * | 13 | * |
| @@ -50,7 +51,7 @@ | |||
| 50 | #include "cdc-acm.h" | 51 | #include "cdc-acm.h" |
| 51 | 52 | ||
| 52 | 53 | ||
| 53 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" | 54 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold" |
| 54 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" | 55 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" |
| 55 | 56 | ||
| 56 | static struct usb_driver acm_driver; | 57 | static struct usb_driver acm_driver; |
| @@ -323,166 +324,92 @@ exit: | |||
| 323 | __func__, retval); | 324 | __func__, retval); |
| 324 | } | 325 | } |
| 325 | 326 | ||
| 326 | /* data interface returns incoming bytes, or we got unthrottled */ | 327 | static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) |
| 327 | static void acm_read_bulk(struct urb *urb) | ||
| 328 | { | 328 | { |
| 329 | struct acm_rb *buf; | 329 | int res; |
| 330 | struct acm_ru *rcv = urb->context; | ||
| 331 | struct acm *acm = rcv->instance; | ||
| 332 | int status = urb->status; | ||
| 333 | 330 | ||
| 334 | dev_vdbg(&acm->data->dev, "%s - status %d\n", __func__, status); | 331 | if (!test_and_clear_bit(index, &acm->read_urbs_free)) |
| 332 | return 0; | ||
| 335 | 333 | ||
| 336 | if (!ACM_READY(acm)) { | 334 | dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index); |
| 337 | dev_dbg(&acm->data->dev, "%s - acm not ready\n", __func__); | 335 | |
| 338 | return; | 336 | res = usb_submit_urb(acm->read_urbs[index], mem_flags); |
| 337 | if (res) { | ||
| 338 | if (res != -EPERM) { | ||
| 339 | dev_err(&acm->data->dev, | ||
| 340 | "%s - usb_submit_urb failed: %d\n", | ||
| 341 | __func__, res); | ||
| 342 | } | ||
| 343 | set_bit(index, &acm->read_urbs_free); | ||
| 344 | return res; | ||
| 339 | } | 345 | } |
| 340 | usb_mark_last_busy(acm->dev); | ||
| 341 | 346 | ||
| 342 | if (status) | 347 | return 0; |
| 343 | dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", | 348 | } |
| 344 | __func__, status); | ||
| 345 | 349 | ||
| 346 | buf = rcv->buffer; | 350 | static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags) |
| 347 | buf->size = urb->actual_length; | 351 | { |
| 352 | int res; | ||
| 353 | int i; | ||
| 348 | 354 | ||
| 349 | if (likely(status == 0)) { | 355 | for (i = 0; i < acm->rx_buflimit; ++i) { |
| 350 | spin_lock(&acm->read_lock); | 356 | res = acm_submit_read_urb(acm, i, mem_flags); |
| 351 | acm->processing++; | 357 | if (res) |
| 352 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | 358 | return res; |
| 353 | list_add_tail(&buf->list, &acm->filled_read_bufs); | ||
| 354 | spin_unlock(&acm->read_lock); | ||
| 355 | } else { | ||
| 356 | /* we drop the buffer due to an error */ | ||
| 357 | spin_lock(&acm->read_lock); | ||
| 358 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | ||
| 359 | list_add(&buf->list, &acm->spare_read_bufs); | ||
| 360 | spin_unlock(&acm->read_lock); | ||
| 361 | /* nevertheless the tasklet must be kicked unconditionally | ||
| 362 | so the queue cannot dry up */ | ||
| 363 | } | 359 | } |
| 364 | if (likely(!acm->susp_count)) | 360 | |
| 365 | tasklet_schedule(&acm->urb_task); | 361 | return 0; |
| 366 | } | 362 | } |
| 367 | 363 | ||
| 368 | static void acm_rx_tasklet(unsigned long _acm) | 364 | static void acm_process_read_urb(struct acm *acm, struct urb *urb) |
| 369 | { | 365 | { |
| 370 | struct acm *acm = (void *)_acm; | ||
| 371 | struct acm_rb *buf; | ||
| 372 | struct tty_struct *tty; | 366 | struct tty_struct *tty; |
| 373 | struct acm_ru *rcv; | ||
| 374 | unsigned long flags; | ||
| 375 | unsigned char throttled; | ||
| 376 | |||
| 377 | dev_vdbg(&acm->data->dev, "%s\n", __func__); | ||
| 378 | 367 | ||
| 379 | if (!ACM_READY(acm)) { | 368 | if (!urb->actual_length) |
| 380 | dev_dbg(&acm->data->dev, "%s - acm not ready\n", __func__); | ||
| 381 | return; | 369 | return; |
| 382 | } | ||
| 383 | |||
| 384 | spin_lock_irqsave(&acm->throttle_lock, flags); | ||
| 385 | throttled = acm->throttle; | ||
| 386 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | ||
| 387 | if (throttled) { | ||
| 388 | dev_dbg(&acm->data->dev, "%s - throttled\n", __func__); | ||
| 389 | return; | ||
| 390 | } | ||
| 391 | 370 | ||
| 392 | tty = tty_port_tty_get(&acm->port); | 371 | tty = tty_port_tty_get(&acm->port); |
| 372 | if (!tty) | ||
| 373 | return; | ||
| 393 | 374 | ||
| 394 | next_buffer: | 375 | tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); |
| 395 | spin_lock_irqsave(&acm->read_lock, flags); | 376 | tty_flip_buffer_push(tty); |
| 396 | if (list_empty(&acm->filled_read_bufs)) { | ||
| 397 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 398 | goto urbs; | ||
| 399 | } | ||
| 400 | buf = list_entry(acm->filled_read_bufs.next, | ||
| 401 | struct acm_rb, list); | ||
| 402 | list_del(&buf->list); | ||
| 403 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 404 | |||
| 405 | dev_vdbg(&acm->data->dev, "%s - processing buf 0x%p, size = %d\n", | ||
| 406 | __func__, buf, buf->size); | ||
| 407 | if (tty) { | ||
| 408 | spin_lock_irqsave(&acm->throttle_lock, flags); | ||
| 409 | throttled = acm->throttle; | ||
| 410 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | ||
| 411 | if (!throttled) { | ||
| 412 | tty_insert_flip_string(tty, buf->base, buf->size); | ||
| 413 | tty_flip_buffer_push(tty); | ||
| 414 | } else { | ||
| 415 | tty_kref_put(tty); | ||
| 416 | dev_dbg(&acm->data->dev, "%s - throttling noticed\n", | ||
| 417 | __func__); | ||
| 418 | spin_lock_irqsave(&acm->read_lock, flags); | ||
| 419 | list_add(&buf->list, &acm->filled_read_bufs); | ||
| 420 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 421 | return; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | spin_lock_irqsave(&acm->read_lock, flags); | ||
| 426 | list_add(&buf->list, &acm->spare_read_bufs); | ||
| 427 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 428 | goto next_buffer; | ||
| 429 | 377 | ||
| 430 | urbs: | ||
| 431 | tty_kref_put(tty); | 378 | tty_kref_put(tty); |
| 379 | } | ||
| 432 | 380 | ||
| 433 | while (!list_empty(&acm->spare_read_bufs)) { | 381 | static void acm_read_bulk_callback(struct urb *urb) |
| 434 | spin_lock_irqsave(&acm->read_lock, flags); | 382 | { |
| 435 | if (list_empty(&acm->spare_read_urbs)) { | 383 | struct acm_rb *rb = urb->context; |
| 436 | acm->processing = 0; | 384 | struct acm *acm = rb->instance; |
| 437 | spin_unlock_irqrestore(&acm->read_lock, flags); | 385 | unsigned long flags; |
| 438 | return; | ||
| 439 | } | ||
| 440 | rcv = list_entry(acm->spare_read_urbs.next, | ||
| 441 | struct acm_ru, list); | ||
| 442 | list_del(&rcv->list); | ||
| 443 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 444 | 386 | ||
| 445 | buf = list_entry(acm->spare_read_bufs.next, | 387 | dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__, |
| 446 | struct acm_rb, list); | 388 | rb->index, urb->actual_length); |
| 447 | list_del(&buf->list); | 389 | set_bit(rb->index, &acm->read_urbs_free); |
| 448 | 390 | ||
| 449 | rcv->buffer = buf; | 391 | if (!acm->dev) { |
| 392 | dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | usb_mark_last_busy(acm->dev); | ||
| 450 | 396 | ||
| 451 | if (acm->is_int_ep) | 397 | if (urb->status) { |
| 452 | usb_fill_int_urb(rcv->urb, acm->dev, | 398 | dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", |
| 453 | acm->rx_endpoint, | 399 | __func__, urb->status); |
| 454 | buf->base, | 400 | return; |
| 455 | acm->readsize, | ||
| 456 | acm_read_bulk, rcv, acm->bInterval); | ||
| 457 | else | ||
| 458 | usb_fill_bulk_urb(rcv->urb, acm->dev, | ||
| 459 | acm->rx_endpoint, | ||
| 460 | buf->base, | ||
| 461 | acm->readsize, | ||
| 462 | acm_read_bulk, rcv); | ||
| 463 | rcv->urb->transfer_dma = buf->dma; | ||
| 464 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 465 | |||
| 466 | /* This shouldn't kill the driver as unsuccessful URBs are | ||
| 467 | returned to the free-urbs-pool and resubmited ASAP */ | ||
| 468 | spin_lock_irqsave(&acm->read_lock, flags); | ||
| 469 | if (acm->susp_count || | ||
| 470 | usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | ||
| 471 | list_add(&buf->list, &acm->spare_read_bufs); | ||
| 472 | list_add(&rcv->list, &acm->spare_read_urbs); | ||
| 473 | acm->processing = 0; | ||
| 474 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 475 | return; | ||
| 476 | } else { | ||
| 477 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 478 | dev_vdbg(&acm->data->dev, | ||
| 479 | "%s - sending urb 0x%p, rcv 0x%p, buf 0x%p\n", | ||
| 480 | __func__, rcv->urb, rcv, buf); | ||
| 481 | } | ||
| 482 | } | 401 | } |
| 402 | acm_process_read_urb(acm, urb); | ||
| 403 | |||
| 404 | /* throttle device if requested by tty */ | ||
| 483 | spin_lock_irqsave(&acm->read_lock, flags); | 405 | spin_lock_irqsave(&acm->read_lock, flags); |
| 484 | acm->processing = 0; | 406 | acm->throttled = acm->throttle_req; |
| 485 | spin_unlock_irqrestore(&acm->read_lock, flags); | 407 | if (!acm->throttled && !acm->susp_count) { |
| 408 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 409 | acm_submit_read_urb(acm, rb->index, GFP_ATOMIC); | ||
| 410 | } else { | ||
| 411 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 412 | } | ||
| 486 | } | 413 | } |
| 487 | 414 | ||
| 488 | /* data interface wrote those outgoing bytes */ | 415 | /* data interface wrote those outgoing bytes */ |
| @@ -530,7 +457,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 530 | { | 457 | { |
| 531 | struct acm *acm; | 458 | struct acm *acm; |
| 532 | int rv = -ENODEV; | 459 | int rv = -ENODEV; |
| 533 | int i; | ||
| 534 | 460 | ||
| 535 | mutex_lock(&open_mutex); | 461 | mutex_lock(&open_mutex); |
| 536 | 462 | ||
| @@ -572,20 +498,11 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 572 | 498 | ||
| 573 | usb_autopm_put_interface(acm->control); | 499 | usb_autopm_put_interface(acm->control); |
| 574 | 500 | ||
| 575 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 501 | if (acm_submit_read_urbs(acm, GFP_KERNEL)) |
| 576 | INIT_LIST_HEAD(&acm->spare_read_bufs); | 502 | goto bail_out; |
| 577 | INIT_LIST_HEAD(&acm->filled_read_bufs); | ||
| 578 | |||
| 579 | for (i = 0; i < acm->rx_buflimit; i++) | ||
| 580 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); | ||
| 581 | for (i = 0; i < acm->rx_buflimit; i++) | ||
| 582 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | ||
| 583 | |||
| 584 | acm->throttle = 0; | ||
| 585 | 503 | ||
| 586 | set_bit(ASYNCB_INITIALIZED, &acm->port.flags); | 504 | set_bit(ASYNCB_INITIALIZED, &acm->port.flags); |
| 587 | rv = tty_port_block_til_ready(&acm->port, tty, filp); | 505 | rv = tty_port_block_til_ready(&acm->port, tty, filp); |
| 588 | tasklet_schedule(&acm->urb_task); | ||
| 589 | 506 | ||
| 590 | mutex_unlock(&acm->mutex); | 507 | mutex_unlock(&acm->mutex); |
| 591 | out: | 508 | out: |
| @@ -613,7 +530,7 @@ static void acm_tty_unregister(struct acm *acm) | |||
| 613 | for (i = 0; i < ACM_NW; i++) | 530 | for (i = 0; i < ACM_NW; i++) |
| 614 | usb_free_urb(acm->wb[i].urb); | 531 | usb_free_urb(acm->wb[i].urb); |
| 615 | for (i = 0; i < acm->rx_buflimit; i++) | 532 | for (i = 0; i < acm->rx_buflimit; i++) |
| 616 | usb_free_urb(acm->ru[i].urb); | 533 | usb_free_urb(acm->read_urbs[i]); |
| 617 | kfree(acm->country_codes); | 534 | kfree(acm->country_codes); |
| 618 | kfree(acm); | 535 | kfree(acm); |
| 619 | } | 536 | } |
| @@ -629,10 +546,8 @@ static void acm_port_down(struct acm *acm) | |||
| 629 | usb_kill_urb(acm->ctrlurb); | 546 | usb_kill_urb(acm->ctrlurb); |
| 630 | for (i = 0; i < ACM_NW; i++) | 547 | for (i = 0; i < ACM_NW; i++) |
| 631 | usb_kill_urb(acm->wb[i].urb); | 548 | usb_kill_urb(acm->wb[i].urb); |
| 632 | tasklet_disable(&acm->urb_task); | ||
| 633 | for (i = 0; i < acm->rx_buflimit; i++) | 549 | for (i = 0; i < acm->rx_buflimit; i++) |
| 634 | usb_kill_urb(acm->ru[i].urb); | 550 | usb_kill_urb(acm->read_urbs[i]); |
| 635 | tasklet_enable(&acm->urb_task); | ||
| 636 | acm->control->needs_remote_wakeup = 0; | 551 | acm->control->needs_remote_wakeup = 0; |
| 637 | usb_autopm_put_interface(acm->control); | 552 | usb_autopm_put_interface(acm->control); |
| 638 | } | 553 | } |
| @@ -731,22 +646,31 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty) | |||
| 731 | static void acm_tty_throttle(struct tty_struct *tty) | 646 | static void acm_tty_throttle(struct tty_struct *tty) |
| 732 | { | 647 | { |
| 733 | struct acm *acm = tty->driver_data; | 648 | struct acm *acm = tty->driver_data; |
| 649 | |||
| 734 | if (!ACM_READY(acm)) | 650 | if (!ACM_READY(acm)) |
| 735 | return; | 651 | return; |
| 736 | spin_lock_bh(&acm->throttle_lock); | 652 | |
| 737 | acm->throttle = 1; | 653 | spin_lock_irq(&acm->read_lock); |
| 738 | spin_unlock_bh(&acm->throttle_lock); | 654 | acm->throttle_req = 1; |
| 655 | spin_unlock_irq(&acm->read_lock); | ||
| 739 | } | 656 | } |
| 740 | 657 | ||
| 741 | static void acm_tty_unthrottle(struct tty_struct *tty) | 658 | static void acm_tty_unthrottle(struct tty_struct *tty) |
| 742 | { | 659 | { |
| 743 | struct acm *acm = tty->driver_data; | 660 | struct acm *acm = tty->driver_data; |
| 661 | unsigned int was_throttled; | ||
| 662 | |||
| 744 | if (!ACM_READY(acm)) | 663 | if (!ACM_READY(acm)) |
| 745 | return; | 664 | return; |
| 746 | spin_lock_bh(&acm->throttle_lock); | 665 | |
| 747 | acm->throttle = 0; | 666 | spin_lock_irq(&acm->read_lock); |
| 748 | spin_unlock_bh(&acm->throttle_lock); | 667 | was_throttled = acm->throttled; |
| 749 | tasklet_schedule(&acm->urb_task); | 668 | acm->throttled = 0; |
| 669 | acm->throttle_req = 0; | ||
| 670 | spin_unlock_irq(&acm->read_lock); | ||
| 671 | |||
| 672 | if (was_throttled) | ||
| 673 | acm_submit_read_urbs(acm, GFP_KERNEL); | ||
| 750 | } | 674 | } |
| 751 | 675 | ||
| 752 | static int acm_tty_break_ctl(struct tty_struct *tty, int state) | 676 | static int acm_tty_break_ctl(struct tty_struct *tty, int state) |
| @@ -884,7 +808,7 @@ static void acm_read_buffers_free(struct acm *acm) | |||
| 884 | 808 | ||
| 885 | for (i = 0; i < acm->rx_buflimit; i++) | 809 | for (i = 0; i < acm->rx_buflimit; i++) |
| 886 | usb_free_coherent(usb_dev, acm->readsize, | 810 | usb_free_coherent(usb_dev, acm->readsize, |
| 887 | acm->rb[i].base, acm->rb[i].dma); | 811 | acm->read_buffers[i].base, acm->read_buffers[i].dma); |
| 888 | } | 812 | } |
| 889 | 813 | ||
| 890 | /* Little helper: write buffers allocate */ | 814 | /* Little helper: write buffers allocate */ |
| @@ -1145,10 +1069,7 @@ made_compressed_probe: | |||
| 1145 | acm->ctrlsize = ctrlsize; | 1069 | acm->ctrlsize = ctrlsize; |
| 1146 | acm->readsize = readsize; | 1070 | acm->readsize = readsize; |
| 1147 | acm->rx_buflimit = num_rx_buf; | 1071 | acm->rx_buflimit = num_rx_buf; |
| 1148 | acm->urb_task.func = acm_rx_tasklet; | ||
| 1149 | acm->urb_task.data = (unsigned long) acm; | ||
| 1150 | INIT_WORK(&acm->work, acm_softint); | 1072 | INIT_WORK(&acm->work, acm_softint); |
| 1151 | spin_lock_init(&acm->throttle_lock); | ||
| 1152 | spin_lock_init(&acm->write_lock); | 1073 | spin_lock_init(&acm->write_lock); |
| 1153 | spin_lock_init(&acm->read_lock); | 1074 | spin_lock_init(&acm->read_lock); |
| 1154 | mutex_init(&acm->mutex); | 1075 | mutex_init(&acm->mutex); |
| @@ -1177,8 +1098,8 @@ made_compressed_probe: | |||
| 1177 | goto alloc_fail5; | 1098 | goto alloc_fail5; |
| 1178 | } | 1099 | } |
| 1179 | for (i = 0; i < num_rx_buf; i++) { | 1100 | for (i = 0; i < num_rx_buf; i++) { |
| 1180 | struct acm_rb *rb = &(acm->rb[i]); | 1101 | struct acm_rb *rb = &(acm->read_buffers[i]); |
| 1181 | struct acm_ru *rcv = &(acm->ru[i]); | 1102 | struct urb *urb; |
| 1182 | 1103 | ||
| 1183 | rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, | 1104 | rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, |
| 1184 | &rb->dma); | 1105 | &rb->dma); |
| @@ -1187,16 +1108,34 @@ made_compressed_probe: | |||
| 1187 | "(read bufs usb_alloc_coherent)\n"); | 1108 | "(read bufs usb_alloc_coherent)\n"); |
| 1188 | goto alloc_fail6; | 1109 | goto alloc_fail6; |
| 1189 | } | 1110 | } |
| 1111 | rb->index = i; | ||
| 1112 | rb->instance = acm; | ||
| 1190 | 1113 | ||
| 1191 | rcv->urb = usb_alloc_urb(0, GFP_KERNEL); | 1114 | urb = usb_alloc_urb(0, GFP_KERNEL); |
| 1192 | if (rcv->urb == NULL) { | 1115 | if (!urb) { |
| 1193 | dev_err(&intf->dev, | 1116 | dev_err(&intf->dev, |
| 1194 | "out of memory (read urbs usb_alloc_urb)\n"); | 1117 | "out of memory (read urbs usb_alloc_urb)\n"); |
| 1195 | goto alloc_fail6; | 1118 | goto alloc_fail6; |
| 1196 | } | 1119 | } |
| 1120 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 1121 | urb->transfer_dma = rb->dma; | ||
| 1122 | if (acm->is_int_ep) { | ||
| 1123 | usb_fill_int_urb(urb, acm->dev, | ||
| 1124 | acm->rx_endpoint, | ||
| 1125 | rb->base, | ||
| 1126 | acm->readsize, | ||
| 1127 | acm_read_bulk_callback, rb, | ||
| 1128 | acm->bInterval); | ||
| 1129 | } else { | ||
| 1130 | usb_fill_bulk_urb(urb, acm->dev, | ||
| 1131 | acm->rx_endpoint, | ||
| 1132 | rb->base, | ||
| 1133 | acm->readsize, | ||
| 1134 | acm_read_bulk_callback, rb); | ||
| 1135 | } | ||
| 1197 | 1136 | ||
| 1198 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 1137 | acm->read_urbs[i] = urb; |
| 1199 | rcv->instance = acm; | 1138 | __set_bit(i, &acm->read_urbs_free); |
| 1200 | } | 1139 | } |
| 1201 | for (i = 0; i < ACM_NW; i++) { | 1140 | for (i = 0; i < ACM_NW; i++) { |
| 1202 | struct acm_wb *snd = &(acm->wb[i]); | 1141 | struct acm_wb *snd = &(acm->wb[i]); |
| @@ -1281,7 +1220,7 @@ alloc_fail7: | |||
| 1281 | usb_free_urb(acm->wb[i].urb); | 1220 | usb_free_urb(acm->wb[i].urb); |
| 1282 | alloc_fail6: | 1221 | alloc_fail6: |
| 1283 | for (i = 0; i < num_rx_buf; i++) | 1222 | for (i = 0; i < num_rx_buf; i++) |
| 1284 | usb_free_urb(acm->ru[i].urb); | 1223 | usb_free_urb(acm->read_urbs[i]); |
| 1285 | acm_read_buffers_free(acm); | 1224 | acm_read_buffers_free(acm); |
| 1286 | usb_free_urb(acm->ctrlurb); | 1225 | usb_free_urb(acm->ctrlurb); |
| 1287 | alloc_fail5: | 1226 | alloc_fail5: |
| @@ -1300,15 +1239,11 @@ static void stop_data_traffic(struct acm *acm) | |||
| 1300 | 1239 | ||
| 1301 | dev_dbg(&acm->control->dev, "%s\n", __func__); | 1240 | dev_dbg(&acm->control->dev, "%s\n", __func__); |
| 1302 | 1241 | ||
| 1303 | tasklet_disable(&acm->urb_task); | ||
| 1304 | |||
| 1305 | usb_kill_urb(acm->ctrlurb); | 1242 | usb_kill_urb(acm->ctrlurb); |
| 1306 | for (i = 0; i < ACM_NW; i++) | 1243 | for (i = 0; i < ACM_NW; i++) |
| 1307 | usb_kill_urb(acm->wb[i].urb); | 1244 | usb_kill_urb(acm->wb[i].urb); |
| 1308 | for (i = 0; i < acm->rx_buflimit; i++) | 1245 | for (i = 0; i < acm->rx_buflimit; i++) |
| 1309 | usb_kill_urb(acm->ru[i].urb); | 1246 | usb_kill_urb(acm->read_urbs[i]); |
| 1310 | |||
| 1311 | tasklet_enable(&acm->urb_task); | ||
| 1312 | 1247 | ||
| 1313 | cancel_work_sync(&acm->work); | 1248 | cancel_work_sync(&acm->work); |
| 1314 | } | 1249 | } |
| @@ -1369,11 +1304,9 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
| 1369 | if (message.event & PM_EVENT_AUTO) { | 1304 | if (message.event & PM_EVENT_AUTO) { |
| 1370 | int b; | 1305 | int b; |
| 1371 | 1306 | ||
| 1372 | spin_lock_irq(&acm->read_lock); | 1307 | spin_lock_irq(&acm->write_lock); |
| 1373 | spin_lock(&acm->write_lock); | 1308 | b = acm->transmitting; |
| 1374 | b = acm->processing + acm->transmitting; | 1309 | spin_unlock_irq(&acm->write_lock); |
| 1375 | spin_unlock(&acm->write_lock); | ||
| 1376 | spin_unlock_irq(&acm->read_lock); | ||
| 1377 | if (b) | 1310 | if (b) |
| 1378 | return -EBUSY; | 1311 | return -EBUSY; |
| 1379 | } | 1312 | } |
| @@ -1435,7 +1368,7 @@ static int acm_resume(struct usb_interface *intf) | |||
| 1435 | if (rv < 0) | 1368 | if (rv < 0) |
| 1436 | goto err_out; | 1369 | goto err_out; |
| 1437 | 1370 | ||
| 1438 | tasklet_schedule(&acm->urb_task); | 1371 | rv = acm_submit_read_urbs(acm, GFP_NOIO); |
| 1439 | } | 1372 | } |
| 1440 | 1373 | ||
| 1441 | err_out: | 1374 | err_out: |
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 7282d1f4912b..7b5c0bd07f80 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h | |||
| @@ -72,16 +72,10 @@ struct acm_wb { | |||
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| 74 | struct acm_rb { | 74 | struct acm_rb { |
| 75 | struct list_head list; | ||
| 76 | int size; | 75 | int size; |
| 77 | unsigned char *base; | 76 | unsigned char *base; |
| 78 | dma_addr_t dma; | 77 | dma_addr_t dma; |
| 79 | }; | 78 | int index; |
| 80 | |||
| 81 | struct acm_ru { | ||
| 82 | struct list_head list; | ||
| 83 | struct acm_rb *buffer; | ||
| 84 | struct urb *urb; | ||
| 85 | struct acm *instance; | 79 | struct acm *instance; |
| 86 | }; | 80 | }; |
| 87 | 81 | ||
| @@ -97,34 +91,30 @@ struct acm { | |||
| 97 | unsigned int country_code_size; /* size of this buffer */ | 91 | unsigned int country_code_size; /* size of this buffer */ |
| 98 | unsigned int country_rel_date; /* release date of version */ | 92 | unsigned int country_rel_date; /* release date of version */ |
| 99 | struct acm_wb wb[ACM_NW]; | 93 | struct acm_wb wb[ACM_NW]; |
| 100 | struct acm_ru ru[ACM_NR]; | 94 | unsigned long read_urbs_free; |
| 101 | struct acm_rb rb[ACM_NR]; | 95 | struct urb *read_urbs[ACM_NR]; |
| 96 | struct acm_rb read_buffers[ACM_NR]; | ||
| 102 | int rx_buflimit; | 97 | int rx_buflimit; |
| 103 | int rx_endpoint; | 98 | int rx_endpoint; |
| 104 | spinlock_t read_lock; | 99 | spinlock_t read_lock; |
| 105 | struct list_head spare_read_urbs; | ||
| 106 | struct list_head spare_read_bufs; | ||
| 107 | struct list_head filled_read_bufs; | ||
| 108 | int write_used; /* number of non-empty write buffers */ | 100 | int write_used; /* number of non-empty write buffers */ |
| 109 | int processing; | ||
| 110 | int transmitting; | 101 | int transmitting; |
| 111 | spinlock_t write_lock; | 102 | spinlock_t write_lock; |
| 112 | struct mutex mutex; | 103 | struct mutex mutex; |
| 113 | struct usb_cdc_line_coding line; /* bits, stop, parity */ | 104 | struct usb_cdc_line_coding line; /* bits, stop, parity */ |
| 114 | struct work_struct work; /* work queue entry for line discipline waking up */ | 105 | struct work_struct work; /* work queue entry for line discipline waking up */ |
| 115 | struct tasklet_struct urb_task; /* rx processing */ | ||
| 116 | spinlock_t throttle_lock; /* synchronize throtteling and read callback */ | ||
| 117 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ | 106 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ |
| 118 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ | 107 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ |
| 119 | unsigned int writesize; /* max packet size for the output bulk endpoint */ | 108 | unsigned int writesize; /* max packet size for the output bulk endpoint */ |
| 120 | unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ | 109 | unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ |
| 121 | unsigned int minor; /* acm minor number */ | 110 | unsigned int minor; /* acm minor number */ |
| 122 | unsigned char throttle; /* throttled by tty layer */ | ||
| 123 | unsigned char clocal; /* termios CLOCAL */ | 111 | unsigned char clocal; /* termios CLOCAL */ |
| 124 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ | 112 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ |
| 125 | unsigned int susp_count; /* number of suspended interfaces */ | 113 | unsigned int susp_count; /* number of suspended interfaces */ |
| 126 | unsigned int combined_interfaces:1; /* control and data collapsed */ | 114 | unsigned int combined_interfaces:1; /* control and data collapsed */ |
| 127 | unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */ | 115 | unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */ |
| 116 | unsigned int throttled:1; /* actually throttled */ | ||
| 117 | unsigned int throttle_req:1; /* throttle requested */ | ||
| 128 | u8 bInterval; | 118 | u8 bInterval; |
| 129 | struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ | 119 | struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ |
| 130 | }; | 120 | }; |
