aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorPaul Fulghum <paulkf@microgate.com>2006-06-28 07:26:48 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-28 17:59:05 -0400
commit2c3bb20f46709a0adfa7ea408013edbcab945d5a (patch)
tree951dde0a4ea31892635886afb1e3f0f03847b1f0 /drivers/char
parent817d6d3bceaf34c99f5343820f9b9e6021f0655c (diff)
[PATCH] add receive_room flow control to flush_to_ldisc
Flush data serially to line discipline in blocks no larger than tty->receive_room to avoid losing data if line discipline is busy (such as N_TTY operating at high speed on heavily loaded system) or does not accept data in large blocks (such as N_MOUSE). Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/tty_io.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index b846d87f2b56..1f03ebf165d9 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2771,8 +2771,7 @@ static void flush_to_ldisc(void *private_)
2771 struct tty_struct *tty = (struct tty_struct *) private_; 2771 struct tty_struct *tty = (struct tty_struct *) private_;
2772 unsigned long flags; 2772 unsigned long flags;
2773 struct tty_ldisc *disc; 2773 struct tty_ldisc *disc;
2774 struct tty_buffer *tbuf; 2774 struct tty_buffer *tbuf, *head;
2775 int count;
2776 char *char_buf; 2775 char *char_buf;
2777 unsigned char *flag_buf; 2776 unsigned char *flag_buf;
2778 2777
@@ -2781,21 +2780,33 @@ static void flush_to_ldisc(void *private_)
2781 return; 2780 return;
2782 2781
2783 spin_lock_irqsave(&tty->buf.lock, flags); 2782 spin_lock_irqsave(&tty->buf.lock, flags);
2784 while((tbuf = tty->buf.head) != NULL) { 2783 head = tty->buf.head;
2785 while ((count = tbuf->commit - tbuf->read) != 0) { 2784 if (head != NULL) {
2786 char_buf = tbuf->char_buf_ptr + tbuf->read; 2785 tty->buf.head = NULL;
2787 flag_buf = tbuf->flag_buf_ptr + tbuf->read; 2786 for (;;) {
2788 tbuf->read += count; 2787 int count = head->commit - head->read;
2788 if (!count) {
2789 if (head->next == NULL)
2790 break;
2791 tbuf = head;
2792 head = head->next;
2793 tty_buffer_free(tty, tbuf);
2794 continue;
2795 }
2796 if (!tty->receive_room) {
2797 schedule_delayed_work(&tty->buf.work, 1);
2798 break;
2799 }
2800 if (count > tty->receive_room)
2801 count = tty->receive_room;
2802 char_buf = head->char_buf_ptr + head->read;
2803 flag_buf = head->flag_buf_ptr + head->read;
2804 head->read += count;
2789 spin_unlock_irqrestore(&tty->buf.lock, flags); 2805 spin_unlock_irqrestore(&tty->buf.lock, flags);
2790 disc->receive_buf(tty, char_buf, flag_buf, count); 2806 disc->receive_buf(tty, char_buf, flag_buf, count);
2791 spin_lock_irqsave(&tty->buf.lock, flags); 2807 spin_lock_irqsave(&tty->buf.lock, flags);
2792 } 2808 }
2793 if (tbuf->active) 2809 tty->buf.head = head;
2794 break;
2795 tty->buf.head = tbuf->next;
2796 if (tty->buf.head == NULL)
2797 tty->buf.tail = NULL;
2798 tty_buffer_free(tty, tbuf);
2799 } 2810 }
2800 spin_unlock_irqrestore(&tty->buf.lock, flags); 2811 spin_unlock_irqrestore(&tty->buf.lock, flags);
2801 2812