Commit 09867af3 authored by Simon Arlott's avatar Simon Arlott Committed by Greg Kroah-Hartman

USB: cdc-acm: support flushing write buffers (TCOFLUSH)

If the serial device never reads data written to it (because it is "output
only") then the write buffers will still be waiting for the URB to complete
on close(), which will hang for 30s until the closing_wait timeout expires.

This can happen with the ESP32-H2/ESP32-C6 USB serial interface. Changing
the port closing_wait timeout is a privileged operation but flushing the
output buffer is not a privileged operation.

Implement the flush_buffer tty operation to cancel in-progress writes so
that tcflush(fd, TCOFLUSH) can be used to unblock the serial port before
close.
Signed-off-by: default avatarSimon Arlott <simon@octiron.net>
Link: https://lore.kernel.org/r/555fbc4c-043b-8932-fb9b-a208d61ffbe4@0882a8b5-c6c3-11e9-b005-00805fc181fe.uuid.home.arpaSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4b3cd783
...@@ -864,6 +864,19 @@ static unsigned int acm_tty_write_room(struct tty_struct *tty) ...@@ -864,6 +864,19 @@ static unsigned int acm_tty_write_room(struct tty_struct *tty)
return acm_wb_is_avail(acm) ? acm->writesize : 0; return acm_wb_is_avail(acm) ? acm->writesize : 0;
} }
static void acm_tty_flush_buffer(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
unsigned long flags;
int i;
spin_lock_irqsave(&acm->write_lock, flags);
for (i = 0; i < ACM_NW; i++)
if (acm->wb[i].use)
usb_unlink_urb(acm->wb[i].urb);
spin_unlock_irqrestore(&acm->write_lock, flags);
}
static unsigned int acm_tty_chars_in_buffer(struct tty_struct *tty) static unsigned int acm_tty_chars_in_buffer(struct tty_struct *tty)
{ {
struct acm *acm = tty->driver_data; struct acm *acm = tty->driver_data;
...@@ -2027,6 +2040,7 @@ static const struct tty_operations acm_ops = { ...@@ -2027,6 +2040,7 @@ static const struct tty_operations acm_ops = {
.hangup = acm_tty_hangup, .hangup = acm_tty_hangup,
.write = acm_tty_write, .write = acm_tty_write,
.write_room = acm_tty_write_room, .write_room = acm_tty_write_room,
.flush_buffer = acm_tty_flush_buffer,
.ioctl = acm_tty_ioctl, .ioctl = acm_tty_ioctl,
.throttle = acm_tty_throttle, .throttle = acm_tty_throttle,
.unthrottle = acm_tty_unthrottle, .unthrottle = acm_tty_unthrottle,
......
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