diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 86 |
1 files changed, 46 insertions, 40 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0725b1871f23..efc4373ededb 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | */ | 51 | */ |
| 52 | 52 | ||
| 53 | #undef DEBUG | 53 | #undef DEBUG |
| 54 | #undef VERBOSE_DEBUG | ||
| 54 | 55 | ||
| 55 | #include <linux/kernel.h> | 56 | #include <linux/kernel.h> |
| 56 | #include <linux/errno.h> | 57 | #include <linux/errno.h> |
| @@ -70,6 +71,9 @@ | |||
| 70 | 71 | ||
| 71 | #include "cdc-acm.h" | 72 | #include "cdc-acm.h" |
| 72 | 73 | ||
| 74 | |||
| 75 | #define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */ | ||
| 76 | |||
| 73 | /* | 77 | /* |
| 74 | * Version Information | 78 | * Version Information |
| 75 | */ | 79 | */ |
| @@ -85,6 +89,12 @@ static DEFINE_MUTEX(open_mutex); | |||
| 85 | 89 | ||
| 86 | #define ACM_READY(acm) (acm && acm->dev && acm->used) | 90 | #define ACM_READY(acm) (acm && acm->dev && acm->used) |
| 87 | 91 | ||
| 92 | #ifdef VERBOSE_DEBUG | ||
| 93 | #define verbose 1 | ||
| 94 | #else | ||
| 95 | #define verbose 0 | ||
| 96 | #endif | ||
| 97 | |||
| 88 | /* | 98 | /* |
| 89 | * Functions for ACM control messages. | 99 | * Functions for ACM control messages. |
| 90 | */ | 100 | */ |
| @@ -136,19 +146,17 @@ static int acm_wb_alloc(struct acm *acm) | |||
| 136 | static int acm_wb_is_avail(struct acm *acm) | 146 | static int acm_wb_is_avail(struct acm *acm) |
| 137 | { | 147 | { |
| 138 | int i, n; | 148 | int i, n; |
| 149 | unsigned long flags; | ||
| 139 | 150 | ||
| 140 | n = ACM_NW; | 151 | n = ACM_NW; |
| 152 | spin_lock_irqsave(&acm->write_lock, flags); | ||
| 141 | for (i = 0; i < ACM_NW; i++) { | 153 | for (i = 0; i < ACM_NW; i++) { |
| 142 | n -= acm->wb[i].use; | 154 | n -= acm->wb[i].use; |
| 143 | } | 155 | } |
| 156 | spin_unlock_irqrestore(&acm->write_lock, flags); | ||
| 144 | return n; | 157 | return n; |
| 145 | } | 158 | } |
| 146 | 159 | ||
| 147 | static inline int acm_wb_is_used(struct acm *acm, int wbn) | ||
| 148 | { | ||
| 149 | return acm->wb[wbn].use; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* | 160 | /* |
| 153 | * Finish write. | 161 | * Finish write. |
| 154 | */ | 162 | */ |
| @@ -157,7 +165,6 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb) | |||
| 157 | unsigned long flags; | 165 | unsigned long flags; |
| 158 | 166 | ||
| 159 | spin_lock_irqsave(&acm->write_lock, flags); | 167 | spin_lock_irqsave(&acm->write_lock, flags); |
| 160 | acm->write_ready = 1; | ||
| 161 | wb->use = 0; | 168 | wb->use = 0; |
| 162 | acm->transmitting--; | 169 | acm->transmitting--; |
| 163 | spin_unlock_irqrestore(&acm->write_lock, flags); | 170 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| @@ -190,40 +197,25 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb) | |||
| 190 | static int acm_write_start(struct acm *acm, int wbn) | 197 | static int acm_write_start(struct acm *acm, int wbn) |
| 191 | { | 198 | { |
| 192 | unsigned long flags; | 199 | unsigned long flags; |
| 193 | struct acm_wb *wb; | 200 | struct acm_wb *wb = &acm->wb[wbn]; |
| 194 | int rc; | 201 | int rc; |
| 195 | 202 | ||
| 196 | spin_lock_irqsave(&acm->write_lock, flags); | 203 | spin_lock_irqsave(&acm->write_lock, flags); |
| 197 | if (!acm->dev) { | 204 | if (!acm->dev) { |
| 205 | wb->use = 0; | ||
| 198 | spin_unlock_irqrestore(&acm->write_lock, flags); | 206 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| 199 | return -ENODEV; | 207 | return -ENODEV; |
| 200 | } | 208 | } |
| 201 | 209 | ||
| 202 | if (!acm->write_ready) { | ||
| 203 | spin_unlock_irqrestore(&acm->write_lock, flags); | ||
| 204 | return 0; /* A white lie */ | ||
| 205 | } | ||
| 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); | 210 | dbg("%s susp_count: %d", __func__, acm->susp_count); |
| 212 | if (acm->susp_count) { | 211 | if (acm->susp_count) { |
| 213 | acm->old_ready = acm->write_ready; | ||
| 214 | acm->delayed_wb = wb; | 212 | acm->delayed_wb = wb; |
| 215 | acm->write_ready = 0; | ||
| 216 | schedule_work(&acm->waker); | 213 | schedule_work(&acm->waker); |
| 217 | spin_unlock_irqrestore(&acm->write_lock, flags); | 214 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| 218 | return 0; /* A white lie */ | 215 | return 0; /* A white lie */ |
| 219 | } | 216 | } |
| 220 | usb_mark_last_busy(acm->dev); | 217 | usb_mark_last_busy(acm->dev); |
| 221 | 218 | ||
| 222 | if (!acm_wb_is_used(acm, wbn)) { | ||
| 223 | spin_unlock_irqrestore(&acm->write_lock, flags); | ||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | rc = acm_start_wb(acm, wb); | 219 | rc = acm_start_wb(acm, wb); |
| 228 | spin_unlock_irqrestore(&acm->write_lock, flags); | 220 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| 229 | 221 | ||
| @@ -488,22 +480,28 @@ urbs: | |||
| 488 | /* data interface wrote those outgoing bytes */ | 480 | /* data interface wrote those outgoing bytes */ |
| 489 | static void acm_write_bulk(struct urb *urb) | 481 | static void acm_write_bulk(struct urb *urb) |
| 490 | { | 482 | { |
| 491 | struct acm *acm; | ||
| 492 | struct acm_wb *wb = urb->context; | 483 | struct acm_wb *wb = urb->context; |
| 484 | struct acm *acm = wb->instance; | ||
| 493 | 485 | ||
| 494 | dbg("Entering acm_write_bulk with status %d", urb->status); | 486 | if (verbose || urb->status |
| 487 | || (urb->actual_length != urb->transfer_buffer_length)) | ||
| 488 | dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n", | ||
| 489 | urb->actual_length, | ||
| 490 | urb->transfer_buffer_length, | ||
| 491 | urb->status); | ||
| 495 | 492 | ||
| 496 | acm = wb->instance; | ||
| 497 | acm_write_done(acm, wb); | 493 | acm_write_done(acm, wb); |
| 498 | if (ACM_READY(acm)) | 494 | if (ACM_READY(acm)) |
| 499 | schedule_work(&acm->work); | 495 | schedule_work(&acm->work); |
| 496 | else | ||
| 497 | wake_up_interruptible(&acm->drain_wait); | ||
| 500 | } | 498 | } |
| 501 | 499 | ||
| 502 | static void acm_softint(struct work_struct *work) | 500 | static void acm_softint(struct work_struct *work) |
| 503 | { | 501 | { |
| 504 | struct acm *acm = container_of(work, struct acm, work); | 502 | struct acm *acm = container_of(work, struct acm, work); |
| 505 | dbg("Entering acm_softint."); | 503 | |
| 506 | 504 | dev_vdbg(&acm->data->dev, "tx work\n"); | |
| 507 | if (!ACM_READY(acm)) | 505 | if (!ACM_READY(acm)) |
| 508 | return; | 506 | return; |
| 509 | tty_wakeup(acm->tty); | 507 | tty_wakeup(acm->tty); |
| @@ -512,7 +510,6 @@ static void acm_softint(struct work_struct *work) | |||
| 512 | static void acm_waker(struct work_struct *waker) | 510 | static void acm_waker(struct work_struct *waker) |
| 513 | { | 511 | { |
| 514 | struct acm *acm = container_of(waker, struct acm, waker); | 512 | struct acm *acm = container_of(waker, struct acm, waker); |
| 515 | long flags; | ||
| 516 | int rv; | 513 | int rv; |
| 517 | 514 | ||
| 518 | rv = usb_autopm_get_interface(acm->control); | 515 | rv = usb_autopm_get_interface(acm->control); |
| @@ -524,9 +521,6 @@ static void acm_waker(struct work_struct *waker) | |||
| 524 | acm_start_wb(acm, acm->delayed_wb); | 521 | acm_start_wb(acm, acm->delayed_wb); |
| 525 | acm->delayed_wb = NULL; | 522 | acm->delayed_wb = NULL; |
| 526 | } | 523 | } |
| 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); | 524 | usb_autopm_put_interface(acm->control); |
| 531 | } | 525 | } |
| 532 | 526 | ||
| @@ -628,6 +622,8 @@ static void acm_tty_unregister(struct acm *acm) | |||
| 628 | kfree(acm); | 622 | kfree(acm); |
| 629 | } | 623 | } |
| 630 | 624 | ||
| 625 | static int acm_tty_chars_in_buffer(struct tty_struct *tty); | ||
| 626 | |||
| 631 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 627 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
| 632 | { | 628 | { |
| 633 | struct acm *acm = tty->driver_data; | 629 | struct acm *acm = tty->driver_data; |
| @@ -642,6 +638,13 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
| 642 | if (acm->dev) { | 638 | if (acm->dev) { |
| 643 | usb_autopm_get_interface(acm->control); | 639 | usb_autopm_get_interface(acm->control); |
| 644 | acm_set_control(acm, acm->ctrlout = 0); | 640 | acm_set_control(acm, acm->ctrlout = 0); |
| 641 | |||
| 642 | /* try letting the last writes drain naturally */ | ||
| 643 | wait_event_interruptible_timeout(acm->drain_wait, | ||
| 644 | (ACM_NW == acm_wb_is_avail(acm)) | ||
| 645 | || !acm->dev, | ||
| 646 | ACM_CLOSE_TIMEOUT * HZ); | ||
| 647 | |||
| 645 | usb_kill_urb(acm->ctrlurb); | 648 | usb_kill_urb(acm->ctrlurb); |
| 646 | for (i = 0; i < ACM_NW; i++) | 649 | for (i = 0; i < ACM_NW; i++) |
| 647 | usb_kill_urb(acm->wb[i].urb); | 650 | usb_kill_urb(acm->wb[i].urb); |
| @@ -697,7 +700,7 @@ static int acm_tty_write_room(struct tty_struct *tty) | |||
| 697 | * Do not let the line discipline to know that we have a reserve, | 700 | * Do not let the line discipline to know that we have a reserve, |
| 698 | * or it might get too enthusiastic. | 701 | * or it might get too enthusiastic. |
| 699 | */ | 702 | */ |
| 700 | return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0; | 703 | return acm_wb_is_avail(acm) ? acm->writesize : 0; |
| 701 | } | 704 | } |
| 702 | 705 | ||
| 703 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) | 706 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) |
| @@ -1072,11 +1075,11 @@ skip_normal_probe: | |||
| 1072 | acm->urb_task.data = (unsigned long) acm; | 1075 | acm->urb_task.data = (unsigned long) acm; |
| 1073 | INIT_WORK(&acm->work, acm_softint); | 1076 | INIT_WORK(&acm->work, acm_softint); |
| 1074 | INIT_WORK(&acm->waker, acm_waker); | 1077 | INIT_WORK(&acm->waker, acm_waker); |
| 1078 | init_waitqueue_head(&acm->drain_wait); | ||
| 1075 | spin_lock_init(&acm->throttle_lock); | 1079 | spin_lock_init(&acm->throttle_lock); |
| 1076 | spin_lock_init(&acm->write_lock); | 1080 | spin_lock_init(&acm->write_lock); |
| 1077 | spin_lock_init(&acm->read_lock); | 1081 | spin_lock_init(&acm->read_lock); |
| 1078 | mutex_init(&acm->mutex); | 1082 | mutex_init(&acm->mutex); |
| 1079 | acm->write_ready = 1; | ||
| 1080 | acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); | 1083 | acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); |
| 1081 | 1084 | ||
| 1082 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); | 1085 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); |
| @@ -1108,9 +1111,11 @@ skip_normal_probe: | |||
| 1108 | rcv->instance = acm; | 1111 | rcv->instance = acm; |
| 1109 | } | 1112 | } |
| 1110 | for (i = 0; i < num_rx_buf; i++) { | 1113 | for (i = 0; i < num_rx_buf; i++) { |
| 1111 | struct acm_rb *buf = &(acm->rb[i]); | 1114 | struct acm_rb *rb = &(acm->rb[i]); |
| 1112 | 1115 | ||
| 1113 | if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { | 1116 | rb->base = usb_buffer_alloc(acm->dev, readsize, |
| 1117 | GFP_KERNEL, &rb->dma); | ||
| 1118 | if (!rb->base) { | ||
| 1114 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); | 1119 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); |
| 1115 | goto alloc_fail7; | 1120 | goto alloc_fail7; |
| 1116 | } | 1121 | } |
| @@ -1172,6 +1177,7 @@ skip_countries: | |||
| 1172 | acm_set_line(acm, &acm->line); | 1177 | acm_set_line(acm, &acm->line); |
| 1173 | 1178 | ||
| 1174 | usb_driver_claim_interface(&acm_driver, data_interface, acm); | 1179 | usb_driver_claim_interface(&acm_driver, data_interface, acm); |
| 1180 | usb_set_intfdata(data_interface, acm); | ||
| 1175 | 1181 | ||
| 1176 | usb_get_intf(control_interface); | 1182 | usb_get_intf(control_interface); |
| 1177 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); | 1183 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); |
| @@ -1221,11 +1227,11 @@ static void acm_disconnect(struct usb_interface *intf) | |||
| 1221 | struct acm *acm = usb_get_intfdata(intf); | 1227 | struct acm *acm = usb_get_intfdata(intf); |
| 1222 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1228 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
| 1223 | 1229 | ||
| 1224 | mutex_lock(&open_mutex); | 1230 | /* sibling interface is already cleaning up */ |
| 1225 | if (!acm || !acm->dev) { | 1231 | if (!acm) |
| 1226 | mutex_unlock(&open_mutex); | ||
| 1227 | return; | 1232 | return; |
| 1228 | } | 1233 | |
| 1234 | mutex_lock(&open_mutex); | ||
| 1229 | if (acm->country_codes){ | 1235 | if (acm->country_codes){ |
| 1230 | device_remove_file(&acm->control->dev, | 1236 | device_remove_file(&acm->control->dev, |
| 1231 | &dev_attr_wCountryCodes); | 1237 | &dev_attr_wCountryCodes); |
