diff options
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r-- | drivers/tty/n_tty.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 7cdd1eb9406c..34aacaaae14a 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -93,6 +93,7 @@ struct n_tty_data { | |||
93 | size_t canon_head; | 93 | size_t canon_head; |
94 | size_t echo_head; | 94 | size_t echo_head; |
95 | size_t echo_commit; | 95 | size_t echo_commit; |
96 | size_t echo_mark; | ||
96 | DECLARE_BITMAP(char_map, 256); | 97 | DECLARE_BITMAP(char_map, 256); |
97 | 98 | ||
98 | /* private to n_tty_receive_overrun (single-threaded) */ | 99 | /* private to n_tty_receive_overrun (single-threaded) */ |
@@ -336,6 +337,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata) | |||
336 | { | 337 | { |
337 | ldata->read_head = ldata->canon_head = ldata->read_tail = 0; | 338 | ldata->read_head = ldata->canon_head = ldata->read_tail = 0; |
338 | ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; | 339 | ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; |
340 | ldata->echo_mark = 0; | ||
339 | ldata->line_start = 0; | 341 | ldata->line_start = 0; |
340 | 342 | ||
341 | ldata->erasing = 0; | 343 | ldata->erasing = 0; |
@@ -768,7 +770,7 @@ static size_t __process_echoes(struct tty_struct *tty) | |||
768 | * data at the tail to prevent a subsequent overrun */ | 770 | * data at the tail to prevent a subsequent overrun */ |
769 | while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { | 771 | while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { |
770 | if (echo_buf(ldata, tail) == ECHO_OP_START) { | 772 | if (echo_buf(ldata, tail) == ECHO_OP_START) { |
771 | if (echo_buf(ldata, tail) == ECHO_OP_ERASE_TAB) | 773 | if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB) |
772 | tail += 3; | 774 | tail += 3; |
773 | else | 775 | else |
774 | tail += 2; | 776 | tail += 2; |
@@ -787,6 +789,7 @@ static void commit_echoes(struct tty_struct *tty) | |||
787 | size_t head; | 789 | size_t head; |
788 | 790 | ||
789 | head = ldata->echo_head; | 791 | head = ldata->echo_head; |
792 | ldata->echo_mark = head; | ||
790 | old = ldata->echo_commit - ldata->echo_tail; | 793 | old = ldata->echo_commit - ldata->echo_tail; |
791 | 794 | ||
792 | /* Process committed echoes if the accumulated # of bytes | 795 | /* Process committed echoes if the accumulated # of bytes |
@@ -810,10 +813,12 @@ static void process_echoes(struct tty_struct *tty) | |||
810 | struct n_tty_data *ldata = tty->disc_data; | 813 | struct n_tty_data *ldata = tty->disc_data; |
811 | size_t echoed; | 814 | size_t echoed; |
812 | 815 | ||
813 | if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_tail) | 816 | if ((!L_ECHO(tty) && !L_ECHONL(tty)) || |
817 | ldata->echo_mark == ldata->echo_tail) | ||
814 | return; | 818 | return; |
815 | 819 | ||
816 | mutex_lock(&ldata->output_lock); | 820 | mutex_lock(&ldata->output_lock); |
821 | ldata->echo_commit = ldata->echo_mark; | ||
817 | echoed = __process_echoes(tty); | 822 | echoed = __process_echoes(tty); |
818 | mutex_unlock(&ldata->output_lock); | 823 | mutex_unlock(&ldata->output_lock); |
819 | 824 | ||
@@ -821,11 +826,13 @@ static void process_echoes(struct tty_struct *tty) | |||
821 | tty->ops->flush_chars(tty); | 826 | tty->ops->flush_chars(tty); |
822 | } | 827 | } |
823 | 828 | ||
829 | /* NB: echo_mark and echo_head should be equivalent here */ | ||
824 | static void flush_echoes(struct tty_struct *tty) | 830 | static void flush_echoes(struct tty_struct *tty) |
825 | { | 831 | { |
826 | struct n_tty_data *ldata = tty->disc_data; | 832 | struct n_tty_data *ldata = tty->disc_data; |
827 | 833 | ||
828 | if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_head) | 834 | if ((!L_ECHO(tty) && !L_ECHONL(tty)) || |
835 | ldata->echo_commit == ldata->echo_head) | ||
829 | return; | 836 | return; |
830 | 837 | ||
831 | mutex_lock(&ldata->output_lock); | 838 | mutex_lock(&ldata->output_lock); |
@@ -1998,7 +2005,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, | |||
1998 | found = 1; | 2005 | found = 1; |
1999 | 2006 | ||
2000 | size = N_TTY_BUF_SIZE - tail; | 2007 | size = N_TTY_BUF_SIZE - tail; |
2001 | n = (found + eol + size) & (N_TTY_BUF_SIZE - 1); | 2008 | n = eol - tail; |
2009 | if (n > 4096) | ||
2010 | n += 4096; | ||
2011 | n += found; | ||
2002 | c = n; | 2012 | c = n; |
2003 | 2013 | ||
2004 | if (found && read_buf(ldata, eol) == __DISABLED_CHAR) { | 2014 | if (found && read_buf(ldata, eol) == __DISABLED_CHAR) { |
@@ -2243,18 +2253,19 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, | |||
2243 | if (time) | 2253 | if (time) |
2244 | timeout = time; | 2254 | timeout = time; |
2245 | } | 2255 | } |
2246 | mutex_unlock(&ldata->atomic_read_lock); | 2256 | n_tty_set_room(tty); |
2247 | remove_wait_queue(&tty->read_wait, &wait); | 2257 | up_read(&tty->termios_rwsem); |
2248 | 2258 | ||
2259 | remove_wait_queue(&tty->read_wait, &wait); | ||
2249 | if (!waitqueue_active(&tty->read_wait)) | 2260 | if (!waitqueue_active(&tty->read_wait)) |
2250 | ldata->minimum_to_wake = minimum; | 2261 | ldata->minimum_to_wake = minimum; |
2251 | 2262 | ||
2263 | mutex_unlock(&ldata->atomic_read_lock); | ||
2264 | |||
2252 | __set_current_state(TASK_RUNNING); | 2265 | __set_current_state(TASK_RUNNING); |
2253 | if (b - buf) | 2266 | if (b - buf) |
2254 | retval = b - buf; | 2267 | retval = b - buf; |
2255 | 2268 | ||
2256 | n_tty_set_room(tty); | ||
2257 | up_read(&tty->termios_rwsem); | ||
2258 | return retval; | 2269 | return retval; |
2259 | } | 2270 | } |
2260 | 2271 | ||