Commit a81cf979 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

cdc-acm: implement put_char() and flush_chars()

This should cut down latencies and waste if the tty layer writes single bytes.

Signed-off-by: Oliver Neukum >oneukum@suse.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ca1c3e6f
...@@ -713,9 +713,20 @@ static int acm_tty_write(struct tty_struct *tty, ...@@ -713,9 +713,20 @@ static int acm_tty_write(struct tty_struct *tty,
} }
if (acm->susp_count) { if (acm->susp_count) {
if (acm->putbuffer) {
/* now to preserve order */
usb_anchor_urb(acm->putbuffer->urb, &acm->delayed);
acm->putbuffer = NULL;
}
usb_anchor_urb(wb->urb, &acm->delayed); usb_anchor_urb(wb->urb, &acm->delayed);
spin_unlock_irqrestore(&acm->write_lock, flags); spin_unlock_irqrestore(&acm->write_lock, flags);
return count; return count;
} else {
if (acm->putbuffer) {
/* at this point there is no good way to handle errors */
acm_start_wb(acm, acm->putbuffer);
acm->putbuffer = NULL;
}
} }
stat = acm_start_wb(acm, wb); stat = acm_start_wb(acm, wb);
...@@ -726,6 +737,60 @@ static int acm_tty_write(struct tty_struct *tty, ...@@ -726,6 +737,60 @@ static int acm_tty_write(struct tty_struct *tty,
return count; return count;
} }
static void acm_tty_flush_chars(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
struct acm_wb *cur = acm->putbuffer;
int err;
unsigned long flags;
acm->putbuffer = NULL;
err = usb_autopm_get_interface_async(acm->control);
spin_lock_irqsave(&acm->write_lock, flags);
if (err < 0) {
cur->use = 0;
goto out;
}
if (acm->susp_count)
usb_anchor_urb(cur->urb, &acm->delayed);
else
acm_start_wb(acm, cur);
out:
spin_unlock_irqrestore(&acm->write_lock, flags);
return;
}
static int acm_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct acm *acm = tty->driver_data;
struct acm_wb *cur;
int wbn;
unsigned long flags;
overflow:
cur = acm->putbuffer;
if (!cur) {
spin_lock_irqsave(&acm->write_lock, flags);
wbn = acm_wb_alloc(acm);
if (wbn >= 0) {
cur = &acm->wb[wbn];
acm->putbuffer = cur;
}
spin_unlock_irqrestore(&acm->write_lock, flags);
if (!cur)
return 0;
}
if (cur->len == acm->writesize) {
acm_tty_flush_chars(tty);
goto overflow;
}
cur->buf[cur->len++] = ch;
return 1;
}
static int acm_tty_write_room(struct tty_struct *tty) static int acm_tty_write_room(struct tty_struct *tty)
{ {
struct acm *acm = tty->driver_data; struct acm *acm = tty->driver_data;
...@@ -1905,6 +1970,8 @@ static const struct tty_operations acm_ops = { ...@@ -1905,6 +1970,8 @@ static const struct tty_operations acm_ops = {
.cleanup = acm_tty_cleanup, .cleanup = acm_tty_cleanup,
.hangup = acm_tty_hangup, .hangup = acm_tty_hangup,
.write = acm_tty_write, .write = acm_tty_write,
.put_char = acm_tty_put_char,
.flush_chars = acm_tty_flush_chars,
.write_room = acm_tty_write_room, .write_room = acm_tty_write_room,
.ioctl = acm_tty_ioctl, .ioctl = acm_tty_ioctl,
.throttle = acm_tty_throttle, .throttle = acm_tty_throttle,
......
...@@ -94,6 +94,7 @@ struct acm { ...@@ -94,6 +94,7 @@ struct acm {
unsigned long read_urbs_free; unsigned long read_urbs_free;
struct urb *read_urbs[ACM_NR]; struct urb *read_urbs[ACM_NR];
struct acm_rb read_buffers[ACM_NR]; struct acm_rb read_buffers[ACM_NR];
struct acm_wb *putbuffer; /* for acm_tty_put_char() */
int rx_buflimit; int rx_buflimit;
int rx_endpoint; int rx_endpoint;
spinlock_t read_lock; spinlock_t read_lock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment