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