diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index c63f3d33914a7def6b4e49d2f3d33a25dbf8fc0c..b22a61a4fbe58c0f32a6df3cbc429655c6f2a4d9 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c @@ -99,10 +99,11 @@ EXPORT_SYMBOL(tty_port_tty_set); static void tty_port_shutdown(struct tty_port *port) { + mutex_lock(&port->mutex); if (port->ops->shutdown && test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) port->ops->shutdown(port); - + mutex_unlock(&port->mutex); } /** @@ -381,3 +382,36 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty, tty_port_tty_set(port, NULL); } EXPORT_SYMBOL(tty_port_close); + +int tty_port_open(struct tty_port *port, struct tty_struct *tty, + struct file *filp) +{ + spin_lock_irq(&port->lock); + if (!tty_hung_up_p(filp)) + ++port->count; + spin_unlock_irq(&port->lock); + tty_port_tty_set(port, tty); + + /* + * Do the device-specific open only if the hardware isn't + * already initialized. Serialize open and shutdown using the + * port mutex. + */ + + mutex_lock(&port->mutex); + + if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (port->ops->activate) { + int retval = port->ops->activate(port, tty); + if (retval) { + mutex_unlock(&port->mutex); + return retval; + } + } + set_bit(ASYNCB_INITIALIZED, &port->flags); + } + mutex_unlock(&port->mutex); + return tty_port_block_til_ready(port, tty, filp); +} + +EXPORT_SYMBOL(tty_port_open); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bd3fa7ff15b12166bf0cf2ad86f3214144f914c0..b0649d92251ff77baf8fcb4be7be1209b119b5cc 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -247,41 +247,31 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) return retval; } -static int serial_open(struct tty_struct *tty, struct file *filp) +static int serial_activate(struct tty_port *tport, struct tty_struct *tty) { - struct usb_serial_port *port = tty->driver_data; + struct usb_serial_port *port = + container_of(tport, struct usb_serial_port, port); struct usb_serial *serial = port->serial; int retval; - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&port->port.lock); - if (!tty_hung_up_p(filp)) - ++port->port.count; - spin_unlock_irq(&port->port.lock); - tty_port_tty_set(&port->port, tty); + if (mutex_lock_interruptible(&port->mutex)) + return -ERESTARTSYS; + mutex_lock(&serial->disc_mutex); + if (serial->disconnected) + retval = -ENODEV; + else + retval = port->serial->type->open(tty, port); + mutex_unlock(&serial->disc_mutex); + mutex_unlock(&port->mutex); + return retval; +} - /* Do the device-specific open only if the hardware isn't - * already initialized. - */ - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { - if (mutex_lock_interruptible(&port->mutex)) - return -ERESTARTSYS; - mutex_lock(&serial->disc_mutex); - if (serial->disconnected) - retval = -ENODEV; - else - retval = port->serial->type->open(tty, port); - mutex_unlock(&serial->disc_mutex); - mutex_unlock(&port->mutex); - if (retval) - return retval; - set_bit(ASYNCB_INITIALIZED, &port->port.flags); - } +static int serial_open(struct tty_struct *tty, struct file *filp) +{ + struct usb_serial_port *port = tty->driver_data; - /* Now do the correct tty layer semantics */ - retval = tty_port_block_til_ready(&port->port, tty, filp); - return retval; + dbg("%s - port %d", __func__, port->number); + return tty_port_open(&port->port, tty, filp); } /** @@ -725,6 +715,7 @@ static void serial_dtr_rts(struct tty_port *port, int on) static const struct tty_port_operations serial_port_ops = { .carrier_raised = serial_carrier_raised, .dtr_rts = serial_dtr_rts, + .activate = serial_activate, }; int usb_serial_probe(struct usb_interface *interface, diff --git a/include/linux/tty.h b/include/linux/tty.h index f0f43d08d8b8765911d51f681034841a73b1c239..6352ac257fcb78163adf8d8954b92c9ae5bbe4b0 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -190,9 +190,15 @@ struct tty_port_operations { /* Control the DTR line */ void (*dtr_rts)(struct tty_port *port, int raise); /* Called when the last close completes or a hangup finishes - IFF the port was initialized. Do not use to free resources */ + IFF the port was initialized. Do not use to free resources. Called + under the port mutex to serialize against activate/shutdowns */ void (*shutdown)(struct tty_port *port); void (*drop)(struct tty_port *port); + /* Called under the port mutex from tty_port_open, serialized using + the port mutex */ + /* FIXME: long term getting the tty argument *out* of this would be + good for consoles */ + int (*activate)(struct tty_port *port, struct tty_struct *tty); }; struct tty_port { @@ -467,6 +473,8 @@ extern int tty_port_close_start(struct tty_port *port, extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); extern void tty_port_close(struct tty_port *port, struct tty_struct *tty, struct file *filp); +extern int tty_port_open(struct tty_port *port, + struct tty_struct *tty, struct file *filp); extern inline int tty_port_users(struct tty_port *port) { return port->count + port->blocked_open;