mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
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>
This commit is contained in:
parent
3f141e2aed
commit
ca79b7b415
2 changed files with 25 additions and 11 deletions
|
@ -326,10 +326,16 @@ static void acm_rx_tasklet(unsigned long _acm)
|
|||
struct tty_struct *tty = acm->tty;
|
||||
struct acm_ru *rcv;
|
||||
unsigned long flags;
|
||||
int i = 0;
|
||||
unsigned char throttled;
|
||||
dbg("Entering acm_rx_tasklet");
|
||||
|
||||
if (!ACM_READY(acm) || acm->throttle)
|
||||
if (!ACM_READY(acm))
|
||||
return;
|
||||
|
||||
spin_lock(&acm->throttle_lock);
|
||||
throttled = acm->throttle;
|
||||
spin_unlock(&acm->throttle_lock);
|
||||
if (throttled)
|
||||
return;
|
||||
|
||||
next_buffer:
|
||||
|
@ -346,22 +352,20 @@ static void acm_rx_tasklet(unsigned long _acm)
|
|||
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
|
||||
|
||||
tty_buffer_request_room(tty, buf->size);
|
||||
if (!acm->throttle)
|
||||
spin_lock(&acm->throttle_lock);
|
||||
throttled = acm->throttle;
|
||||
spin_unlock(&acm->throttle_lock);
|
||||
if (!throttled)
|
||||
tty_insert_flip_string(tty, buf->base, buf->size);
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
spin_lock(&acm->throttle_lock);
|
||||
if (acm->throttle) {
|
||||
dbg("Throtteling noticed");
|
||||
memmove(buf->base, buf->base + i, buf->size - i);
|
||||
buf->size -= i;
|
||||
spin_unlock(&acm->throttle_lock);
|
||||
if (throttled) {
|
||||
dbg("Throttling noticed");
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
list_add(&buf->list, &acm->filled_read_bufs);
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&acm->throttle_lock);
|
||||
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
|
@ -467,7 +471,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
goto bail_out;
|
||||
}
|
||||
|
||||
if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS))
|
||||
if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
|
||||
(acm->ctrl_caps & USB_CDC_CAP_LINE))
|
||||
goto full_bailout;
|
||||
|
||||
INIT_LIST_HEAD(&acm->spare_read_urbs);
|
||||
|
@ -480,6 +485,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
|
||||
}
|
||||
|
||||
acm->throttle = 0;
|
||||
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
|
||||
done:
|
||||
|
|
|
@ -73,6 +73,13 @@ struct usb_cdc_acm_descriptor {
|
|||
__u8 bmCapabilities;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* capabilities from 5.2.3.3 */
|
||||
|
||||
#define USB_CDC_COMM_FEATURE 0x01
|
||||
#define USB_CDC_CAP_LINE 0x02
|
||||
#define USB_CDC_CAP_BRK 0x04
|
||||
#define USB_CDC_CAP_NOTIFY 0x08
|
||||
|
||||
/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
|
||||
struct usb_cdc_union_desc {
|
||||
__u8 bLength;
|
||||
|
|
Loading…
Reference in a new issue