summaryrefslogtreecommitdiff
path: root/drivers/tty/tty_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r--drivers/tty/tty_buffer.c102
1 files changed, 53 insertions, 49 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index ddd74d41cbb2..06725f5cc819 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -27,9 +27,9 @@
* Locking: none
*/
-void tty_buffer_free_all(struct tty_struct *tty)
+void tty_buffer_free_all(struct tty_port *port)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *thead;
while ((thead = buf->head) != NULL) {
@@ -56,11 +56,11 @@ void tty_buffer_free_all(struct tty_struct *tty)
* Locking: Caller must hold tty->buf.lock
*/
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
{
struct tty_buffer *p;
- if (tty->buf.memory_used + size > 65536)
+ if (port->buf.memory_used + size > 65536)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
if (p == NULL)
@@ -72,7 +72,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
p->read = 0;
p->char_buf_ptr = (char *)(p->data);
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
- tty->buf.memory_used += size;
+ port->buf.memory_used += size;
return p;
}
@@ -87,9 +87,9 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
* Locking: Caller must hold tty->buf.lock
*/
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &port->buf;
/* Dumb strategy for now - should keep some stats */
buf->memory_used -= b->size;
@@ -114,14 +114,14 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
* Locking: Caller must hold tty->buf.lock
*/
-static void __tty_buffer_flush(struct tty_struct *tty)
+static void __tty_buffer_flush(struct tty_port *port)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *thead;
while ((thead = buf->head) != NULL) {
buf->head = thead->next;
- tty_buffer_free(tty, thead);
+ tty_buffer_free(port, thead);
}
buf->tail = NULL;
}
@@ -140,7 +140,7 @@ static void __tty_buffer_flush(struct tty_struct *tty)
void tty_buffer_flush(struct tty_struct *tty)
{
struct tty_port *port = tty->port;
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &port->buf;
unsigned long flags;
spin_lock_irqsave(&buf->lock, flags);
@@ -155,7 +155,7 @@ void tty_buffer_flush(struct tty_struct *tty)
test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0);
return;
} else
- __tty_buffer_flush(tty);
+ __tty_buffer_flush(port);
spin_unlock_irqrestore(&buf->lock, flags);
}
@@ -171,9 +171,9 @@ void tty_buffer_flush(struct tty_struct *tty)
* Locking: Caller must hold tty->buf.lock
*/
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size)
{
- struct tty_buffer **tbh = &tty->buf.free;
+ struct tty_buffer **tbh = &port->buf.free;
while ((*tbh) != NULL) {
struct tty_buffer *t = *tbh;
if (t->size >= size) {
@@ -182,14 +182,14 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
t->used = 0;
t->commit = 0;
t->read = 0;
- tty->buf.memory_used += t->size;
+ port->buf.memory_used += t->size;
return t;
}
tbh = &((*tbh)->next);
}
/* Round the buffer size out */
size = (size + 0xFF) & ~0xFF;
- return tty_buffer_alloc(tty, size);
+ return tty_buffer_alloc(port, size);
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
@@ -200,11 +200,11 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
- * Locking: Caller must hold tty->buf.lock
+ * Locking: Caller must hold port->buf.lock
*/
-static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_port *port, size_t size)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &port->buf;
struct tty_buffer *b, *n;
int left;
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
@@ -218,7 +218,7 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
if (left < size) {
/* This is the slow path - looking for new buffers to use */
- if ((n = tty_buffer_find(tty, size)) != NULL) {
+ if ((n = tty_buffer_find(port, size)) != NULL) {
if (b != NULL) {
b->next = n;
b->commit = b->used;
@@ -241,16 +241,17 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
*
- * Locking: Takes tty->buf.lock
+ * Locking: Takes port->buf.lock
*/
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
+ struct tty_port *port = tty->port;
unsigned long flags;
int length;
- spin_lock_irqsave(&tty->buf.lock, flags);
- length = __tty_buffer_request_room(tty, size);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
+ spin_lock_irqsave(&port->buf.lock, flags);
+ length = __tty_buffer_request_room(port, size);
+ spin_unlock_irqrestore(&port->buf.lock, flags);
return length;
}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
@@ -265,13 +266,13 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
* Queue a series of bytes to the tty buffering. All the characters
* passed are marked with the supplied flag. Returns the number added.
*
- * Locking: Called functions may take tty->buf.lock
+ * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
const unsigned char *chars, char flag, size_t size)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &tty->port->buf;
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
@@ -280,7 +281,7 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
struct tty_buffer *tb;
spin_lock_irqsave(&buf->lock, flags);
- space = __tty_buffer_request_room(tty, goal);
+ space = __tty_buffer_request_room(tty->port, goal);
tb = buf->tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0)) {
@@ -311,13 +312,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
* the flags array indicates the status of the character. Returns the
* number added.
*
- * Locking: Called functions may take tty->buf.lock
+ * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_flags(struct tty_struct *tty,
const unsigned char *chars, const char *flags, size_t size)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &tty->port->buf;
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
@@ -326,7 +327,7 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
struct tty_buffer *tb;
spin_lock_irqsave(&buf->lock, __flags);
- space = __tty_buffer_request_room(tty, goal);
+ space = __tty_buffer_request_room(tty->port, goal);
tb = buf->tail;
/* If there is no space then tb may be NULL */
if (unlikely(space == 0)) {
@@ -357,12 +358,12 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
* Note that this function can only be used when the low_latency flag
* is unset. Otherwise the workqueue won't be flushed.
*
- * Locking: Takes tty->buf.lock
+ * Locking: Takes port->buf.lock
*/
void tty_schedule_flip(struct tty_struct *tty)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &tty->port->buf;
unsigned long flags;
spin_lock_irqsave(&buf->lock, flags);
@@ -385,19 +386,19 @@ EXPORT_SYMBOL(tty_schedule_flip);
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
*
- * Locking: May call functions taking tty->buf.lock
+ * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
- size_t size)
+ size_t size)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &tty->port->buf;
int space;
unsigned long flags;
struct tty_buffer *tb;
spin_lock_irqsave(&buf->lock, flags);
- space = __tty_buffer_request_room(tty, size);
+ space = __tty_buffer_request_room(tty->port, size);
tb = buf->tail;
if (likely(space)) {
@@ -423,19 +424,19 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
*
- * Locking: May call functions taking tty->buf.lock
+ * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &tty->port->buf;
int space;
unsigned long __flags;
struct tty_buffer *tb;
spin_lock_irqsave(&buf->lock, __flags);
- space = __tty_buffer_request_room(tty, size);
+ space = __tty_buffer_request_room(tty->port, size);
tb = buf->tail;
if (likely(space)) {
@@ -464,13 +465,16 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
static void flush_to_ldisc(struct work_struct *work)
{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, buf.work);
- struct tty_port *port = tty->port;
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_port *port = container_of(work, struct tty_port, buf.work);
+ struct tty_bufhead *buf = &port->buf;
+ struct tty_struct *tty;
unsigned long flags;
struct tty_ldisc *disc;
+ tty = port->itty;
+ if (WARN_RATELIMIT(tty == NULL, "tty is NULL"))
+ return;
+
disc = tty_ldisc_ref(tty);
if (disc == NULL) /* !TTY_LDISC */
return;
@@ -489,7 +493,7 @@ static void flush_to_ldisc(struct work_struct *work)
if (head->next == NULL)
break;
buf->head = head->next;
- tty_buffer_free(tty, head);
+ tty_buffer_free(port, head);
continue;
}
/* Ldisc or user is trying to flush the buffers
@@ -515,7 +519,7 @@ static void flush_to_ldisc(struct work_struct *work)
/* We may have a deferred request to flush the input buffer,
if so pull the chain under the lock and empty the queue */
if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
- __tty_buffer_flush(tty);
+ __tty_buffer_flush(port);
clear_bit(TTYP_FLUSHPENDING, &port->iflags);
wake_up(&tty->read_wait);
}
@@ -535,7 +539,7 @@ static void flush_to_ldisc(struct work_struct *work)
void tty_flush_to_ldisc(struct tty_struct *tty)
{
if (!tty->low_latency)
- flush_work(&tty->buf.work);
+ flush_work(&tty->port->buf.work);
}
/**
@@ -553,7 +557,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
void tty_flip_buffer_push(struct tty_struct *tty)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &tty->port->buf;
unsigned long flags;
spin_lock_irqsave(&buf->lock, flags);
@@ -578,9 +582,9 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
* Locking: none
*/
-void tty_buffer_init(struct tty_struct *tty)
+void tty_buffer_init(struct tty_port *port)
{
- struct tty_bufhead *buf = &tty->buf;
+ struct tty_bufhead *buf = &port->buf;
spin_lock_init(&buf->lock);
buf->head = NULL;