diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 729b0472bab0..d3c996921011 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -5,6 +5,7 @@ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) * Copyright (C) 2008 David Brownell * Copyright (C) 2008 by Nokia Corporation + * Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * * This code also borrows from usbserial.c, which is * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) @@ -291,7 +292,11 @@ __acquires(&port->port_lock) break; } - if (do_tty_wake && port->port.tty) + /* race with close() */ + if (!port->port.tty) + return -ESHUTDOWN; + + if (do_tty_wake) tty_wakeup(port->port.tty); return status; } @@ -344,7 +349,7 @@ __acquires(&port->port_lock) if (!port->port_usb) break; } - return port->read_started; + return port->port.tty ? port->read_started : 0; } /* @@ -570,10 +575,11 @@ static int gs_start_io(struct gs_port *port) started = gs_start_rx(port); if (started) { - gs_start_tx(port); + status = gs_start_tx(port); /* Unblock any pending writes into our circular buffer, in case * we didn't in gs_start_tx() */ - tty_wakeup(port->port.tty); + if (!status) + tty_wakeup(port->port.tty); } else { /* Free reqs only if we are still connected */ if (port->port_usb) { @@ -646,9 +652,9 @@ static int gs_open(struct tty_struct *tty, struct file *file) struct gserial *gser = port->port_usb; pr_debug("gs_open: start ttyGS%d\n", port->port_num); - gs_start_io(port); + status = gs_start_io(port); - if (gser->connect) + if (!status && gser->connect) gser->connect(gser); } else { pr_debug("delay start of ttyGS%d\n", port->port_num); @@ -1351,8 +1357,8 @@ int gserial_connect(struct gserial *gser, u8 port_num) */ if (port->port.count) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); - gs_start_io(port); - if (gser->connect) + status = gs_start_io(port); + if (!status && gser->connect) gser->connect(gser); } else { if (gser->disconnect) @@ -1453,6 +1459,7 @@ void gserial_resume(struct gserial *gser) { struct gs_port *port; unsigned long flags; + int status = 0; spin_lock_irqsave(&serial_port_lock, flags); port = gser->ioport; @@ -1471,8 +1478,8 @@ void gserial_resume(struct gserial *gser) } pr_debug("delayed start ttyGS%d\n", port->port_num); - gs_start_io(port); - if (gser->connect) + status = gs_start_io(port); + if (!status && gser->connect) gser->connect(gser); port->start_delayed = false; spin_unlock_irqrestore(&port->port_lock, flags);