aboutsummaryrefslogtreecommitdiffstats
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.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 9769b1149f76..a4bbb28f10be 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -23,6 +23,7 @@ void tty_port_init(struct tty_port *port)
23 memset(port, 0, sizeof(*port)); 23 memset(port, 0, sizeof(*port));
24 init_waitqueue_head(&port->open_wait); 24 init_waitqueue_head(&port->open_wait);
25 init_waitqueue_head(&port->close_wait); 25 init_waitqueue_head(&port->close_wait);
26 init_waitqueue_head(&port->delta_msr_wait);
26 mutex_init(&port->mutex); 27 mutex_init(&port->mutex);
27 spin_lock_init(&port->lock); 28 spin_lock_init(&port->lock);
28 port->close_delay = (50 * HZ) / 100; 29 port->close_delay = (50 * HZ) / 100;
@@ -96,6 +97,14 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
96} 97}
97EXPORT_SYMBOL(tty_port_tty_set); 98EXPORT_SYMBOL(tty_port_tty_set);
98 99
100static void tty_port_shutdown(struct tty_port *port)
101{
102 if (port->ops->shutdown &&
103 test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
104 port->ops->shutdown(port);
105
106}
107
99/** 108/**
100 * tty_port_hangup - hangup helper 109 * tty_port_hangup - hangup helper
101 * @port: tty port 110 * @port: tty port
@@ -116,6 +125,8 @@ void tty_port_hangup(struct tty_port *port)
116 port->tty = NULL; 125 port->tty = NULL;
117 spin_unlock_irqrestore(&port->lock, flags); 126 spin_unlock_irqrestore(&port->lock, flags);
118 wake_up_interruptible(&port->open_wait); 127 wake_up_interruptible(&port->open_wait);
128 wake_up_interruptible(&port->delta_msr_wait);
129 tty_port_shutdown(port);
119} 130}
120EXPORT_SYMBOL(tty_port_hangup); 131EXPORT_SYMBOL(tty_port_hangup);
121 132
@@ -296,15 +307,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
296 307
297 if (port->count) { 308 if (port->count) {
298 spin_unlock_irqrestore(&port->lock, flags); 309 spin_unlock_irqrestore(&port->lock, flags);
310 if (port->ops->drop)
311 port->ops->drop(port);
299 return 0; 312 return 0;
300 } 313 }
301 port->flags |= ASYNC_CLOSING; 314 set_bit(ASYNCB_CLOSING, &port->flags);
302 tty->closing = 1; 315 tty->closing = 1;
303 spin_unlock_irqrestore(&port->lock, flags); 316 spin_unlock_irqrestore(&port->lock, flags);
304 /* Don't block on a stalled port, just pull the chain */ 317 /* Don't block on a stalled port, just pull the chain */
305 if (tty->flow_stopped) 318 if (tty->flow_stopped)
306 tty_driver_flush_buffer(tty); 319 tty_driver_flush_buffer(tty);
307 if (port->flags & ASYNC_INITIALIZED && 320 if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
308 port->closing_wait != ASYNC_CLOSING_WAIT_NONE) 321 port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
309 tty_wait_until_sent(tty, port->closing_wait); 322 tty_wait_until_sent(tty, port->closing_wait);
310 if (port->drain_delay) { 323 if (port->drain_delay) {
@@ -318,6 +331,9 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
318 timeout = 2 * HZ; 331 timeout = 2 * HZ;
319 schedule_timeout_interruptible(timeout); 332 schedule_timeout_interruptible(timeout);
320 } 333 }
334 /* Don't call port->drop for the last reference. Callers will want
335 to drop the last active reference in ->shutdown() or the tty
336 shutdown path */
321 return 1; 337 return 1;
322} 338}
323EXPORT_SYMBOL(tty_port_close_start); 339EXPORT_SYMBOL(tty_port_close_start);
@@ -348,3 +364,14 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
348 spin_unlock_irqrestore(&port->lock, flags); 364 spin_unlock_irqrestore(&port->lock, flags);
349} 365}
350EXPORT_SYMBOL(tty_port_close_end); 366EXPORT_SYMBOL(tty_port_close_end);
367
368void tty_port_close(struct tty_port *port, struct tty_struct *tty,
369 struct file *filp)
370{
371 if (tty_port_close_start(port, tty, filp) == 0)
372 return;
373 tty_port_shutdown(port);
374 tty_port_close_end(port, tty);
375 tty_port_tty_set(port, NULL);
376}
377EXPORT_SYMBOL(tty_port_close);