X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fn_tty.c;h=b9371d5bf7906b48d4b340c5a8756c3fa132f516;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=ae09412cc31796c14e4fba3935f1ac9e6fe8ff7d;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index ae09412cc..b9371d5bf 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -62,7 +62,7 @@ static inline unsigned char *alloc_buf(void) { - int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; if (PAGE_SIZE != N_TTY_BUF_SIZE) return kmalloc(N_TTY_BUF_SIZE, prio); @@ -78,7 +78,32 @@ static inline void free_buf(unsigned char *buf) free_page((unsigned long) buf); } -static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) +/** + * n_tty_set__room - receive space + * @tty: terminal + * + * Called by the driver to find out how much data it is + * permitted to feed to the line discipline without any being lost + * and thus to manage flow control. Not serialized. Answers for the + * "instant". + */ + +static void n_tty_set_room(struct tty_struct *tty) +{ + int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + + /* + * If we are doing input canonicalization, and there are no + * pending newlines, let characters through without limit, so + * that erase characters will be handled. Other excess + * characters will be beeped. + */ + if (left <= 0) + left = tty->icanon && !tty->canon_data; + tty->receive_room = left; +} + +static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) { if (tty->read_cnt < N_TTY_BUF_SIZE) { tty->read_buf[tty->read_head] = c; @@ -87,7 +112,7 @@ static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) } } -static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) +static void put_tty_queue(unsigned char c, struct tty_struct *tty) { unsigned long flags; /* @@ -107,7 +132,7 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) * We test the TTY_THROTTLED bit first so that it always * indicates the current state. The decision about whether * it is worth allowing more input has been taken by the caller. - * Can sleep, may be called under the atomic_read semaphore but + * Can sleep, may be called under the atomic_read_lock mutex but * this is not guaranteed. */ @@ -136,6 +161,7 @@ static void reset_buffer_flags(struct tty_struct *tty) spin_unlock_irqrestore(&tty->read_lock, flags); tty->canon_head = tty->canon_data = tty->erasing = 0; memset(&tty->read_flags, 0, sizeof tty->read_flags); + n_tty_set_room(tty); check_unthrottle(tty); } @@ -606,9 +632,11 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty) char buf[64]; tty->num_overrun++; - if (time_before(tty->overrun_time, jiffies - HZ)) { - printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), - tty->num_overrun); + if (time_before(tty->overrun_time, jiffies - HZ) || + time_after(tty->overrun_time, jiffies)) { + printk(KERN_WARNING "%s: %d input overrun(s)\n", + tty_name(tty, buf), + tty->num_overrun); tty->overrun_time = jiffies; tty->num_overrun = 0; } @@ -768,10 +796,8 @@ send_signal: } if (c == '\n') { if (L_ECHO(tty) || L_ECHONL(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) put_char('\a', tty); - return; - } opost('\n', tty); } goto handle_newline; @@ -788,10 +814,8 @@ send_signal: * XXX are EOL_CHAR and EOL2_CHAR echoed?!? */ if (L_ECHO(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) put_char('\a', tty); - return; - } /* Record the column of first canon char. */ if (tty->canon_head == tty->read_head) tty->canon_column = tty->column; @@ -840,33 +864,6 @@ send_signal: put_tty_queue(c, tty); } -/** - * n_tty_receive_room - receive space - * @tty: terminal - * - * Called by the driver to find out how much data it is - * permitted to feed to the line discipline without any being lost - * and thus to manage flow control. Not serialized. Answers for the - * "instant". - */ - -static int n_tty_receive_room(struct tty_struct *tty) -{ - int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; - - /* - * If we are doing input canonicalization, and there are no - * pending newlines, let characters through without limit, so - * that erase characters will be handled. Other excess - * characters will be beeped. - */ - if (tty->icanon && !tty->canon_data) - return N_TTY_BUF_SIZE; - - if (left > 0) - return left; - return 0; -} /** * n_tty_write_wakeup - asynchronous I/O notifier @@ -958,6 +955,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, tty->driver->flush_chars(tty); } + n_tty_set_room(tty); + if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) @@ -969,7 +968,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, * mode. We don't want to throttle the driver if we're in * canonical mode and don't have a newline yet! */ - if (n_tty_receive_room(tty) < TTY_THRESHOLD_THROTTLE) { + if (tty->receive_room < TTY_THRESHOLD_THROTTLE) { /* check TTY_THROTTLED first so it indicates our state */ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && tty->driver->throttle) @@ -1004,6 +1003,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { tty->raw = 1; tty->real_raw = 1; + n_tty_set_room(tty); return; } if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || @@ -1056,6 +1056,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) else tty->real_raw = 0; } + n_tty_set_room(tty); } /** @@ -1131,11 +1132,11 @@ static inline int input_available_p(struct tty_struct *tty, int amt) * buffer, and once to drain the space from the (physical) beginning of * the buffer to head pointer. * - * Called under the tty->atomic_read sem and with TTY_DONT_FLIP set + * Called under the tty->atomic_read_lock sem and with TTY_DONT_FLIP set * */ -static inline int copy_from_read_buf(struct tty_struct *tty, +static int copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr) @@ -1261,11 +1262,11 @@ do_it_again: * Internal serialization of reads. */ if (file->f_flags & O_NONBLOCK) { - if (down_trylock(&tty->atomic_read)) + if (!mutex_trylock(&tty->atomic_read_lock)) return -EAGAIN; } else { - if (down_interruptible(&tty->atomic_read)) + if (mutex_lock_interruptible(&tty->atomic_read_lock)) return -ERESTARTSYS; } @@ -1313,6 +1314,7 @@ do_it_again: retval = -ERESTARTSYS; break; } + n_tty_set_room(tty); clear_bit(TTY_DONT_FLIP, &tty->flags); timeout = schedule_timeout(timeout); set_bit(TTY_DONT_FLIP, &tty->flags); @@ -1382,8 +1384,10 @@ do_it_again: * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode, * we won't get any more characters. */ - if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) + if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) { + n_tty_set_room(tty); check_unthrottle(tty); + } if (b - buf >= minimum) break; @@ -1391,7 +1395,7 @@ do_it_again: timeout = time; } clear_bit(TTY_DONT_FLIP, &tty->flags); - up(&tty->atomic_read); + mutex_unlock(&tty->atomic_read_lock); remove_wait_queue(&tty->read_wait, &wait); if (!waitqueue_active(&tty->read_wait)) @@ -1406,6 +1410,8 @@ do_it_again: } else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) goto do_it_again; + n_tty_set_room(tty); + return retval; } @@ -1471,13 +1477,17 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file, if (tty->driver->flush_chars) tty->driver->flush_chars(tty); } else { - c = tty->driver->write(tty, b, nr); - if (c < 0) { - retval = c; - goto break_out; + while (nr > 0) { + c = tty->driver->write(tty, b, nr); + if (c < 0) { + retval = c; + goto break_out; + } + if (!c) + break; + b += c; + nr -= c; } - b += c; - nr -= c; } if (!nr) break; @@ -1554,7 +1564,6 @@ struct tty_ldisc tty_ldisc_N_TTY = { normal_poll, /* poll */ NULL, /* hangup */ n_tty_receive_buf, /* receive_buf */ - n_tty_receive_room, /* receive_room */ n_tty_write_wakeup /* write_wakeup */ };