Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca79b7b4 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman
Browse files

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: default avatarJoris van Rantwijk <jorispubl@xs4all.nl>
Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 3f141e2a
Loading
Loading
Loading
Loading
+18 −11
Original line number Diff line number Diff line
@@ -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:
+7 −0
Original line number Diff line number Diff line
@@ -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;