diff options
author | David Kubicek <dave@awk.cz> | 2005-11-01 12:51:34 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-04 16:48:29 -0500 |
commit | 61a87adf2e7b410da8e41799c61c21a7b8c8b001 (patch) | |
tree | b4d09ce45dadd78cd2b92848a96c508f44d12f88 | |
parent | 2e1dcc1600c1d83b26479edd076866595bbd3523 (diff) |
[PATCH] USB: Converting cdc acm to a ring queue
this patch by David converts the sending queue of the CDC ACM driver
to a queue of URBs. This is needed for quicker devices. Please apply.
Signed-Off-By: Oliver Neukum <oliver@neukum.name>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/class/cdc-acm.c | 229 ++++++++++++++++++++++++++++++--------------
drivers/usb/class/cdc-acm.h | 33 +++++-
2 files changed, 185 insertions(+), 77 deletions(-)
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 227 | ||||
-rw-r--r-- | drivers/usb/class/cdc-acm.h | 33 |
2 files changed, 184 insertions, 76 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 1b4751412970..72936dc15ec9 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com> | 6 | * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com> |
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 | * | 10 | * |
10 | * USB Abstract Control Model driver for USB modems and ISDN adapters | 11 | * USB Abstract Control Model driver for USB modems and ISDN adapters |
11 | * | 12 | * |
@@ -29,6 +30,7 @@ | |||
29 | * config we want, sysadmin changes bConfigurationValue in sysfs. | 30 | * config we want, sysadmin changes bConfigurationValue in sysfs. |
30 | * v0.23 - use softirq for rx processing, as needed by tty layer | 31 | * v0.23 - use softirq for rx processing, as needed by tty layer |
31 | * v0.24 - change probe method to evaluate CDC union descriptor | 32 | * v0.24 - change probe method to evaluate CDC union descriptor |
33 | * v0.25 - downstream tasks paralelized to maximize throughput | ||
32 | */ | 34 | */ |
33 | 35 | ||
34 | /* | 36 | /* |
@@ -63,14 +65,15 @@ | |||
63 | #include <linux/usb_cdc.h> | 65 | #include <linux/usb_cdc.h> |
64 | #include <asm/byteorder.h> | 66 | #include <asm/byteorder.h> |
65 | #include <asm/unaligned.h> | 67 | #include <asm/unaligned.h> |
68 | #include <linux/list.h> | ||
66 | 69 | ||
67 | #include "cdc-acm.h" | 70 | #include "cdc-acm.h" |
68 | 71 | ||
69 | /* | 72 | /* |
70 | * Version Information | 73 | * Version Information |
71 | */ | 74 | */ |
72 | #define DRIVER_VERSION "v0.23" | 75 | #define DRIVER_VERSION "v0.25" |
73 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik" | 76 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" |
74 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" | 77 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" |
75 | 78 | ||
76 | static struct usb_driver acm_driver; | 79 | static struct usb_driver acm_driver; |
@@ -284,7 +287,9 @@ exit: | |||
284 | /* data interface returns incoming bytes, or we got unthrottled */ | 287 | /* data interface returns incoming bytes, or we got unthrottled */ |
285 | static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) | 288 | static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) |
286 | { | 289 | { |
287 | struct acm *acm = urb->context; | 290 | struct acm_rb *buf; |
291 | struct acm_ru *rcv = urb->context; | ||
292 | struct acm *acm = rcv->instance; | ||
288 | dbg("Entering acm_read_bulk with status %d\n", urb->status); | 293 | dbg("Entering acm_read_bulk with status %d\n", urb->status); |
289 | 294 | ||
290 | if (!ACM_READY(acm)) | 295 | if (!ACM_READY(acm)) |
@@ -293,49 +298,109 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) | |||
293 | if (urb->status) | 298 | if (urb->status) |
294 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status); | 299 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status); |
295 | 300 | ||
296 | /* calling tty_flip_buffer_push() in_irq() isn't allowed */ | 301 | buf = rcv->buffer; |
297 | tasklet_schedule(&acm->bh); | 302 | buf->size = urb->actual_length; |
303 | |||
304 | spin_lock(&acm->read_lock); | ||
305 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | ||
306 | list_add_tail(&buf->list, &acm->filled_read_bufs); | ||
307 | spin_unlock(&acm->read_lock); | ||
308 | |||
309 | tasklet_schedule(&acm->urb_task); | ||
298 | } | 310 | } |
299 | 311 | ||
300 | static void acm_rx_tasklet(unsigned long _acm) | 312 | static void acm_rx_tasklet(unsigned long _acm) |
301 | { | 313 | { |
302 | struct acm *acm = (void *)_acm; | 314 | struct acm *acm = (void *)_acm; |
303 | struct urb *urb = acm->readurb; | 315 | struct acm_rb *buf; |
304 | struct tty_struct *tty = acm->tty; | 316 | struct tty_struct *tty = acm->tty; |
305 | unsigned char *data = urb->transfer_buffer; | 317 | struct acm_ru *rcv; |
318 | //unsigned long flags; | ||
306 | int i = 0; | 319 | int i = 0; |
307 | dbg("Entering acm_rx_tasklet"); | 320 | dbg("Entering acm_rx_tasklet"); |
308 | 321 | ||
309 | if (urb->actual_length > 0 && !acm->throttle) { | 322 | if (!ACM_READY(acm) || acm->throttle) |
310 | for (i = 0; i < urb->actual_length && !acm->throttle; i++) { | 323 | return; |
311 | /* if we insert more than TTY_FLIPBUF_SIZE characters, | 324 | |
312 | * we drop them. */ | 325 | next_buffer: |
313 | if (tty->flip.count >= TTY_FLIPBUF_SIZE) { | 326 | spin_lock(&acm->read_lock); |
314 | tty_flip_buffer_push(tty); | 327 | if (list_empty(&acm->filled_read_bufs)) { |
315 | } | 328 | spin_unlock(&acm->read_lock); |
316 | tty_insert_flip_char(tty, data[i], 0); | 329 | goto urbs; |
317 | } | ||
318 | dbg("Handed %d bytes to tty layer", i+1); | ||
319 | tty_flip_buffer_push(tty); | ||
320 | } | 330 | } |
331 | buf = list_entry(acm->filled_read_bufs.next, | ||
332 | struct acm_rb, list); | ||
333 | list_del(&buf->list); | ||
334 | spin_unlock(&acm->read_lock); | ||
335 | |||
336 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size); | ||
337 | |||
338 | for (i = 0; i < buf->size && !acm->throttle; i++) { | ||
339 | /* if we insert more than TTY_FLIPBUF_SIZE characters, | ||
340 | we drop them. */ | ||
341 | if (tty->flip.count >= TTY_FLIPBUF_SIZE) { | ||
342 | tty_flip_buffer_push(tty); | ||
343 | } | ||
344 | tty_insert_flip_char(tty, buf->base[i], 0); | ||
345 | } | ||
346 | tty_flip_buffer_push(tty); | ||
321 | 347 | ||
322 | spin_lock(&acm->throttle_lock); | 348 | spin_lock(&acm->throttle_lock); |
323 | if (acm->throttle) { | 349 | if (acm->throttle) { |
324 | dbg("Throtteling noticed"); | 350 | dbg("Throtteling noticed"); |
325 | memmove(data, data + i, urb->actual_length - i); | 351 | memmove(buf->base, buf->base + i, buf->size - i); |
326 | urb->actual_length -= i; | 352 | buf->size -= i; |
327 | acm->resubmit_to_unthrottle = 1; | ||
328 | spin_unlock(&acm->throttle_lock); | 353 | spin_unlock(&acm->throttle_lock); |
354 | spin_lock(&acm->read_lock); | ||
355 | list_add(&buf->list, &acm->filled_read_bufs); | ||
356 | spin_unlock(&acm->read_lock); | ||
329 | return; | 357 | return; |
330 | } | 358 | } |
331 | spin_unlock(&acm->throttle_lock); | 359 | spin_unlock(&acm->throttle_lock); |
332 | 360 | ||
333 | urb->actual_length = 0; | 361 | spin_lock(&acm->read_lock); |
334 | urb->dev = acm->dev; | 362 | list_add(&buf->list, &acm->spare_read_bufs); |
335 | 363 | spin_unlock(&acm->read_lock); | |
336 | i = usb_submit_urb(urb, GFP_ATOMIC); | 364 | goto next_buffer; |
337 | if (i) | 365 | |
338 | dev_dbg(&acm->data->dev, "bulk rx resubmit %d\n", i); | 366 | urbs: |
367 | while (!list_empty(&acm->spare_read_bufs)) { | ||
368 | spin_lock(&acm->read_lock); | ||
369 | if (list_empty(&acm->spare_read_urbs)) { | ||
370 | spin_unlock(&acm->read_lock); | ||
371 | return; | ||
372 | } | ||
373 | rcv = list_entry(acm->spare_read_urbs.next, | ||
374 | struct acm_ru, list); | ||
375 | list_del(&rcv->list); | ||
376 | spin_unlock(&acm->read_lock); | ||
377 | |||
378 | buf = list_entry(acm->spare_read_bufs.next, | ||
379 | struct acm_rb, list); | ||
380 | list_del(&buf->list); | ||
381 | |||
382 | rcv->buffer = buf; | ||
383 | |||
384 | usb_fill_bulk_urb(rcv->urb, acm->dev, | ||
385 | acm->rx_endpoint, | ||
386 | buf->base, | ||
387 | acm->readsize, | ||
388 | acm_read_bulk, rcv); | ||
389 | rcv->urb->transfer_dma = buf->dma; | ||
390 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
391 | |||
392 | dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf); | ||
393 | |||
394 | /* This shouldn't kill the driver as unsuccessful URBs are returned to the | ||
395 | free-urbs-pool and resubmited ASAP */ | ||
396 | if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | ||
397 | list_add(&buf->list, &acm->spare_read_bufs); | ||
398 | spin_lock(&acm->read_lock); | ||
399 | list_add(&rcv->list, &acm->spare_read_urbs); | ||
400 | spin_unlock(&acm->read_lock); | ||
401 | return; | ||
402 | } | ||
403 | } | ||
339 | } | 404 | } |
340 | 405 | ||
341 | /* data interface wrote those outgoing bytes */ | 406 | /* data interface wrote those outgoing bytes */ |
@@ -369,6 +434,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
369 | { | 434 | { |
370 | struct acm *acm; | 435 | struct acm *acm; |
371 | int rv = -EINVAL; | 436 | int rv = -EINVAL; |
437 | int i; | ||
372 | dbg("Entering acm_tty_open.\n"); | 438 | dbg("Entering acm_tty_open.\n"); |
373 | 439 | ||
374 | down(&open_sem); | 440 | down(&open_sem); |
@@ -382,7 +448,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
382 | tty->driver_data = acm; | 448 | tty->driver_data = acm; |
383 | acm->tty = tty; | 449 | acm->tty = tty; |
384 | 450 | ||
385 | 451 | /* force low_latency on so that our tty_push actually forces the data through, | |
452 | otherwise it is scheduled, and with high data rates data can get lost. */ | ||
453 | tty->low_latency = 1; | ||
386 | 454 | ||
387 | if (acm->used++) { | 455 | if (acm->used++) { |
388 | goto done; | 456 | goto done; |
@@ -394,18 +462,20 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
394 | goto bail_out; | 462 | goto bail_out; |
395 | } | 463 | } |
396 | 464 | ||
397 | acm->readurb->dev = acm->dev; | ||
398 | if (usb_submit_urb(acm->readurb, GFP_KERNEL)) { | ||
399 | dbg("usb_submit_urb(read bulk) failed"); | ||
400 | goto bail_out_and_unlink; | ||
401 | } | ||
402 | |||
403 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) | 465 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) |
404 | goto full_bailout; | 466 | goto full_bailout; |
405 | 467 | ||
406 | /* force low_latency on so that our tty_push actually forces the data through, | 468 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
407 | otherwise it is scheduled, and with high data rates data can get lost. */ | 469 | INIT_LIST_HEAD(&acm->spare_read_bufs); |
408 | tty->low_latency = 1; | 470 | INIT_LIST_HEAD(&acm->filled_read_bufs); |
471 | for (i = 0; i < ACM_NRU; i++) { | ||
472 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); | ||
473 | } | ||
474 | for (i = 0; i < ACM_NRB; i++) { | ||
475 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | ||
476 | } | ||
477 | |||
478 | tasklet_schedule(&acm->urb_task); | ||
409 | 479 | ||
410 | done: | 480 | done: |
411 | err_out: | 481 | err_out: |
@@ -413,8 +483,6 @@ err_out: | |||
413 | return rv; | 483 | return rv; |
414 | 484 | ||
415 | full_bailout: | 485 | full_bailout: |
416 | usb_kill_urb(acm->readurb); | ||
417 | bail_out_and_unlink: | ||
418 | usb_kill_urb(acm->ctrlurb); | 486 | usb_kill_urb(acm->ctrlurb); |
419 | bail_out: | 487 | bail_out: |
420 | acm->used--; | 488 | acm->used--; |
@@ -424,18 +492,22 @@ bail_out: | |||
424 | 492 | ||
425 | static void acm_tty_unregister(struct acm *acm) | 493 | static void acm_tty_unregister(struct acm *acm) |
426 | { | 494 | { |
495 | int i; | ||
496 | |||
427 | tty_unregister_device(acm_tty_driver, acm->minor); | 497 | tty_unregister_device(acm_tty_driver, acm->minor); |
428 | usb_put_intf(acm->control); | 498 | usb_put_intf(acm->control); |
429 | acm_table[acm->minor] = NULL; | 499 | acm_table[acm->minor] = NULL; |
430 | usb_free_urb(acm->ctrlurb); | 500 | usb_free_urb(acm->ctrlurb); |
431 | usb_free_urb(acm->readurb); | ||
432 | usb_free_urb(acm->writeurb); | 501 | usb_free_urb(acm->writeurb); |
502 | for (i = 0; i < ACM_NRU; i++) | ||
503 | usb_free_urb(acm->ru[i].urb); | ||
433 | kfree(acm); | 504 | kfree(acm); |
434 | } | 505 | } |
435 | 506 | ||
436 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 507 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
437 | { | 508 | { |
438 | struct acm *acm = tty->driver_data; | 509 | struct acm *acm = tty->driver_data; |
510 | int i; | ||
439 | 511 | ||
440 | if (!acm || !acm->used) | 512 | if (!acm || !acm->used) |
441 | return; | 513 | return; |
@@ -446,7 +518,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
446 | acm_set_control(acm, acm->ctrlout = 0); | 518 | acm_set_control(acm, acm->ctrlout = 0); |
447 | usb_kill_urb(acm->ctrlurb); | 519 | usb_kill_urb(acm->ctrlurb); |
448 | usb_kill_urb(acm->writeurb); | 520 | usb_kill_urb(acm->writeurb); |
449 | usb_kill_urb(acm->readurb); | 521 | for (i = 0; i < ACM_NRU; i++) |
522 | usb_kill_urb(acm->ru[i].urb); | ||
450 | } else | 523 | } else |
451 | acm_tty_unregister(acm); | 524 | acm_tty_unregister(acm); |
452 | } | 525 | } |
@@ -528,10 +601,7 @@ static void acm_tty_unthrottle(struct tty_struct *tty) | |||
528 | spin_lock_bh(&acm->throttle_lock); | 601 | spin_lock_bh(&acm->throttle_lock); |
529 | acm->throttle = 0; | 602 | acm->throttle = 0; |
530 | spin_unlock_bh(&acm->throttle_lock); | 603 | spin_unlock_bh(&acm->throttle_lock); |
531 | if (acm->resubmit_to_unthrottle) { | 604 | tasklet_schedule(&acm->urb_task); |
532 | acm->resubmit_to_unthrottle = 0; | ||
533 | acm_read_bulk(acm->readurb, NULL); | ||
534 | } | ||
535 | } | 605 | } |
536 | 606 | ||
537 | static void acm_tty_break_ctl(struct tty_struct *tty, int state) | 607 | static void acm_tty_break_ctl(struct tty_struct *tty, int state) |
@@ -694,6 +764,7 @@ static int acm_probe (struct usb_interface *intf, | |||
694 | int call_interface_num = -1; | 764 | int call_interface_num = -1; |
695 | int data_interface_num; | 765 | int data_interface_num; |
696 | unsigned long quirks; | 766 | unsigned long quirks; |
767 | int i; | ||
697 | 768 | ||
698 | /* handle quirks deadly to normal probing*/ | 769 | /* handle quirks deadly to normal probing*/ |
699 | quirks = (unsigned long)id->driver_info; | 770 | quirks = (unsigned long)id->driver_info; |
@@ -833,7 +904,7 @@ skip_normal_probe: | |||
833 | } | 904 | } |
834 | 905 | ||
835 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); | 906 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); |
836 | readsize = le16_to_cpu(epread->wMaxPacketSize); | 907 | readsize = le16_to_cpu(epread->wMaxPacketSize)*2; |
837 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); | 908 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); |
838 | acm->control = control_interface; | 909 | acm->control = control_interface; |
839 | acm->data = data_interface; | 910 | acm->data = data_interface; |
@@ -842,12 +913,14 @@ skip_normal_probe: | |||
842 | acm->ctrl_caps = ac_management_function; | 913 | acm->ctrl_caps = ac_management_function; |
843 | acm->ctrlsize = ctrlsize; | 914 | acm->ctrlsize = ctrlsize; |
844 | acm->readsize = readsize; | 915 | acm->readsize = readsize; |
845 | acm->bh.func = acm_rx_tasklet; | 916 | acm->urb_task.func = acm_rx_tasklet; |
846 | acm->bh.data = (unsigned long) acm; | 917 | acm->urb_task.data = (unsigned long) acm; |
847 | INIT_WORK(&acm->work, acm_softint, acm); | 918 | INIT_WORK(&acm->work, acm_softint, acm); |
848 | spin_lock_init(&acm->throttle_lock); | 919 | spin_lock_init(&acm->throttle_lock); |
849 | spin_lock_init(&acm->write_lock); | 920 | spin_lock_init(&acm->write_lock); |
921 | spin_lock_init(&acm->read_lock); | ||
850 | acm->write_ready = 1; | 922 | acm->write_ready = 1; |
923 | acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); | ||
851 | 924 | ||
852 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); | 925 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); |
853 | if (!buf) { | 926 | if (!buf) { |
@@ -856,13 +929,6 @@ skip_normal_probe: | |||
856 | } | 929 | } |
857 | acm->ctrl_buffer = buf; | 930 | acm->ctrl_buffer = buf; |
858 | 931 | ||
859 | buf = usb_buffer_alloc(usb_dev, readsize, GFP_KERNEL, &acm->read_dma); | ||
860 | if (!buf) { | ||
861 | dev_dbg(&intf->dev, "out of memory (read buffer alloc)\n"); | ||
862 | goto alloc_fail3; | ||
863 | } | ||
864 | acm->read_buffer = buf; | ||
865 | |||
866 | if (acm_write_buffers_alloc(acm) < 0) { | 932 | if (acm_write_buffers_alloc(acm) < 0) { |
867 | dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); | 933 | dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); |
868 | goto alloc_fail4; | 934 | goto alloc_fail4; |
@@ -873,10 +939,25 @@ skip_normal_probe: | |||
873 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); | 939 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); |
874 | goto alloc_fail5; | 940 | goto alloc_fail5; |
875 | } | 941 | } |
876 | acm->readurb = usb_alloc_urb(0, GFP_KERNEL); | 942 | for (i = 0; i < ACM_NRU; i++) { |
877 | if (!acm->readurb) { | 943 | struct acm_ru *rcv = &(acm->ru[i]); |
878 | dev_dbg(&intf->dev, "out of memory (readurb kmalloc)\n"); | 944 | |
879 | goto alloc_fail6; | 945 | if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { |
946 | dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); | ||
947 | goto alloc_fail7; | ||
948 | } | ||
949 | |||
950 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
951 | rcv->instance = acm; | ||
952 | } | ||
953 | for (i = 0; i < ACM_NRB; i++) { | ||
954 | struct acm_rb *buf = &(acm->rb[i]); | ||
955 | |||
956 | // Using usb_buffer_alloc instead of kmalloc as Oliver suggested | ||
957 | if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { | ||
958 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); | ||
959 | goto alloc_fail7; | ||
960 | } | ||
880 | } | 961 | } |
881 | acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); | 962 | acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); |
882 | if (!acm->writeurb) { | 963 | if (!acm->writeurb) { |
@@ -889,15 +970,9 @@ skip_normal_probe: | |||
889 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 970 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
890 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; | 971 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; |
891 | 972 | ||
892 | usb_fill_bulk_urb(acm->readurb, usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress), | ||
893 | acm->read_buffer, readsize, acm_read_bulk, acm); | ||
894 | acm->readurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; | ||
895 | acm->readurb->transfer_dma = acm->read_dma; | ||
896 | |||
897 | usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), | 973 | usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), |
898 | NULL, acm->writesize, acm_write_bulk, acm); | 974 | NULL, acm->writesize, acm_write_bulk, acm); |
899 | acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; | 975 | acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; |
900 | /* acm->writeurb->transfer_dma = 0; */ | ||
901 | 976 | ||
902 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); | 977 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); |
903 | 978 | ||
@@ -917,14 +992,14 @@ skip_normal_probe: | |||
917 | return 0; | 992 | return 0; |
918 | 993 | ||
919 | alloc_fail7: | 994 | alloc_fail7: |
920 | usb_free_urb(acm->readurb); | 995 | for (i = 0; i < ACM_NRB; i++) |
921 | alloc_fail6: | 996 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
997 | for (i = 0; i < ACM_NRU; i++) | ||
998 | usb_free_urb(acm->ru[i].urb); | ||
922 | usb_free_urb(acm->ctrlurb); | 999 | usb_free_urb(acm->ctrlurb); |
923 | alloc_fail5: | 1000 | alloc_fail5: |
924 | acm_write_buffers_free(acm); | 1001 | acm_write_buffers_free(acm); |
925 | alloc_fail4: | 1002 | alloc_fail4: |
926 | usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma); | ||
927 | alloc_fail3: | ||
928 | usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1003 | usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
929 | alloc_fail2: | 1004 | alloc_fail2: |
930 | kfree(acm); | 1005 | kfree(acm); |
@@ -936,6 +1011,7 @@ static void acm_disconnect(struct usb_interface *intf) | |||
936 | { | 1011 | { |
937 | struct acm *acm = usb_get_intfdata (intf); | 1012 | struct acm *acm = usb_get_intfdata (intf); |
938 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1013 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1014 | int i; | ||
939 | 1015 | ||
940 | if (!acm || !acm->dev) { | 1016 | if (!acm || !acm->dev) { |
941 | dbg("disconnect on nonexisting interface"); | 1017 | dbg("disconnect on nonexisting interface"); |
@@ -946,15 +1022,24 @@ static void acm_disconnect(struct usb_interface *intf) | |||
946 | acm->dev = NULL; | 1022 | acm->dev = NULL; |
947 | usb_set_intfdata (intf, NULL); | 1023 | usb_set_intfdata (intf, NULL); |
948 | 1024 | ||
1025 | tasklet_disable(&acm->urb_task); | ||
1026 | |||
949 | usb_kill_urb(acm->ctrlurb); | 1027 | usb_kill_urb(acm->ctrlurb); |
950 | usb_kill_urb(acm->readurb); | ||
951 | usb_kill_urb(acm->writeurb); | 1028 | usb_kill_urb(acm->writeurb); |
1029 | for (i = 0; i < ACM_NRU; i++) | ||
1030 | usb_kill_urb(acm->ru[i].urb); | ||
1031 | |||
1032 | INIT_LIST_HEAD(&acm->filled_read_bufs); | ||
1033 | INIT_LIST_HEAD(&acm->spare_read_bufs); | ||
1034 | |||
1035 | tasklet_enable(&acm->urb_task); | ||
952 | 1036 | ||
953 | flush_scheduled_work(); /* wait for acm_softint */ | 1037 | flush_scheduled_work(); /* wait for acm_softint */ |
954 | 1038 | ||
955 | acm_write_buffers_free(acm); | 1039 | acm_write_buffers_free(acm); |
956 | usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma); | ||
957 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1040 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1041 | for (i = 0; i < ACM_NRB; i++) | ||
1042 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | ||
958 | 1043 | ||
959 | usb_driver_release_interface(&acm_driver, acm->data); | 1044 | usb_driver_release_interface(&acm_driver, acm->data); |
960 | 1045 | ||
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 963a5dfd2096..fd2aaccdcbac 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h | |||
@@ -59,6 +59,9 @@ | |||
59 | * when processing onlcr, so we only need 2 buffers. | 59 | * when processing onlcr, so we only need 2 buffers. |
60 | */ | 60 | */ |
61 | #define ACM_NWB 2 | 61 | #define ACM_NWB 2 |
62 | #define ACM_NRU 16 | ||
63 | #define ACM_NRB 16 | ||
64 | |||
62 | struct acm_wb { | 65 | struct acm_wb { |
63 | unsigned char *buf; | 66 | unsigned char *buf; |
64 | dma_addr_t dmah; | 67 | dma_addr_t dmah; |
@@ -66,22 +69,43 @@ struct acm_wb { | |||
66 | int use; | 69 | int use; |
67 | }; | 70 | }; |
68 | 71 | ||
72 | struct acm_rb { | ||
73 | struct list_head list; | ||
74 | int size; | ||
75 | unsigned char *base; | ||
76 | dma_addr_t dma; | ||
77 | }; | ||
78 | |||
79 | struct acm_ru { | ||
80 | struct list_head list; | ||
81 | struct acm_rb *buffer; | ||
82 | struct urb *urb; | ||
83 | struct acm *instance; | ||
84 | }; | ||
85 | |||
69 | struct acm { | 86 | struct acm { |
70 | struct usb_device *dev; /* the corresponding usb device */ | 87 | struct usb_device *dev; /* the corresponding usb device */ |
71 | struct usb_interface *control; /* control interface */ | 88 | struct usb_interface *control; /* control interface */ |
72 | struct usb_interface *data; /* data interface */ | 89 | struct usb_interface *data; /* data interface */ |
73 | struct tty_struct *tty; /* the corresponding tty */ | 90 | struct tty_struct *tty; /* the corresponding tty */ |
74 | struct urb *ctrlurb, *readurb, *writeurb; /* urbs */ | 91 | struct urb *ctrlurb, *writeurb; /* urbs */ |
75 | u8 *ctrl_buffer, *read_buffer; /* buffers of urbs */ | 92 | u8 *ctrl_buffer; /* buffers of urbs */ |
76 | dma_addr_t ctrl_dma, read_dma; /* dma handles of buffers */ | 93 | dma_addr_t ctrl_dma; /* dma handles of buffers */ |
77 | struct acm_wb wb[ACM_NWB]; | 94 | struct acm_wb wb[ACM_NWB]; |
95 | struct acm_ru ru[ACM_NRU]; | ||
96 | struct acm_rb rb[ACM_NRB]; | ||
97 | int rx_endpoint; | ||
98 | spinlock_t read_lock; | ||
99 | struct list_head spare_read_urbs; | ||
100 | struct list_head spare_read_bufs; | ||
101 | struct list_head filled_read_bufs; | ||
78 | int write_current; /* current write buffer */ | 102 | int write_current; /* current write buffer */ |
79 | int write_used; /* number of non-empty write buffers */ | 103 | int write_used; /* number of non-empty write buffers */ |
80 | int write_ready; /* write urb is not running */ | 104 | int write_ready; /* write urb is not running */ |
81 | spinlock_t write_lock; | 105 | spinlock_t write_lock; |
82 | struct usb_cdc_line_coding line; /* bits, stop, parity */ | 106 | struct usb_cdc_line_coding line; /* bits, stop, parity */ |
83 | struct work_struct work; /* work queue entry for line discipline waking up */ | 107 | struct work_struct work; /* work queue entry for line discipline waking up */ |
84 | struct tasklet_struct bh; /* rx processing */ | 108 | struct tasklet_struct urb_task; /* rx processing */ |
85 | spinlock_t throttle_lock; /* synchronize throtteling and read callback */ | 109 | spinlock_t throttle_lock; /* synchronize throtteling and read callback */ |
86 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ | 110 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ |
87 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ | 111 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ |
@@ -91,7 +115,6 @@ struct acm { | |||
91 | unsigned int minor; /* acm minor number */ | 115 | unsigned int minor; /* acm minor number */ |
92 | unsigned char throttle; /* throttled by tty layer */ | 116 | unsigned char throttle; /* throttled by tty layer */ |
93 | unsigned char clocal; /* termios CLOCAL */ | 117 | unsigned char clocal; /* termios CLOCAL */ |
94 | unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */ | ||
95 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ | 118 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ |
96 | }; | 119 | }; |
97 | 120 | ||