diff options
author | Oliver Neukum <oneukum@suse.de> | 2007-02-12 02:41:35 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-16 18:32:21 -0500 |
commit | ca79b7b4158cbf32625793a1fc1d59ac46d44197 (patch) | |
tree | d35d994606f16006b8b103a5eaa636e7ee4a1fe9 | |
parent | 3f141e2aed586c41c2666d49c70c1c1bbb6d6abd (diff) |
USB: cdc-acm: fix incorrect throtteling, make set_control optional
this is Joris' fixes reshuffelled and features renamed as David requested.
- acm_set_control is not mandatory, honour that
- throtteling is reset upon open
- throtteling is read consistently when processing input data
Signed-off-by: Joris van Rantwijk <jorispubl@xs4all.nl>
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 29 | ||||
-rw-r--r-- | include/linux/usb/cdc.h | 7 |
2 files changed, 25 insertions, 11 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 98199628e394..023cf5d45a9d 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -326,10 +326,16 @@ static void acm_rx_tasklet(unsigned long _acm) | |||
326 | struct tty_struct *tty = acm->tty; | 326 | struct tty_struct *tty = acm->tty; |
327 | struct acm_ru *rcv; | 327 | struct acm_ru *rcv; |
328 | unsigned long flags; | 328 | unsigned long flags; |
329 | int i = 0; | 329 | unsigned char throttled; |
330 | dbg("Entering acm_rx_tasklet"); | 330 | dbg("Entering acm_rx_tasklet"); |
331 | 331 | ||
332 | if (!ACM_READY(acm) || acm->throttle) | 332 | if (!ACM_READY(acm)) |
333 | return; | ||
334 | |||
335 | spin_lock(&acm->throttle_lock); | ||
336 | throttled = acm->throttle; | ||
337 | spin_unlock(&acm->throttle_lock); | ||
338 | if (throttled) | ||
333 | return; | 339 | return; |
334 | 340 | ||
335 | next_buffer: | 341 | next_buffer: |
@@ -346,22 +352,20 @@ next_buffer: | |||
346 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); | 352 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); |
347 | 353 | ||
348 | tty_buffer_request_room(tty, buf->size); | 354 | tty_buffer_request_room(tty, buf->size); |
349 | if (!acm->throttle) | 355 | spin_lock(&acm->throttle_lock); |
356 | throttled = acm->throttle; | ||
357 | spin_unlock(&acm->throttle_lock); | ||
358 | if (!throttled) | ||
350 | tty_insert_flip_string(tty, buf->base, buf->size); | 359 | tty_insert_flip_string(tty, buf->base, buf->size); |
351 | tty_flip_buffer_push(tty); | 360 | tty_flip_buffer_push(tty); |
352 | 361 | ||
353 | spin_lock(&acm->throttle_lock); | 362 | if (throttled) { |
354 | if (acm->throttle) { | 363 | dbg("Throttling noticed"); |
355 | dbg("Throtteling noticed"); | ||
356 | memmove(buf->base, buf->base + i, buf->size - i); | ||
357 | buf->size -= i; | ||
358 | spin_unlock(&acm->throttle_lock); | ||
359 | spin_lock_irqsave(&acm->read_lock, flags); | 364 | spin_lock_irqsave(&acm->read_lock, flags); |
360 | list_add(&buf->list, &acm->filled_read_bufs); | 365 | list_add(&buf->list, &acm->filled_read_bufs); |
361 | spin_unlock_irqrestore(&acm->read_lock, flags); | 366 | spin_unlock_irqrestore(&acm->read_lock, flags); |
362 | return; | 367 | return; |
363 | } | 368 | } |
364 | spin_unlock(&acm->throttle_lock); | ||
365 | 369 | ||
366 | spin_lock_irqsave(&acm->read_lock, flags); | 370 | spin_lock_irqsave(&acm->read_lock, flags); |
367 | list_add(&buf->list, &acm->spare_read_bufs); | 371 | list_add(&buf->list, &acm->spare_read_bufs); |
@@ -467,7 +471,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
467 | goto bail_out; | 471 | goto bail_out; |
468 | } | 472 | } |
469 | 473 | ||
470 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) | 474 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && |
475 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) | ||
471 | goto full_bailout; | 476 | goto full_bailout; |
472 | 477 | ||
473 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 478 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
@@ -480,6 +485,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
480 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | 485 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); |
481 | } | 486 | } |
482 | 487 | ||
488 | acm->throttle = 0; | ||
489 | |||
483 | tasklet_schedule(&acm->urb_task); | 490 | tasklet_schedule(&acm->urb_task); |
484 | 491 | ||
485 | done: | 492 | done: |
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h index ba617c372455..956edf3bbecb 100644 --- a/include/linux/usb/cdc.h +++ b/include/linux/usb/cdc.h | |||
@@ -73,6 +73,13 @@ struct usb_cdc_acm_descriptor { | |||
73 | __u8 bmCapabilities; | 73 | __u8 bmCapabilities; |
74 | } __attribute__ ((packed)); | 74 | } __attribute__ ((packed)); |
75 | 75 | ||
76 | /* capabilities from 5.2.3.3 */ | ||
77 | |||
78 | #define USB_CDC_COMM_FEATURE 0x01 | ||
79 | #define USB_CDC_CAP_LINE 0x02 | ||
80 | #define USB_CDC_CAP_BRK 0x04 | ||
81 | #define USB_CDC_CAP_NOTIFY 0x08 | ||
82 | |||
76 | /* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ | 83 | /* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ |
77 | struct usb_cdc_union_desc { | 84 | struct usb_cdc_union_desc { |
78 | __u8 bLength; | 85 | __u8 bLength; |