X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fn_tty.c;h=2bdb0144a22e3f0b4d8675826bdd0ea353ac3079;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=5a3be050e7bf0ba45cb83da487465910a0286321;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 5a3be050e..2bdb0144a 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -44,10 +44,10 @@ #include #include #include +#include #include #include -#include /* number of characters left in xmit buffer before select has we have room */ #define WAKEUP_CHARS 256 @@ -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); } @@ -152,7 +178,7 @@ static void reset_buffer_flags(struct tty_struct *tty) * lock_kernel() still. */ -void n_tty_flush_buffer(struct tty_struct * tty) +static void n_tty_flush_buffer(struct tty_struct * tty) { /* clear everything and unthrottle the driver */ reset_buffer_flags(tty); @@ -174,7 +200,7 @@ void n_tty_flush_buffer(struct tty_struct * tty) * at this instant in time. */ -ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) +static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) { unsigned long flags; ssize_t n = 0; @@ -270,7 +296,7 @@ static int opost(unsigned char c, struct tty_struct *tty) if (space < spaces) return -1; tty->column += spaces; - tty->driver->write(tty, 0, " ", spaces); + tty->driver->write(tty, " ", spaces); return 0; } tty->column += spaces; @@ -306,23 +332,17 @@ static int opost(unsigned char c, struct tty_struct *tty) */ static ssize_t opost_block(struct tty_struct * tty, - const unsigned char __user * inbuf, unsigned int nr) + const unsigned char * buf, unsigned int nr) { - char buf[80]; int space; int i; - char *cp; + const unsigned char *cp; space = tty->driver->write_room(tty); if (!space) return 0; if (nr > space) nr = space; - if (nr > sizeof(buf)) - nr = sizeof(buf); - - if (copy_from_user(buf, inbuf, nr)) - return -EFAULT; for (i = 0, cp = buf; i < nr; i++, cp++) { switch (*cp) { @@ -336,12 +356,8 @@ static ssize_t opost_block(struct tty_struct * tty, case '\r': if (O_ONOCR(tty) && tty->column == 0) goto break_out; - if (O_OCRNL(tty)) { - *cp = '\n'; - if (O_ONLRET(tty)) - tty->canon_column = tty->column = 0; - break; - } + if (O_OCRNL(tty)) + goto break_out; tty->canon_column = tty->column = 0; break; case '\t': @@ -352,7 +368,7 @@ static ssize_t opost_block(struct tty_struct * tty, break; default: if (O_OLCUC(tty)) - *cp = toupper(*cp); + goto break_out; if (!iscntrl(*cp)) tty->column++; break; @@ -361,7 +377,7 @@ static ssize_t opost_block(struct tty_struct * tty, break_out: if (tty->driver->flush_chars) tty->driver->flush_chars(tty); - i = tty->driver->write(tty, 0, buf, i); + i = tty->driver->write(tty, buf, i); return i; } @@ -616,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; } @@ -778,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; @@ -798,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; @@ -850,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 @@ -968,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)) @@ -979,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) @@ -1005,7 +994,7 @@ int is_ignored(int sig) * when the ldisc is closed. */ -static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) +static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old) { if (!tty) return; @@ -1014,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) || @@ -1066,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); } /** @@ -1141,26 +1132,25 @@ 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 * */ -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) { int retval; - ssize_t n; + size_t n; unsigned long flags; retval = 0; spin_lock_irqsave(&tty->read_lock, flags); n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail); - n = min((ssize_t)*nr, n); + n = min(*nr, n); spin_unlock_irqrestore(&tty->read_lock, flags); if (n) { - mb(); retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); n -= retval; spin_lock_irqsave(&tty->read_lock, flags); @@ -1271,16 +1261,15 @@ 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; } add_wait_queue(&tty->read_wait, &wait); - set_bit(TTY_DONT_FLIP, &tty->flags); while (nr) { /* First test for status change. */ if (tty->packet && tty->link->ctrl_status) { @@ -1323,9 +1312,8 @@ do_it_again: retval = -ERESTARTSYS; break; } - clear_bit(TTY_DONT_FLIP, &tty->flags); + n_tty_set_room(tty); timeout = schedule_timeout(timeout); - set_bit(TTY_DONT_FLIP, &tty->flags); continue; } __set_current_state(TASK_RUNNING); @@ -1392,16 +1380,17 @@ 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; if (time) 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)) @@ -1416,6 +1405,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; } @@ -1435,9 +1426,9 @@ do_it_again: */ static ssize_t write_chan(struct tty_struct * tty, struct file * file, - const unsigned char __user * buf, size_t nr) + const unsigned char * buf, size_t nr) { - const unsigned char __user *b = buf; + const unsigned char *b = buf; DECLARE_WAITQUEUE(wait, current); int c; ssize_t retval = 0; @@ -1473,7 +1464,7 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file, nr -= num; if (nr == 0) break; - get_user(c, b); + c = *b; if (opost(c, tty) < 0) break; b++; nr--; @@ -1481,13 +1472,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, 1, 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; @@ -1564,7 +1559,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 */ };