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

Signed-off-by: Oliver Neukum >oneu...@suse.com>
---
 drivers/usb/class/cdc-acm.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/class/cdc-acm.h |  1 +
 2 files changed, 68 insertions(+)

diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b30e742..1cb3124 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -712,9 +712,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);
@@ -725,6 +736,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;
@@ -1888,6 +1953,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,
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index dd9af38..648a6f7 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -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;
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to