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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ca1c3e6f81
commit
a81cf9799a
@ -713,9 +713,20 @@ static int acm_tty_write(struct tty_struct *tty,
|
||||
}
|
||||
|
||||
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);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
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);
|
||||
@ -726,6 +737,60 @@ static int acm_tty_write(struct tty_struct *tty,
|
||||
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)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
@ -1905,6 +1970,8 @@ static const struct tty_operations acm_ops = {
|
||||
.cleanup = acm_tty_cleanup,
|
||||
.hangup = acm_tty_hangup,
|
||||
.write = acm_tty_write,
|
||||
.put_char = acm_tty_put_char,
|
||||
.flush_chars = acm_tty_flush_chars,
|
||||
.write_room = acm_tty_write_room,
|
||||
.ioctl = acm_tty_ioctl,
|
||||
.throttle = acm_tty_throttle,
|
||||
|
@ -94,6 +94,7 @@ struct acm {
|
||||
unsigned long read_urbs_free;
|
||||
struct urb *read_urbs[ACM_NR];
|
||||
struct acm_rb read_buffers[ACM_NR];
|
||||
struct acm_wb *putbuffer; /* for acm_tty_put_char() */
|
||||
int rx_buflimit;
|
||||
int rx_endpoint;
|
||||
spinlock_t read_lock;
|
||||
|
Loading…
Reference in New Issue
Block a user