USB: serial: opticon: stop all I/O on close()
authorJohan Hovold <johan@kernel.org>
Tue, 14 Jan 2020 11:01:46 +0000 (12:01 +0100)
committerJohan Hovold <johan@kernel.org>
Fri, 17 Jan 2020 10:28:05 +0000 (11:28 +0100)
Make sure to stop any submitted write URBs on close().

Note that the tty layer will wait up to 30 seconds for the buffers to
drain before close() is called.

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
drivers/usb/serial/opticon.c

index 05ea21ed967c13af2dae70c842878b150407a336..9fd9caab397b8e74d0e3a54d4e94a45b05ad2b02 100644 (file)
@@ -42,6 +42,8 @@ struct opticon_private {
        bool cts;
        int outstanding_urbs;
        int outstanding_bytes;
+
+       struct usb_anchor anchor;
 };
 
 
@@ -150,6 +152,15 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
        return res;
 }
 
+static void opticon_close(struct usb_serial_port *port)
+{
+       struct opticon_private *priv = usb_get_serial_port_data(port);
+
+       usb_kill_anchored_urbs(&priv->anchor);
+
+       usb_serial_generic_close(port);
+}
+
 static void opticon_write_control_callback(struct urb *urb)
 {
        struct usb_serial_port *port = urb->context;
@@ -226,10 +237,13 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
                (unsigned char *)dr, buffer, count,
                opticon_write_control_callback, port);
 
+       usb_anchor_urb(urb, &priv->anchor);
+
        /* send it down the pipe */
        ret = usb_submit_urb(urb, GFP_ATOMIC);
        if (ret) {
                dev_err(&port->dev, "failed to submit write urb: %d\n", ret);
+               usb_unanchor_urb(urb);
                goto error;
        }
 
@@ -364,6 +378,7 @@ static int opticon_port_probe(struct usb_serial_port *port)
                return -ENOMEM;
 
        spin_lock_init(&priv->lock);
+       init_usb_anchor(&priv->anchor);
 
        usb_set_serial_port_data(port, priv);
 
@@ -391,6 +406,7 @@ static struct usb_serial_driver opticon_device = {
        .port_probe =           opticon_port_probe,
        .port_remove =          opticon_port_remove,
        .open =                 opticon_open,
+       .close =                opticon_close,
        .write =                opticon_write,
        .write_room =           opticon_write_room,
        .chars_in_buffer =      opticon_chars_in_buffer,