aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tty_port.c29
-rw-r--r--include/linux/tty.h8
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}
97EXPORT_SYMBOL(tty_port_tty_set); 97EXPORT_SYMBOL(tty_port_tty_set);
98 98
99static 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}
120EXPORT_SYMBOL(tty_port_hangup); 129EXPORT_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}
323EXPORT_SYMBOL(tty_port_close_start); 337EXPORT_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}
350EXPORT_SYMBOL(tty_port_close_end); 364EXPORT_SYMBOL(tty_port_close_end);
365
366void 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}
375EXPORT_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;
187struct tty_port_operations { 187struct 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
193struct tty_port { 198struct tty_port {
@@ -459,7 +464,8 @@ extern int tty_port_block_til_ready(struct tty_port *port,
459extern int tty_port_close_start(struct tty_port *port, 464extern 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);
461extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); 466extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
462 467extern void tty_port_close(struct tty_port *port,
468 struct tty_struct *tty, struct file *filp);
463extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); 469extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
464extern int tty_unregister_ldisc(int disc); 470extern int tty_unregister_ldisc(int disc);
465extern int tty_set_ldisc(struct tty_struct *tty, int ldisc); 471extern int tty_set_ldisc(struct tty_struct *tty, int ldisc);