summaryrefslogtreecommitdiff
path: root/drivers/char/tty_port.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tty_port.c')
-rw-r--r--drivers/char/tty_port.c39
1 files changed, 35 insertions, 4 deletions
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 9769b1149f76..c0ff7eeafbb2 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -96,6 +96,14 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_port_tty_set);
+static void tty_port_shutdown(struct tty_port *port)
+{
+ if (port->ops->shutdown &&
+ test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
+ port->ops->shutdown(port);
+
+}
+
/**
* tty_port_hangup - hangup helper
* @port: tty port
@@ -116,6 +124,7 @@ void tty_port_hangup(struct tty_port *port)
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
+ tty_port_shutdown(port);
}
EXPORT_SYMBOL(tty_port_hangup);
@@ -208,8 +217,14 @@ int tty_port_block_til_ready(struct tty_port *port,
/* if non-blocking mode is set we can pass directly to open unless
the port has just hung up or is in another error state */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (tty->flags & (1 << TTY_IO_ERROR)) {
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+ if (filp->f_flags & O_NONBLOCK) {
+ /* Indicate we are open */
+ if (tty->termios->c_cflag & CBAUD)
+ tty_port_raise_dtr_rts(port);
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -296,15 +311,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
if (port->count) {
spin_unlock_irqrestore(&port->lock, flags);
+ if (port->ops->drop)
+ port->ops->drop(port);
return 0;
}
- port->flags |= ASYNC_CLOSING;
+ set_bit(ASYNCB_CLOSING, &port->flags);
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
/* Don't block on a stalled port, just pull the chain */
if (tty->flow_stopped)
tty_driver_flush_buffer(tty);
- if (port->flags & ASYNC_INITIALIZED &&
+ if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
if (port->drain_delay) {
@@ -318,6 +335,9 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
timeout = 2 * HZ;
schedule_timeout_interruptible(timeout);
}
+ /* Don't call port->drop for the last reference. Callers will want
+ to drop the last active reference in ->shutdown() or the tty
+ shutdown path */
return 1;
}
EXPORT_SYMBOL(tty_port_close_start);
@@ -348,3 +368,14 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_close_end);
+
+void tty_port_close(struct tty_port *port, struct tty_struct *tty,
+ struct file *filp)
+{
+ if (tty_port_close_start(port, tty, filp) == 0)
+ return;
+ tty_port_shutdown(port);
+ tty_port_close_end(port, tty);
+ tty_port_tty_set(port, NULL);
+}
+EXPORT_SYMBOL(tty_port_close);