diff options
| author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-07-22 03:12:37 -0400 |
|---|---|---|
| committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-07-22 03:12:37 -0400 |
| commit | 8725f25acc656c1522d48a6746055099efdaca4c (patch) | |
| tree | e241424fa58178ed6c2a95a4eb931ea83dbea33c /drivers/usb/class/cdc-acm.c | |
| parent | c69cccc95fe4b90dde5fe33e6a3b77880b534fa4 (diff) | |
| parent | 93ded9b8fd42abe2c3607097963d8de6ad9117eb (diff) | |
Merge commit 'origin/master'
Manually fixed up:
drivers/net/fs_enet/fs_enet-main.c
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 177 |
1 files changed, 143 insertions, 34 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index c3201affa0b6..95ae6377d7e5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -159,12 +159,34 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb) | |||
| 159 | spin_lock_irqsave(&acm->write_lock, flags); | 159 | spin_lock_irqsave(&acm->write_lock, flags); |
| 160 | acm->write_ready = 1; | 160 | acm->write_ready = 1; |
| 161 | wb->use = 0; | 161 | wb->use = 0; |
| 162 | acm->transmitting--; | ||
| 162 | spin_unlock_irqrestore(&acm->write_lock, flags); | 163 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| 163 | } | 164 | } |
| 164 | 165 | ||
| 165 | /* | 166 | /* |
| 166 | * Poke write. | 167 | * Poke write. |
| 168 | * | ||
| 169 | * the caller is responsible for locking | ||
| 167 | */ | 170 | */ |
| 171 | |||
| 172 | static int acm_start_wb(struct acm *acm, struct acm_wb *wb) | ||
| 173 | { | ||
| 174 | int rc; | ||
| 175 | |||
| 176 | acm->transmitting++; | ||
| 177 | |||
| 178 | wb->urb->transfer_buffer = wb->buf; | ||
| 179 | wb->urb->transfer_dma = wb->dmah; | ||
| 180 | wb->urb->transfer_buffer_length = wb->len; | ||
| 181 | wb->urb->dev = acm->dev; | ||
| 182 | |||
| 183 | if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { | ||
| 184 | dbg("usb_submit_urb(write bulk) failed: %d", rc); | ||
| 185 | acm_write_done(acm, wb); | ||
| 186 | } | ||
| 187 | return rc; | ||
| 188 | } | ||
| 189 | |||
| 168 | static int acm_write_start(struct acm *acm, int wbn) | 190 | static int acm_write_start(struct acm *acm, int wbn) |
| 169 | { | 191 | { |
| 170 | unsigned long flags; | 192 | unsigned long flags; |
| @@ -182,26 +204,31 @@ static int acm_write_start(struct acm *acm, int wbn) | |||
| 182 | return 0; /* A white lie */ | 204 | return 0; /* A white lie */ |
| 183 | } | 205 | } |
| 184 | 206 | ||
| 207 | wb = &acm->wb[wbn]; | ||
| 208 | if(acm_wb_is_avail(acm) <= 1) | ||
| 209 | acm->write_ready = 0; | ||
| 210 | |||
| 211 | dbg("%s susp_count: %d", __func__, acm->susp_count); | ||
| 212 | if (acm->susp_count) { | ||
| 213 | acm->old_ready = acm->write_ready; | ||
| 214 | acm->delayed_wb = wb; | ||
| 215 | acm->write_ready = 0; | ||
| 216 | schedule_work(&acm->waker); | ||
| 217 | spin_unlock_irqrestore(&acm->write_lock, flags); | ||
| 218 | return 0; /* A white lie */ | ||
| 219 | } | ||
| 220 | usb_mark_last_busy(acm->dev); | ||
| 221 | |||
| 185 | if (!acm_wb_is_used(acm, wbn)) { | 222 | if (!acm_wb_is_used(acm, wbn)) { |
| 186 | spin_unlock_irqrestore(&acm->write_lock, flags); | 223 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| 187 | return 0; | 224 | return 0; |
| 188 | } | 225 | } |
| 189 | wb = &acm->wb[wbn]; | ||
| 190 | 226 | ||
| 191 | if(acm_wb_is_avail(acm) <= 1) | 227 | rc = acm_start_wb(acm, wb); |
| 192 | acm->write_ready = 0; | ||
| 193 | spin_unlock_irqrestore(&acm->write_lock, flags); | 228 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| 194 | 229 | ||
| 195 | wb->urb->transfer_buffer = wb->buf; | ||
| 196 | wb->urb->transfer_dma = wb->dmah; | ||
| 197 | wb->urb->transfer_buffer_length = wb->len; | ||
| 198 | wb->urb->dev = acm->dev; | ||
| 199 | |||
| 200 | if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { | ||
| 201 | dbg("usb_submit_urb(write bulk) failed: %d", rc); | ||
| 202 | acm_write_done(acm, wb); | ||
| 203 | } | ||
| 204 | return rc; | 230 | return rc; |
| 231 | |||
| 205 | } | 232 | } |
| 206 | /* | 233 | /* |
| 207 | * attributes exported through sysfs | 234 | * attributes exported through sysfs |
| @@ -304,6 +331,7 @@ static void acm_ctrl_irq(struct urb *urb) | |||
| 304 | break; | 331 | break; |
| 305 | } | 332 | } |
| 306 | exit: | 333 | exit: |
| 334 | usb_mark_last_busy(acm->dev); | ||
| 307 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 335 | retval = usb_submit_urb (urb, GFP_ATOMIC); |
| 308 | if (retval) | 336 | if (retval) |
| 309 | err ("%s - usb_submit_urb failed with result %d", | 337 | err ("%s - usb_submit_urb failed with result %d", |
| @@ -320,8 +348,11 @@ static void acm_read_bulk(struct urb *urb) | |||
| 320 | 348 | ||
| 321 | dbg("Entering acm_read_bulk with status %d", status); | 349 | dbg("Entering acm_read_bulk with status %d", status); |
| 322 | 350 | ||
| 323 | if (!ACM_READY(acm)) | 351 | if (!ACM_READY(acm)) { |
| 352 | dev_dbg(&acm->data->dev, "Aborting, acm not ready"); | ||
| 324 | return; | 353 | return; |
| 354 | } | ||
| 355 | usb_mark_last_busy(acm->dev); | ||
| 325 | 356 | ||
| 326 | if (status) | 357 | if (status) |
| 327 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", status); | 358 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", status); |
| @@ -331,6 +362,7 @@ static void acm_read_bulk(struct urb *urb) | |||
| 331 | 362 | ||
| 332 | if (likely(status == 0)) { | 363 | if (likely(status == 0)) { |
| 333 | spin_lock(&acm->read_lock); | 364 | spin_lock(&acm->read_lock); |
| 365 | acm->processing++; | ||
| 334 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | 366 | list_add_tail(&rcv->list, &acm->spare_read_urbs); |
| 335 | list_add_tail(&buf->list, &acm->filled_read_bufs); | 367 | list_add_tail(&buf->list, &acm->filled_read_bufs); |
| 336 | spin_unlock(&acm->read_lock); | 368 | spin_unlock(&acm->read_lock); |
| @@ -343,7 +375,8 @@ static void acm_read_bulk(struct urb *urb) | |||
| 343 | /* nevertheless the tasklet must be kicked unconditionally | 375 | /* nevertheless the tasklet must be kicked unconditionally |
| 344 | so the queue cannot dry up */ | 376 | so the queue cannot dry up */ |
| 345 | } | 377 | } |
| 346 | tasklet_schedule(&acm->urb_task); | 378 | if (likely(!acm->susp_count)) |
| 379 | tasklet_schedule(&acm->urb_task); | ||
| 347 | } | 380 | } |
| 348 | 381 | ||
| 349 | static void acm_rx_tasklet(unsigned long _acm) | 382 | static void acm_rx_tasklet(unsigned long _acm) |
| @@ -354,16 +387,23 @@ static void acm_rx_tasklet(unsigned long _acm) | |||
| 354 | struct acm_ru *rcv; | 387 | struct acm_ru *rcv; |
| 355 | unsigned long flags; | 388 | unsigned long flags; |
| 356 | unsigned char throttled; | 389 | unsigned char throttled; |
| 390 | |||
| 357 | dbg("Entering acm_rx_tasklet"); | 391 | dbg("Entering acm_rx_tasklet"); |
| 358 | 392 | ||
| 359 | if (!ACM_READY(acm)) | 393 | if (!ACM_READY(acm)) |
| 394 | { | ||
| 395 | dbg("acm_rx_tasklet: ACM not ready"); | ||
| 360 | return; | 396 | return; |
| 397 | } | ||
| 361 | 398 | ||
| 362 | spin_lock_irqsave(&acm->throttle_lock, flags); | 399 | spin_lock_irqsave(&acm->throttle_lock, flags); |
| 363 | throttled = acm->throttle; | 400 | throttled = acm->throttle; |
| 364 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | 401 | spin_unlock_irqrestore(&acm->throttle_lock, flags); |
| 365 | if (throttled) | 402 | if (throttled) |
| 403 | { | ||
| 404 | dbg("acm_rx_tasklet: throttled"); | ||
| 366 | return; | 405 | return; |
| 406 | } | ||
| 367 | 407 | ||
| 368 | next_buffer: | 408 | next_buffer: |
| 369 | spin_lock_irqsave(&acm->read_lock, flags); | 409 | spin_lock_irqsave(&acm->read_lock, flags); |
| @@ -403,6 +443,7 @@ urbs: | |||
| 403 | while (!list_empty(&acm->spare_read_bufs)) { | 443 | while (!list_empty(&acm->spare_read_bufs)) { |
| 404 | spin_lock_irqsave(&acm->read_lock, flags); | 444 | spin_lock_irqsave(&acm->read_lock, flags); |
| 405 | if (list_empty(&acm->spare_read_urbs)) { | 445 | if (list_empty(&acm->spare_read_urbs)) { |
| 446 | acm->processing = 0; | ||
| 406 | spin_unlock_irqrestore(&acm->read_lock, flags); | 447 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 407 | return; | 448 | return; |
| 408 | } | 449 | } |
| @@ -425,18 +466,23 @@ urbs: | |||
| 425 | rcv->urb->transfer_dma = buf->dma; | 466 | rcv->urb->transfer_dma = buf->dma; |
| 426 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 467 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
| 427 | 468 | ||
| 428 | dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); | ||
| 429 | |||
| 430 | /* This shouldn't kill the driver as unsuccessful URBs are returned to the | 469 | /* This shouldn't kill the driver as unsuccessful URBs are returned to the |
| 431 | free-urbs-pool and resubmited ASAP */ | 470 | free-urbs-pool and resubmited ASAP */ |
| 432 | if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | 471 | spin_lock_irqsave(&acm->read_lock, flags); |
| 472 | if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | ||
| 433 | list_add(&buf->list, &acm->spare_read_bufs); | 473 | list_add(&buf->list, &acm->spare_read_bufs); |
| 434 | spin_lock_irqsave(&acm->read_lock, flags); | ||
| 435 | list_add(&rcv->list, &acm->spare_read_urbs); | 474 | list_add(&rcv->list, &acm->spare_read_urbs); |
| 475 | acm->processing = 0; | ||
| 436 | spin_unlock_irqrestore(&acm->read_lock, flags); | 476 | spin_unlock_irqrestore(&acm->read_lock, flags); |
| 437 | return; | 477 | return; |
| 478 | } else { | ||
| 479 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 480 | dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); | ||
| 438 | } | 481 | } |
| 439 | } | 482 | } |
| 483 | spin_lock_irqsave(&acm->read_lock, flags); | ||
| 484 | acm->processing = 0; | ||
| 485 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 440 | } | 486 | } |
| 441 | 487 | ||
| 442 | /* data interface wrote those outgoing bytes */ | 488 | /* data interface wrote those outgoing bytes */ |
| @@ -463,6 +509,27 @@ static void acm_softint(struct work_struct *work) | |||
| 463 | tty_wakeup(acm->tty); | 509 | tty_wakeup(acm->tty); |
| 464 | } | 510 | } |
| 465 | 511 | ||
| 512 | static void acm_waker(struct work_struct *waker) | ||
| 513 | { | ||
| 514 | struct acm *acm = container_of(waker, struct acm, waker); | ||
| 515 | long flags; | ||
| 516 | int rv; | ||
| 517 | |||
| 518 | rv = usb_autopm_get_interface(acm->control); | ||
| 519 | if (rv < 0) { | ||
| 520 | err("Autopm failure in %s", __func__); | ||
| 521 | return; | ||
| 522 | } | ||
| 523 | if (acm->delayed_wb) { | ||
| 524 | acm_start_wb(acm, acm->delayed_wb); | ||
| 525 | acm->delayed_wb = NULL; | ||
| 526 | } | ||
| 527 | spin_lock_irqsave(&acm->write_lock, flags); | ||
| 528 | acm->write_ready = acm->old_ready; | ||
| 529 | spin_unlock_irqrestore(&acm->write_lock, flags); | ||
| 530 | usb_autopm_put_interface(acm->control); | ||
| 531 | } | ||
| 532 | |||
| 466 | /* | 533 | /* |
| 467 | * TTY handlers | 534 | * TTY handlers |
| 468 | */ | 535 | */ |
| @@ -492,6 +559,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 492 | 559 | ||
| 493 | if (usb_autopm_get_interface(acm->control) < 0) | 560 | if (usb_autopm_get_interface(acm->control) < 0) |
| 494 | goto early_bail; | 561 | goto early_bail; |
| 562 | else | ||
| 563 | acm->control->needs_remote_wakeup = 1; | ||
| 495 | 564 | ||
| 496 | mutex_lock(&acm->mutex); | 565 | mutex_lock(&acm->mutex); |
| 497 | if (acm->used++) { | 566 | if (acm->used++) { |
| @@ -509,6 +578,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 509 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && | 578 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && |
| 510 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) | 579 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) |
| 511 | goto full_bailout; | 580 | goto full_bailout; |
| 581 | usb_autopm_put_interface(acm->control); | ||
| 512 | 582 | ||
| 513 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 583 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
| 514 | INIT_LIST_HEAD(&acm->spare_read_bufs); | 584 | INIT_LIST_HEAD(&acm->spare_read_bufs); |
| @@ -570,12 +640,14 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
| 570 | mutex_lock(&open_mutex); | 640 | mutex_lock(&open_mutex); |
| 571 | if (!--acm->used) { | 641 | if (!--acm->used) { |
| 572 | if (acm->dev) { | 642 | if (acm->dev) { |
| 643 | usb_autopm_get_interface(acm->control); | ||
| 573 | acm_set_control(acm, acm->ctrlout = 0); | 644 | acm_set_control(acm, acm->ctrlout = 0); |
| 574 | usb_kill_urb(acm->ctrlurb); | 645 | usb_kill_urb(acm->ctrlurb); |
| 575 | for (i = 0; i < ACM_NW; i++) | 646 | for (i = 0; i < ACM_NW; i++) |
| 576 | usb_kill_urb(acm->wb[i].urb); | 647 | usb_kill_urb(acm->wb[i].urb); |
| 577 | for (i = 0; i < nr; i++) | 648 | for (i = 0; i < nr; i++) |
| 578 | usb_kill_urb(acm->ru[i].urb); | 649 | usb_kill_urb(acm->ru[i].urb); |
| 650 | acm->control->needs_remote_wakeup = 0; | ||
| 579 | usb_autopm_put_interface(acm->control); | 651 | usb_autopm_put_interface(acm->control); |
| 580 | } else | 652 | } else |
| 581 | acm_tty_unregister(acm); | 653 | acm_tty_unregister(acm); |
| @@ -766,7 +838,7 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios | |||
| 766 | * USB probe and disconnect routines. | 838 | * USB probe and disconnect routines. |
| 767 | */ | 839 | */ |
| 768 | 840 | ||
| 769 | /* Little helper: write buffers free */ | 841 | /* Little helpers: write/read buffers free */ |
| 770 | static void acm_write_buffers_free(struct acm *acm) | 842 | static void acm_write_buffers_free(struct acm *acm) |
| 771 | { | 843 | { |
| 772 | int i; | 844 | int i; |
| @@ -777,6 +849,15 @@ static void acm_write_buffers_free(struct acm *acm) | |||
| 777 | } | 849 | } |
| 778 | } | 850 | } |
| 779 | 851 | ||
| 852 | static void acm_read_buffers_free(struct acm *acm) | ||
| 853 | { | ||
| 854 | struct usb_device *usb_dev = interface_to_usbdev(acm->control); | ||
| 855 | int i, n = acm->rx_buflimit; | ||
| 856 | |||
| 857 | for (i = 0; i < n; i++) | ||
| 858 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | ||
| 859 | } | ||
| 860 | |||
| 780 | /* Little helper: write buffers allocate */ | 861 | /* Little helper: write buffers allocate */ |
| 781 | static int acm_write_buffers_alloc(struct acm *acm) | 862 | static int acm_write_buffers_alloc(struct acm *acm) |
| 782 | { | 863 | { |
| @@ -987,6 +1068,7 @@ skip_normal_probe: | |||
| 987 | acm->urb_task.func = acm_rx_tasklet; | 1068 | acm->urb_task.func = acm_rx_tasklet; |
| 988 | acm->urb_task.data = (unsigned long) acm; | 1069 | acm->urb_task.data = (unsigned long) acm; |
| 989 | INIT_WORK(&acm->work, acm_softint); | 1070 | INIT_WORK(&acm->work, acm_softint); |
| 1071 | INIT_WORK(&acm->waker, acm_waker); | ||
| 990 | spin_lock_init(&acm->throttle_lock); | 1072 | spin_lock_init(&acm->throttle_lock); |
| 991 | spin_lock_init(&acm->write_lock); | 1073 | spin_lock_init(&acm->write_lock); |
| 992 | spin_lock_init(&acm->read_lock); | 1074 | spin_lock_init(&acm->read_lock); |
| @@ -1098,8 +1180,7 @@ alloc_fail8: | |||
| 1098 | for (i = 0; i < ACM_NW; i++) | 1180 | for (i = 0; i < ACM_NW; i++) |
| 1099 | usb_free_urb(acm->wb[i].urb); | 1181 | usb_free_urb(acm->wb[i].urb); |
| 1100 | alloc_fail7: | 1182 | alloc_fail7: |
| 1101 | for (i = 0; i < num_rx_buf; i++) | 1183 | acm_read_buffers_free(acm); |
| 1102 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | ||
| 1103 | for (i = 0; i < num_rx_buf; i++) | 1184 | for (i = 0; i < num_rx_buf; i++) |
| 1104 | usb_free_urb(acm->ru[i].urb); | 1185 | usb_free_urb(acm->ru[i].urb); |
| 1105 | usb_free_urb(acm->ctrlurb); | 1186 | usb_free_urb(acm->ctrlurb); |
| @@ -1116,6 +1197,7 @@ alloc_fail: | |||
| 1116 | static void stop_data_traffic(struct acm *acm) | 1197 | static void stop_data_traffic(struct acm *acm) |
| 1117 | { | 1198 | { |
| 1118 | int i; | 1199 | int i; |
| 1200 | dbg("Entering stop_data_traffic"); | ||
| 1119 | 1201 | ||
| 1120 | tasklet_disable(&acm->urb_task); | 1202 | tasklet_disable(&acm->urb_task); |
| 1121 | 1203 | ||
| @@ -1128,21 +1210,16 @@ static void stop_data_traffic(struct acm *acm) | |||
| 1128 | tasklet_enable(&acm->urb_task); | 1210 | tasklet_enable(&acm->urb_task); |
| 1129 | 1211 | ||
| 1130 | cancel_work_sync(&acm->work); | 1212 | cancel_work_sync(&acm->work); |
| 1213 | cancel_work_sync(&acm->waker); | ||
| 1131 | } | 1214 | } |
| 1132 | 1215 | ||
| 1133 | static void acm_disconnect(struct usb_interface *intf) | 1216 | static void acm_disconnect(struct usb_interface *intf) |
| 1134 | { | 1217 | { |
| 1135 | struct acm *acm = usb_get_intfdata(intf); | 1218 | struct acm *acm = usb_get_intfdata(intf); |
| 1136 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1219 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
| 1137 | int i; | ||
| 1138 | |||
| 1139 | if (!acm || !acm->dev) { | ||
| 1140 | dbg("disconnect on nonexisting interface"); | ||
| 1141 | return; | ||
| 1142 | } | ||
| 1143 | 1220 | ||
| 1144 | mutex_lock(&open_mutex); | 1221 | mutex_lock(&open_mutex); |
| 1145 | if (!usb_get_intfdata(intf)) { | 1222 | if (!acm || !acm->dev) { |
| 1146 | mutex_unlock(&open_mutex); | 1223 | mutex_unlock(&open_mutex); |
| 1147 | return; | 1224 | return; |
| 1148 | } | 1225 | } |
| @@ -1161,10 +1238,10 @@ static void acm_disconnect(struct usb_interface *intf) | |||
| 1161 | 1238 | ||
| 1162 | acm_write_buffers_free(acm); | 1239 | acm_write_buffers_free(acm); |
| 1163 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1240 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
| 1164 | for (i = 0; i < acm->rx_buflimit; i++) | 1241 | acm_read_buffers_free(acm); |
| 1165 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | ||
| 1166 | 1242 | ||
| 1167 | usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf); | 1243 | usb_driver_release_interface(&acm_driver, intf == acm->control ? |
| 1244 | acm->data : acm->control); | ||
| 1168 | 1245 | ||
| 1169 | if (!acm->used) { | 1246 | if (!acm->used) { |
| 1170 | acm_tty_unregister(acm); | 1247 | acm_tty_unregister(acm); |
| @@ -1178,11 +1255,31 @@ static void acm_disconnect(struct usb_interface *intf) | |||
| 1178 | tty_hangup(acm->tty); | 1255 | tty_hangup(acm->tty); |
| 1179 | } | 1256 | } |
| 1180 | 1257 | ||
| 1258 | #ifdef CONFIG_PM | ||
| 1181 | static int acm_suspend(struct usb_interface *intf, pm_message_t message) | 1259 | static int acm_suspend(struct usb_interface *intf, pm_message_t message) |
| 1182 | { | 1260 | { |
| 1183 | struct acm *acm = usb_get_intfdata(intf); | 1261 | struct acm *acm = usb_get_intfdata(intf); |
| 1262 | int cnt; | ||
| 1263 | |||
| 1264 | if (acm->dev->auto_pm) { | ||
| 1265 | int b; | ||
| 1266 | |||
| 1267 | spin_lock_irq(&acm->read_lock); | ||
| 1268 | spin_lock(&acm->write_lock); | ||
| 1269 | b = acm->processing + acm->transmitting; | ||
| 1270 | spin_unlock(&acm->write_lock); | ||
| 1271 | spin_unlock_irq(&acm->read_lock); | ||
| 1272 | if (b) | ||
| 1273 | return -EBUSY; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | spin_lock_irq(&acm->read_lock); | ||
| 1277 | spin_lock(&acm->write_lock); | ||
| 1278 | cnt = acm->susp_count++; | ||
| 1279 | spin_unlock(&acm->write_lock); | ||
| 1280 | spin_unlock_irq(&acm->read_lock); | ||
| 1184 | 1281 | ||
| 1185 | if (acm->susp_count++) | 1282 | if (cnt) |
| 1186 | return 0; | 1283 | return 0; |
| 1187 | /* | 1284 | /* |
| 1188 | we treat opened interfaces differently, | 1285 | we treat opened interfaces differently, |
| @@ -1201,15 +1298,21 @@ static int acm_resume(struct usb_interface *intf) | |||
| 1201 | { | 1298 | { |
| 1202 | struct acm *acm = usb_get_intfdata(intf); | 1299 | struct acm *acm = usb_get_intfdata(intf); |
| 1203 | int rv = 0; | 1300 | int rv = 0; |
| 1301 | int cnt; | ||
| 1302 | |||
| 1303 | spin_lock_irq(&acm->read_lock); | ||
| 1304 | acm->susp_count -= 1; | ||
| 1305 | cnt = acm->susp_count; | ||
| 1306 | spin_unlock_irq(&acm->read_lock); | ||
| 1204 | 1307 | ||
| 1205 | if (--acm->susp_count) | 1308 | if (cnt) |
| 1206 | return 0; | 1309 | return 0; |
| 1207 | 1310 | ||
| 1208 | mutex_lock(&acm->mutex); | 1311 | mutex_lock(&acm->mutex); |
| 1209 | if (acm->used) { | 1312 | if (acm->used) { |
| 1210 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); | 1313 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
| 1211 | if (rv < 0) | 1314 | if (rv < 0) |
| 1212 | goto err_out; | 1315 | goto err_out; |
| 1213 | 1316 | ||
| 1214 | tasklet_schedule(&acm->urb_task); | 1317 | tasklet_schedule(&acm->urb_task); |
| 1215 | } | 1318 | } |
| @@ -1218,6 +1321,8 @@ err_out: | |||
| 1218 | mutex_unlock(&acm->mutex); | 1321 | mutex_unlock(&acm->mutex); |
| 1219 | return rv; | 1322 | return rv; |
| 1220 | } | 1323 | } |
| 1324 | |||
| 1325 | #endif /* CONFIG_PM */ | ||
| 1221 | /* | 1326 | /* |
| 1222 | * USB driver structure. | 1327 | * USB driver structure. |
| 1223 | */ | 1328 | */ |
| @@ -1273,10 +1378,14 @@ static struct usb_driver acm_driver = { | |||
| 1273 | .name = "cdc_acm", | 1378 | .name = "cdc_acm", |
| 1274 | .probe = acm_probe, | 1379 | .probe = acm_probe, |
| 1275 | .disconnect = acm_disconnect, | 1380 | .disconnect = acm_disconnect, |
| 1381 | #ifdef CONFIG_PM | ||
| 1276 | .suspend = acm_suspend, | 1382 | .suspend = acm_suspend, |
| 1277 | .resume = acm_resume, | 1383 | .resume = acm_resume, |
| 1384 | #endif | ||
| 1278 | .id_table = acm_ids, | 1385 | .id_table = acm_ids, |
| 1386 | #ifdef CONFIG_PM | ||
| 1279 | .supports_autosuspend = 1, | 1387 | .supports_autosuspend = 1, |
| 1388 | #endif | ||
| 1280 | }; | 1389 | }; |
| 1281 | 1390 | ||
| 1282 | /* | 1391 | /* |
