diff options
-rw-r--r-- | drivers/char/tty_port.c | 29 | ||||
-rw-r--r-- | include/linux/tty.h | 8 |
2 files changed, 34 insertions, 3 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); | ||
diff --git a/include/linux/tty.h b/include/linux/tty.h index a916a318004e..ecb3d1ba3017 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
@@ -187,7 +187,12 @@ struct tty_port; | |||
187 | struct tty_port_operations { | 187 | struct tty_port_operations { |
188 | /* Return 1 if the carrier is raised */ | 188 | /* Return 1 if the carrier is raised */ |
189 | int (*carrier_raised)(struct tty_port *port); | 189 | int (*carrier_raised)(struct tty_port *port); |
190 | /* Control the DTR line */ | ||
190 | void (*dtr_rts)(struct tty_port *port, int raise); | 191 | void (*dtr_rts)(struct tty_port *port, int raise); |
192 | /* Called when the last close completes or a hangup finishes | ||
193 | IFF the port was initialized. Do not use to free resources */ | ||
194 | void (*shutdown)(struct tty_port *port); | ||
195 | void (*drop)(struct tty_port *port); | ||
191 | }; | 196 | }; |
192 | 197 | ||
193 | struct tty_port { | 198 | struct tty_port { |
@@ -459,7 +464,8 @@ extern int tty_port_block_til_ready(struct tty_port *port, | |||
459 | extern int tty_port_close_start(struct tty_port *port, | 464 | extern int tty_port_close_start(struct tty_port *port, |
460 | struct tty_struct *tty, struct file *filp); | 465 | struct tty_struct *tty, struct file *filp); |
461 | extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); | 466 | extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); |
462 | 467 | extern void tty_port_close(struct tty_port *port, | |
468 | struct tty_struct *tty, struct file *filp); | ||
463 | extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); | 469 | extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); |
464 | extern int tty_unregister_ldisc(int disc); | 470 | extern int tty_unregister_ldisc(int disc); |
465 | extern int tty_set_ldisc(struct tty_struct *tty, int ldisc); | 471 | extern int tty_set_ldisc(struct tty_struct *tty, int ldisc); |