diff options
| author | Steve French <sfrench@us.ibm.com> | 2006-01-12 17:47:08 -0500 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2006-01-12 17:47:08 -0500 |
| commit | 94bc2be31a01a3055ec94176e595dfe208e92d3b (patch) | |
| tree | ebfbe81c6718a6390bfa1b99c6d228237d818576 /drivers/usb/class/cdc-acm.c | |
| parent | c32a0b689cb9cc160cfcd19735bbf50bb70c6ef4 (diff) | |
| parent | 58cba4650a7a414eabd2b40cc9d8e45fcdf192d9 (diff) | |
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 227 |
1 files changed, 153 insertions, 74 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 1b4751412970..b9fd39fd1b5b 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,104 @@ 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 | tty_buffer_request_room(tty, buf->size); | ||
| 339 | if (!acm->throttle) | ||
| 340 | tty_insert_flip_string(tty, buf->base, buf->size); | ||
| 341 | tty_flip_buffer_push(tty); | ||
| 321 | 342 | ||
| 322 | spin_lock(&acm->throttle_lock); | 343 | spin_lock(&acm->throttle_lock); |
| 323 | if (acm->throttle) { | 344 | if (acm->throttle) { |
| 324 | dbg("Throtteling noticed"); | 345 | dbg("Throtteling noticed"); |
| 325 | memmove(data, data + i, urb->actual_length - i); | 346 | memmove(buf->base, buf->base + i, buf->size - i); |
| 326 | urb->actual_length -= i; | 347 | buf->size -= i; |
| 327 | acm->resubmit_to_unthrottle = 1; | ||
| 328 | spin_unlock(&acm->throttle_lock); | 348 | spin_unlock(&acm->throttle_lock); |
| 349 | spin_lock(&acm->read_lock); | ||
| 350 | list_add(&buf->list, &acm->filled_read_bufs); | ||
| 351 | spin_unlock(&acm->read_lock); | ||
| 329 | return; | 352 | return; |
| 330 | } | 353 | } |
| 331 | spin_unlock(&acm->throttle_lock); | 354 | spin_unlock(&acm->throttle_lock); |
| 332 | 355 | ||
| 333 | urb->actual_length = 0; | 356 | spin_lock(&acm->read_lock); |
| 334 | urb->dev = acm->dev; | 357 | list_add(&buf->list, &acm->spare_read_bufs); |
| 335 | 358 | spin_unlock(&acm->read_lock); | |
| 336 | i = usb_submit_urb(urb, GFP_ATOMIC); | 359 | goto next_buffer; |
| 337 | if (i) | 360 | |
| 338 | dev_dbg(&acm->data->dev, "bulk rx resubmit %d\n", i); | 361 | urbs: |
| 362 | while (!list_empty(&acm->spare_read_bufs)) { | ||
| 363 | spin_lock(&acm->read_lock); | ||
| 364 | if (list_empty(&acm->spare_read_urbs)) { | ||
| 365 | spin_unlock(&acm->read_lock); | ||
| 366 | return; | ||
| 367 | } | ||
| 368 | rcv = list_entry(acm->spare_read_urbs.next, | ||
| 369 | struct acm_ru, list); | ||
| 370 | list_del(&rcv->list); | ||
| 371 | spin_unlock(&acm->read_lock); | ||
| 372 | |||
| 373 | buf = list_entry(acm->spare_read_bufs.next, | ||
| 374 | struct acm_rb, list); | ||
| 375 | list_del(&buf->list); | ||
| 376 | |||
| 377 | rcv->buffer = buf; | ||
| 378 | |||
| 379 | usb_fill_bulk_urb(rcv->urb, acm->dev, | ||
| 380 | acm->rx_endpoint, | ||
| 381 | buf->base, | ||
| 382 | acm->readsize, | ||
| 383 | acm_read_bulk, rcv); | ||
| 384 | rcv->urb->transfer_dma = buf->dma; | ||
| 385 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 386 | |||
| 387 | dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf); | ||
| 388 | |||
| 389 | /* This shouldn't kill the driver as unsuccessful URBs are returned to the | ||
| 390 | free-urbs-pool and resubmited ASAP */ | ||
| 391 | if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | ||
| 392 | list_add(&buf->list, &acm->spare_read_bufs); | ||
| 393 | spin_lock(&acm->read_lock); | ||
| 394 | list_add(&rcv->list, &acm->spare_read_urbs); | ||
| 395 | spin_unlock(&acm->read_lock); | ||
| 396 | return; | ||
| 397 | } | ||
| 398 | } | ||
| 339 | } | 399 | } |
| 340 | 400 | ||
| 341 | /* data interface wrote those outgoing bytes */ | 401 | /* data interface wrote those outgoing bytes */ |
| @@ -369,6 +429,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 369 | { | 429 | { |
| 370 | struct acm *acm; | 430 | struct acm *acm; |
| 371 | int rv = -EINVAL; | 431 | int rv = -EINVAL; |
| 432 | int i; | ||
| 372 | dbg("Entering acm_tty_open.\n"); | 433 | dbg("Entering acm_tty_open.\n"); |
| 373 | 434 | ||
| 374 | down(&open_sem); | 435 | down(&open_sem); |
| @@ -382,7 +443,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 382 | tty->driver_data = acm; | 443 | tty->driver_data = acm; |
| 383 | acm->tty = tty; | 444 | acm->tty = tty; |
| 384 | 445 | ||
| 385 | 446 | /* force low_latency on so that our tty_push actually forces the data through, | |
| 447 | otherwise it is scheduled, and with high data rates data can get lost. */ | ||
| 448 | tty->low_latency = 1; | ||
| 386 | 449 | ||
| 387 | if (acm->used++) { | 450 | if (acm->used++) { |
| 388 | goto done; | 451 | goto done; |
| @@ -394,18 +457,20 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 394 | goto bail_out; | 457 | goto bail_out; |
| 395 | } | 458 | } |
| 396 | 459 | ||
| 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)) | 460 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) |
| 404 | goto full_bailout; | 461 | goto full_bailout; |
| 405 | 462 | ||
| 406 | /* force low_latency on so that our tty_push actually forces the data through, | 463 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
| 407 | otherwise it is scheduled, and with high data rates data can get lost. */ | 464 | INIT_LIST_HEAD(&acm->spare_read_bufs); |
| 408 | tty->low_latency = 1; | 465 | INIT_LIST_HEAD(&acm->filled_read_bufs); |
| 466 | for (i = 0; i < ACM_NRU; i++) { | ||
| 467 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); | ||
| 468 | } | ||
| 469 | for (i = 0; i < ACM_NRB; i++) { | ||
| 470 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | ||
| 471 | } | ||
| 472 | |||
| 473 | tasklet_schedule(&acm->urb_task); | ||
| 409 | 474 | ||
| 410 | done: | 475 | done: |
| 411 | err_out: | 476 | err_out: |
| @@ -413,8 +478,6 @@ err_out: | |||
| 413 | return rv; | 478 | return rv; |
| 414 | 479 | ||
| 415 | full_bailout: | 480 | full_bailout: |
| 416 | usb_kill_urb(acm->readurb); | ||
| 417 | bail_out_and_unlink: | ||
| 418 | usb_kill_urb(acm->ctrlurb); | 481 | usb_kill_urb(acm->ctrlurb); |
| 419 | bail_out: | 482 | bail_out: |
| 420 | acm->used--; | 483 | acm->used--; |
| @@ -424,18 +487,22 @@ bail_out: | |||
| 424 | 487 | ||
| 425 | static void acm_tty_unregister(struct acm *acm) | 488 | static void acm_tty_unregister(struct acm *acm) |
| 426 | { | 489 | { |
| 490 | int i; | ||
| 491 | |||
| 427 | tty_unregister_device(acm_tty_driver, acm->minor); | 492 | tty_unregister_device(acm_tty_driver, acm->minor); |
| 428 | usb_put_intf(acm->control); | 493 | usb_put_intf(acm->control); |
| 429 | acm_table[acm->minor] = NULL; | 494 | acm_table[acm->minor] = NULL; |
| 430 | usb_free_urb(acm->ctrlurb); | 495 | usb_free_urb(acm->ctrlurb); |
| 431 | usb_free_urb(acm->readurb); | ||
| 432 | usb_free_urb(acm->writeurb); | 496 | usb_free_urb(acm->writeurb); |
| 497 | for (i = 0; i < ACM_NRU; i++) | ||
| 498 | usb_free_urb(acm->ru[i].urb); | ||
| 433 | kfree(acm); | 499 | kfree(acm); |
| 434 | } | 500 | } |
| 435 | 501 | ||
| 436 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 502 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
| 437 | { | 503 | { |
| 438 | struct acm *acm = tty->driver_data; | 504 | struct acm *acm = tty->driver_data; |
| 505 | int i; | ||
| 439 | 506 | ||
| 440 | if (!acm || !acm->used) | 507 | if (!acm || !acm->used) |
| 441 | return; | 508 | return; |
| @@ -446,7 +513,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
| 446 | acm_set_control(acm, acm->ctrlout = 0); | 513 | acm_set_control(acm, acm->ctrlout = 0); |
| 447 | usb_kill_urb(acm->ctrlurb); | 514 | usb_kill_urb(acm->ctrlurb); |
| 448 | usb_kill_urb(acm->writeurb); | 515 | usb_kill_urb(acm->writeurb); |
| 449 | usb_kill_urb(acm->readurb); | 516 | for (i = 0; i < ACM_NRU; i++) |
| 517 | usb_kill_urb(acm->ru[i].urb); | ||
| 450 | } else | 518 | } else |
| 451 | acm_tty_unregister(acm); | 519 | acm_tty_unregister(acm); |
| 452 | } | 520 | } |
| @@ -528,10 +596,7 @@ static void acm_tty_unthrottle(struct tty_struct *tty) | |||
| 528 | spin_lock_bh(&acm->throttle_lock); | 596 | spin_lock_bh(&acm->throttle_lock); |
| 529 | acm->throttle = 0; | 597 | acm->throttle = 0; |
| 530 | spin_unlock_bh(&acm->throttle_lock); | 598 | spin_unlock_bh(&acm->throttle_lock); |
| 531 | if (acm->resubmit_to_unthrottle) { | 599 | tasklet_schedule(&acm->urb_task); |
| 532 | acm->resubmit_to_unthrottle = 0; | ||
| 533 | acm_read_bulk(acm->readurb, NULL); | ||
| 534 | } | ||
| 535 | } | 600 | } |
| 536 | 601 | ||
| 537 | static void acm_tty_break_ctl(struct tty_struct *tty, int state) | 602 | static void acm_tty_break_ctl(struct tty_struct *tty, int state) |
| @@ -588,7 +653,7 @@ static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int | |||
| 588 | return -ENOIOCTLCMD; | 653 | return -ENOIOCTLCMD; |
| 589 | } | 654 | } |
| 590 | 655 | ||
| 591 | static __u32 acm_tty_speed[] = { | 656 | static const __u32 acm_tty_speed[] = { |
| 592 | 0, 50, 75, 110, 134, 150, 200, 300, 600, | 657 | 0, 50, 75, 110, 134, 150, 200, 300, 600, |
| 593 | 1200, 1800, 2400, 4800, 9600, 19200, 38400, | 658 | 1200, 1800, 2400, 4800, 9600, 19200, 38400, |
| 594 | 57600, 115200, 230400, 460800, 500000, 576000, | 659 | 57600, 115200, 230400, 460800, 500000, 576000, |
| @@ -596,7 +661,7 @@ static __u32 acm_tty_speed[] = { | |||
| 596 | 2500000, 3000000, 3500000, 4000000 | 661 | 2500000, 3000000, 3500000, 4000000 |
| 597 | }; | 662 | }; |
| 598 | 663 | ||
| 599 | static __u8 acm_tty_size[] = { | 664 | static const __u8 acm_tty_size[] = { |
| 600 | 5, 6, 7, 8 | 665 | 5, 6, 7, 8 |
| 601 | }; | 666 | }; |
| 602 | 667 | ||
| @@ -694,6 +759,7 @@ static int acm_probe (struct usb_interface *intf, | |||
| 694 | int call_interface_num = -1; | 759 | int call_interface_num = -1; |
| 695 | int data_interface_num; | 760 | int data_interface_num; |
| 696 | unsigned long quirks; | 761 | unsigned long quirks; |
| 762 | int i; | ||
| 697 | 763 | ||
| 698 | /* handle quirks deadly to normal probing*/ | 764 | /* handle quirks deadly to normal probing*/ |
| 699 | quirks = (unsigned long)id->driver_info; | 765 | quirks = (unsigned long)id->driver_info; |
| @@ -833,7 +899,7 @@ skip_normal_probe: | |||
| 833 | } | 899 | } |
| 834 | 900 | ||
| 835 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); | 901 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); |
| 836 | readsize = le16_to_cpu(epread->wMaxPacketSize); | 902 | readsize = le16_to_cpu(epread->wMaxPacketSize)*2; |
| 837 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); | 903 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); |
| 838 | acm->control = control_interface; | 904 | acm->control = control_interface; |
| 839 | acm->data = data_interface; | 905 | acm->data = data_interface; |
| @@ -842,12 +908,14 @@ skip_normal_probe: | |||
| 842 | acm->ctrl_caps = ac_management_function; | 908 | acm->ctrl_caps = ac_management_function; |
| 843 | acm->ctrlsize = ctrlsize; | 909 | acm->ctrlsize = ctrlsize; |
| 844 | acm->readsize = readsize; | 910 | acm->readsize = readsize; |
| 845 | acm->bh.func = acm_rx_tasklet; | 911 | acm->urb_task.func = acm_rx_tasklet; |
| 846 | acm->bh.data = (unsigned long) acm; | 912 | acm->urb_task.data = (unsigned long) acm; |
| 847 | INIT_WORK(&acm->work, acm_softint, acm); | 913 | INIT_WORK(&acm->work, acm_softint, acm); |
| 848 | spin_lock_init(&acm->throttle_lock); | 914 | spin_lock_init(&acm->throttle_lock); |
| 849 | spin_lock_init(&acm->write_lock); | 915 | spin_lock_init(&acm->write_lock); |
| 916 | spin_lock_init(&acm->read_lock); | ||
| 850 | acm->write_ready = 1; | 917 | acm->write_ready = 1; |
| 918 | acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); | ||
| 851 | 919 | ||
| 852 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); | 920 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); |
| 853 | if (!buf) { | 921 | if (!buf) { |
| @@ -856,13 +924,6 @@ skip_normal_probe: | |||
| 856 | } | 924 | } |
| 857 | acm->ctrl_buffer = buf; | 925 | acm->ctrl_buffer = buf; |
| 858 | 926 | ||
| 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) { | 927 | if (acm_write_buffers_alloc(acm) < 0) { |
| 867 | dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); | 928 | dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); |
| 868 | goto alloc_fail4; | 929 | goto alloc_fail4; |
| @@ -873,10 +934,25 @@ skip_normal_probe: | |||
| 873 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); | 934 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); |
| 874 | goto alloc_fail5; | 935 | goto alloc_fail5; |
| 875 | } | 936 | } |
| 876 | acm->readurb = usb_alloc_urb(0, GFP_KERNEL); | 937 | for (i = 0; i < ACM_NRU; i++) { |
| 877 | if (!acm->readurb) { | 938 | struct acm_ru *rcv = &(acm->ru[i]); |
| 878 | dev_dbg(&intf->dev, "out of memory (readurb kmalloc)\n"); | 939 | |
| 879 | goto alloc_fail6; | 940 | if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { |
| 941 | dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); | ||
| 942 | goto alloc_fail7; | ||
| 943 | } | ||
| 944 | |||
| 945 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 946 | rcv->instance = acm; | ||
| 947 | } | ||
| 948 | for (i = 0; i < ACM_NRB; i++) { | ||
| 949 | struct acm_rb *buf = &(acm->rb[i]); | ||
| 950 | |||
| 951 | // Using usb_buffer_alloc instead of kmalloc as Oliver suggested | ||
| 952 | if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { | ||
| 953 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); | ||
| 954 | goto alloc_fail7; | ||
| 955 | } | ||
| 880 | } | 956 | } |
| 881 | acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); | 957 | acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); |
| 882 | if (!acm->writeurb) { | 958 | if (!acm->writeurb) { |
| @@ -889,15 +965,9 @@ skip_normal_probe: | |||
| 889 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 965 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
| 890 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; | 966 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; |
| 891 | 967 | ||
| 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), | 968 | usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), |
| 898 | NULL, acm->writesize, acm_write_bulk, acm); | 969 | NULL, acm->writesize, acm_write_bulk, acm); |
| 899 | acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; | 970 | acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; |
| 900 | /* acm->writeurb->transfer_dma = 0; */ | ||
| 901 | 971 | ||
| 902 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); | 972 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); |
| 903 | 973 | ||
| @@ -917,14 +987,14 @@ skip_normal_probe: | |||
| 917 | return 0; | 987 | return 0; |
| 918 | 988 | ||
| 919 | alloc_fail7: | 989 | alloc_fail7: |
| 920 | usb_free_urb(acm->readurb); | 990 | for (i = 0; i < ACM_NRB; i++) |
| 921 | alloc_fail6: | 991 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
| 992 | for (i = 0; i < ACM_NRU; i++) | ||
| 993 | usb_free_urb(acm->ru[i].urb); | ||
| 922 | usb_free_urb(acm->ctrlurb); | 994 | usb_free_urb(acm->ctrlurb); |
| 923 | alloc_fail5: | 995 | alloc_fail5: |
| 924 | acm_write_buffers_free(acm); | 996 | acm_write_buffers_free(acm); |
| 925 | alloc_fail4: | 997 | 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); | 998 | usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
| 929 | alloc_fail2: | 999 | alloc_fail2: |
| 930 | kfree(acm); | 1000 | kfree(acm); |
| @@ -936,6 +1006,7 @@ static void acm_disconnect(struct usb_interface *intf) | |||
| 936 | { | 1006 | { |
| 937 | struct acm *acm = usb_get_intfdata (intf); | 1007 | struct acm *acm = usb_get_intfdata (intf); |
| 938 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1008 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
| 1009 | int i; | ||
| 939 | 1010 | ||
| 940 | if (!acm || !acm->dev) { | 1011 | if (!acm || !acm->dev) { |
| 941 | dbg("disconnect on nonexisting interface"); | 1012 | dbg("disconnect on nonexisting interface"); |
| @@ -946,15 +1017,24 @@ static void acm_disconnect(struct usb_interface *intf) | |||
| 946 | acm->dev = NULL; | 1017 | acm->dev = NULL; |
| 947 | usb_set_intfdata (intf, NULL); | 1018 | usb_set_intfdata (intf, NULL); |
| 948 | 1019 | ||
| 1020 | tasklet_disable(&acm->urb_task); | ||
| 1021 | |||
| 949 | usb_kill_urb(acm->ctrlurb); | 1022 | usb_kill_urb(acm->ctrlurb); |
| 950 | usb_kill_urb(acm->readurb); | ||
| 951 | usb_kill_urb(acm->writeurb); | 1023 | usb_kill_urb(acm->writeurb); |
| 1024 | for (i = 0; i < ACM_NRU; i++) | ||
| 1025 | usb_kill_urb(acm->ru[i].urb); | ||
| 1026 | |||
| 1027 | INIT_LIST_HEAD(&acm->filled_read_bufs); | ||
| 1028 | INIT_LIST_HEAD(&acm->spare_read_bufs); | ||
| 1029 | |||
| 1030 | tasklet_enable(&acm->urb_task); | ||
| 952 | 1031 | ||
| 953 | flush_scheduled_work(); /* wait for acm_softint */ | 1032 | flush_scheduled_work(); /* wait for acm_softint */ |
| 954 | 1033 | ||
| 955 | acm_write_buffers_free(acm); | 1034 | 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); | 1035 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
| 1036 | for (i = 0; i < ACM_NRB; i++) | ||
| 1037 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | ||
| 958 | 1038 | ||
| 959 | usb_driver_release_interface(&acm_driver, acm->data); | 1039 | usb_driver_release_interface(&acm_driver, acm->data); |
| 960 | 1040 | ||
| @@ -1003,7 +1083,6 @@ static struct usb_device_id acm_ids[] = { | |||
| 1003 | MODULE_DEVICE_TABLE (usb, acm_ids); | 1083 | MODULE_DEVICE_TABLE (usb, acm_ids); |
| 1004 | 1084 | ||
| 1005 | static struct usb_driver acm_driver = { | 1085 | static struct usb_driver acm_driver = { |
| 1006 | .owner = THIS_MODULE, | ||
| 1007 | .name = "cdc_acm", | 1086 | .name = "cdc_acm", |
| 1008 | .probe = acm_probe, | 1087 | .probe = acm_probe, |
| 1009 | .disconnect = acm_disconnect, | 1088 | .disconnect = acm_disconnect, |
