diff options
Diffstat (limited to 'drivers/char/tty_port.c')
-rw-r--r-- | drivers/char/tty_port.c | 31 |
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 | } |
97 | EXPORT_SYMBOL(tty_port_tty_set); | 98 | EXPORT_SYMBOL(tty_port_tty_set); |
98 | 99 | ||
100 | static 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 | } |
120 | EXPORT_SYMBOL(tty_port_hangup); | 131 | EXPORT_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 | } |
323 | EXPORT_SYMBOL(tty_port_close_start); | 339 | EXPORT_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 | } |
350 | EXPORT_SYMBOL(tty_port_close_end); | 366 | EXPORT_SYMBOL(tty_port_close_end); |
367 | |||
368 | void 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 | } | ||
377 | EXPORT_SYMBOL(tty_port_close); | ||