summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tty_port.c18
-rw-r--r--include/linux/tty.h12
2 files changed, 30 insertions, 0 deletions
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 84006de2900f..be492dd66437 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -29,6 +29,7 @@ void tty_port_init(struct tty_port *port)
spin_lock_init(&port->lock);
port->close_delay = (50 * HZ) / 100;
port->closing_wait = (3000 * HZ) / 100;
+ kref_init(&port->kref);
}
EXPORT_SYMBOL(tty_port_init);
@@ -56,6 +57,23 @@ void tty_port_free_xmit_buf(struct tty_port *port)
}
EXPORT_SYMBOL(tty_port_free_xmit_buf);
+static void tty_port_destructor(struct kref *kref)
+{
+ struct tty_port *port = container_of(kref, struct tty_port, kref);
+ if (port->xmit_buf)
+ free_page((unsigned long)port->xmit_buf);
+ if (port->ops->destruct)
+ port->ops->destruct(port);
+ else
+ kfree(port);
+}
+
+void tty_port_put(struct tty_port *port)
+{
+ if (port)
+ kref_put(&port->kref, tty_port_destructor);
+}
+EXPORT_SYMBOL(tty_port_put);
/**
* tty_port_tty_get - get a tty reference
diff --git a/include/linux/tty.h b/include/linux/tty.h
index e9269ca1542a..e6da667ba34d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -199,6 +199,8 @@ struct tty_port_operations {
/* FIXME: long term getting the tty argument *out* of this would be
good for consoles */
int (*activate)(struct tty_port *port, struct tty_struct *tty);
+ /* Called on the final put of a port */
+ void (*destruct)(struct tty_port *port);
};
struct tty_port {
@@ -219,6 +221,7 @@ struct tty_port {
int drain_delay; /* Set to zero if no pure time
based drain is needed else
set to size of fifo */
+ struct kref kref; /* Ref counter */
};
/*
@@ -461,6 +464,15 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
extern void tty_port_init(struct tty_port *port);
extern int tty_port_alloc_xmit_buf(struct tty_port *port);
extern void tty_port_free_xmit_buf(struct tty_port *port);
+extern void tty_port_put(struct tty_port *port);
+
+extern inline struct tty_port *tty_port_get(struct tty_port *port)
+{
+ if (port)
+ kref_get(&port->kref);
+ return port;
+}
+
extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
extern int tty_port_carrier_raised(struct tty_port *port);