aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_buffer.c
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-06-15 09:14:14 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-23 19:42:59 -0400
commitda261e7fe7b0e23a0d4d46039d20dc60fa197b49 (patch)
tree829f2d3cd05150f399b89460b1796afb64f9770d /drivers/tty/tty_buffer.c
parent3b80df7ca7e2fec76be2eda304cc7e0eb90f911d (diff)
tty: Simplify tty buffer/ldisc interface with helper function
Ldisc interface functions must be called with interrupts enabled. Separating the ldisc calls into a helper function simplies the eventual removal of the spinlock. Note that access to the buf->head ptr outside the spinlock is safe here because; * __tty_buffer_flush() is prevented from running while buffer work performs i/o, * tty_buffer_find() only assigns buf->head if the flip buffer list is empty (which is never the case in flush_to_ldisc() since at least one buffer is always left in the list after use) Access to the read index outside the spinlock is safe here for the same reasons. Update the buffer's read index _after_ the data has been received by the ldisc. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r--drivers/tty/tty_buffer.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index a42a028a9d4e..6c7a1d043c76 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -403,6 +403,18 @@ int tty_prepare_flip_string_flags(struct tty_port *port,
403EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); 403EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
404 404
405 405
406static int
407receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
408{
409 struct tty_ldisc *disc = tty->ldisc;
410
411 count = min_t(int, count, tty->receive_room);
412 if (count)
413 disc->ops->receive_buf(tty, head->char_buf_ptr + head->read,
414 head->flag_buf_ptr + head->read, count);
415 head->read += count;
416 return count;
417}
406 418
407/** 419/**
408 * flush_to_ldisc 420 * flush_to_ldisc
@@ -438,8 +450,6 @@ static void flush_to_ldisc(struct work_struct *work)
438 struct tty_buffer *head; 450 struct tty_buffer *head;
439 while ((head = buf->head) != NULL) { 451 while ((head = buf->head) != NULL) {
440 int count; 452 int count;
441 char *char_buf;
442 unsigned char *flag_buf;
443 453
444 count = head->commit - head->read; 454 count = head->commit - head->read;
445 if (!count) { 455 if (!count) {
@@ -449,16 +459,10 @@ static void flush_to_ldisc(struct work_struct *work)
449 tty_buffer_free(port, head); 459 tty_buffer_free(port, head);
450 continue; 460 continue;
451 } 461 }
452 if (!tty->receive_room)
453 break;
454 if (count > tty->receive_room)
455 count = tty->receive_room;
456 char_buf = head->char_buf_ptr + head->read;
457 flag_buf = head->flag_buf_ptr + head->read;
458 head->read += count;
459 spin_unlock_irqrestore(&buf->lock, flags); 462 spin_unlock_irqrestore(&buf->lock, flags);
460 disc->ops->receive_buf(tty, char_buf, 463
461 flag_buf, count); 464 count = receive_buf(tty, head, count);
465
462 spin_lock_irqsave(&buf->lock, flags); 466 spin_lock_irqsave(&buf->lock, flags);
463 /* Ldisc or user is trying to flush the buffers. 467 /* Ldisc or user is trying to flush the buffers.
464 We may have a deferred request to flush the 468 We may have a deferred request to flush the
@@ -469,7 +473,8 @@ static void flush_to_ldisc(struct work_struct *work)
469 clear_bit(TTYP_FLUSHPENDING, &port->iflags); 473 clear_bit(TTYP_FLUSHPENDING, &port->iflags);
470 wake_up(&tty->read_wait); 474 wake_up(&tty->read_wait);
471 break; 475 break;
472 } 476 } else if (!count)
477 break;
473 } 478 }
474 clear_bit(TTYP_FLUSHING, &port->iflags); 479 clear_bit(TTYP_FLUSHING, &port->iflags);
475 } 480 }