X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fn_tty.c;h=2bdb0144a22e3f0b4d8675826bdd0ea353ac3079;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=0721974625424078677b352223a2baea5a6f1e6f;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 072197462..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; /* @@ -99,11 +124,18 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) spin_unlock_irqrestore(&tty->read_lock, flags); } -/* - * Check whether to call the driver.unthrottle function. - * We test the TTY_THROTTLED bit first so that it always - * indicates the current state. +/** + * check_unthrottle - allow new receive data + * @tty; tty device + * + * Check whether to call the driver.unthrottle function. + * 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_lock mutex but + * this is not guaranteed. */ + static void check_unthrottle(struct tty_struct * tty) { if (tty->count && @@ -112,10 +144,13 @@ static void check_unthrottle(struct tty_struct * tty) tty->driver->unthrottle(tty); } -/* - * Reset the read buffer counters, clear the flags, - * and make sure the driver is unthrottled. Called - * from n_tty_open() and n_tty_flush_buffer(). +/** + * reset_buffer_flags - reset buffer state + * @tty: terminal to reset + * + * Reset the read buffer counters, clear the flags, + * and make sure the driver is unthrottled. Called + * from n_tty_open() and n_tty_flush_buffer(). */ static void reset_buffer_flags(struct tty_struct *tty) { @@ -126,13 +161,24 @@ 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); } -/* - * Flush the input buffer +/** + * n_tty_flush_buffer - clean input queue + * @tty: terminal device + * + * Flush the input buffer. Called when the line discipline is + * being closed, when the tty layer wants the buffer flushed (eg + * at hangup) or when the N_TTY line discipline internally has to + * clean the pending queue (for example some signals). + * + * FIXME: tty->ctrl_status is not spinlocked and relies on + * 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); @@ -146,10 +192,15 @@ void n_tty_flush_buffer(struct tty_struct * tty) } } -/* - * Return number of characters buffered to be delivered to user +/** + * n_tty_chars_in_buffer - report available bytes + * @tty: tty device + * + * Report the number of characters buffered to be delivered to user + * 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; @@ -166,20 +217,47 @@ ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) return n; } +/** + * is_utf8_continuation - utf8 multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character. We use this to correctly compute the on screen size + * of the character when printing + */ + static inline int is_utf8_continuation(unsigned char c) { return (c & 0xc0) == 0x80; } +/** + * is_continuation - multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character and the terminal is in unicode mode. + */ + static inline int is_continuation(unsigned char c, struct tty_struct *tty) { return I_IUTF8(tty) && is_utf8_continuation(c); } -/* - * Perform OPOST processing. Returns -1 when the output device is - * full and the character must be retried. +/** + * opost - output post processor + * @c: character (or partial unicode symbol) + * @tty: terminal device + * + * Perform OPOST processing. Returns -1 when the output device is + * full and the character must be retried. Note that Linux currently + * ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. They simply aren't + * relevant in the world today. If you ever need them, add them here. + * + * Called from both the receive and transmit sides and can be called + * re-entrantly. Relies on lock_kernel() still. */ + static int opost(unsigned char c, struct tty_struct *tty) { int space, spaces; @@ -218,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; @@ -239,28 +317,32 @@ static int opost(unsigned char c, struct tty_struct *tty) return 0; } -/* - * opost_block --- to speed up block console writes, among other - * things. +/** + * opost_block - block postprocess + * @tty: terminal device + * @inbuf: user buffer + * @nr: number of bytes + * + * This path is used to speed up block console writes, among other + * things when processing blocks of output data. It handles only + * the simple cases normally found and helps to generate blocks of + * symbols for the console driver and thus improve performance. + * + * Called from write_chan under the tty layer write lock. */ + 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) { @@ -274,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': @@ -290,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; @@ -299,18 +377,32 @@ 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; } - +/** + * put_char - write character to driver + * @c: character (or part of unicode symbol) + * @tty: terminal device + * + * Queue a byte to the driver layer for output + */ + static inline void put_char(unsigned char c, struct tty_struct *tty) { tty->driver->put_char(tty, c); } -/* Must be called only when L_ECHO(tty) is true. */ +/** + * echo_char - echo characters + * @c: unicode byte to echo + * @tty: terminal device + * + * Echo user input back onto the screen. This must be called only when + * L_ECHO(tty) is true. Called from the driver receive_buf path. + */ static void echo_char(unsigned char c, struct tty_struct *tty) { @@ -331,6 +423,16 @@ static inline void finish_erasing(struct tty_struct *tty) } } +/** + * eraser - handle erase function + * @c: character input + * @tty: terminal device + * + * Perform erase and neccessary output when an erase character is + * present in the stream from the driver layer. Handles the complexities + * of UTF-8 multibyte symbols. + */ + static void eraser(unsigned char c, struct tty_struct *tty) { enum { ERASE, WERASE, KILL } kill_type; @@ -463,6 +565,18 @@ static void eraser(unsigned char c, struct tty_struct *tty) finish_erasing(tty); } +/** + * isig - handle the ISIG optio + * @sig: signal + * @tty: terminal + * @flush: force flush + * + * Called when a signal is being sent due to terminal input. This + * may caus terminal flushing to take place according to the termios + * settings and character used. Called from the driver receive_buf + * path so serialized. + */ + static inline void isig(int sig, struct tty_struct *tty, int flush) { if (tty->pgrp > 0) @@ -474,6 +588,16 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) } } +/** + * n_tty_receive_break - handle break + * @tty: terminal + * + * An RS232 break event has been hit in the incoming bitstream. This + * can cause a variety of events depending upon the termios settings. + * + * Called from the receive_buf path so single threaded. + */ + static inline void n_tty_receive_break(struct tty_struct *tty) { if (I_IGNBRK(tty)) @@ -490,19 +614,42 @@ static inline void n_tty_receive_break(struct tty_struct *tty) wake_up_interruptible(&tty->read_wait); } +/** + * n_tty_receive_overrun - handle overrun reporting + * @tty: terminal + * + * Data arrived faster than we could process it. While the tty + * driver has flagged this the bits that were missed are gone + * forever. + * + * Called from the receive_buf path so single threaded. Does not + * need locking as num_overrun and overrun_time are function + * private. + */ + 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("%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; } } +/** + * n_tty_receive_parity_error - error notifier + * @tty: terminal device + * @c: character + * + * Process a parity error and queue the right data to indicate + * the error case if neccessary. Locking as per n_tty_receive_buf. + */ static inline void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { @@ -520,6 +667,16 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, wake_up_interruptible(&tty->read_wait); } +/** + * n_tty_receive_char - perform processing + * @tty: terminal device + * @c: character + * + * Process an individual character of input received from the driver. + * This is serialized with respect to itself by the rules for the + * driver above. + */ + static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { unsigned long flags; @@ -639,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; @@ -659,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; @@ -711,28 +864,14 @@ send_signal: put_tty_queue(c, tty); } -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; -} -/* - * Required for the ptys, serial driver etc. since processes - * that attach themselves to the master and rely on ASYNC - * IO must be woken up +/** + * n_tty_write_wakeup - asynchronous I/O notifier + * @tty: tty device + * + * Required for the ptys, serial driver etc. since processes + * that attach themselves to the master and rely on ASYNC + * IO must be woken up */ static void n_tty_write_wakeup(struct tty_struct *tty) @@ -745,6 +884,19 @@ static void n_tty_write_wakeup(struct tty_struct *tty) return; } +/** + * n_tty_receive_buf - data receive + * @tty: terminal device + * @cp: buffer + * @fp: flag buffer + * @count: characters + * + * Called by the terminal driver when a block of characters has + * been received. This function must be called from soft contexts + * not from interrupt context. The driver is responsible for making + * calls one at a time and in order (or using flush_to_ldisc) + */ + static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { @@ -803,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)) @@ -814,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) @@ -828,7 +982,19 @@ int is_ignored(int sig) current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); } -static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) +/** + * n_tty_set_termios - termios data changed + * @tty: terminal + * @old: previous data + * + * Called by the tty layer when the user changes termios flags so + * that the line discipline can plan ahead. This function cannot sleep + * and is protected from re-entry by the tty layer. The user is + * guaranteed that this function will not be re-entered or in progress + * when the ldisc is closed. + */ + +static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old) { if (!tty) return; @@ -837,13 +1003,13 @@ 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) || I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { - local_irq_disable(); // FIXME: is this safe? memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) @@ -879,7 +1045,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) set_bit(SUSP_CHAR(tty), tty->process_char_map); } clear_bit(__DISABLED_CHAR, tty->process_char_map); - local_irq_enable(); // FIXME: is this safe? tty->raw = 0; tty->real_raw = 0; } else { @@ -891,8 +1056,19 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) else tty->real_raw = 0; } + n_tty_set_room(tty); } +/** + * n_tty_close - close the ldisc for this tty + * @tty: device + * + * Called from the terminal layer when this line discipline is + * being shut down, either because of a close or becsuse of a + * discipline change. The function will not be called while other + * ldisc methods are in progress. + */ + static void n_tty_close(struct tty_struct *tty) { n_tty_flush_buffer(tty); @@ -902,11 +1078,22 @@ static void n_tty_close(struct tty_struct *tty) } } +/** + * n_tty_open - open an ldisc + * @tty: terminal to open + * + * Called when this line discipline is being attached to the + * terminal device. Can sleep. Called serialized so that no + * other events will occur in parallel. No further open will occur + * until a close. + */ + static int n_tty_open(struct tty_struct *tty) { if (!tty) return -EINVAL; + /* This one is ugly. Currently a malloc failure here can panic */ if (!tty->read_buf) { tty->read_buf = alloc_buf(); if (!tty->read_buf) @@ -932,30 +1119,38 @@ static inline int input_available_p(struct tty_struct *tty, int amt) return 0; } -/* - * Helper function to speed up read_chan. It is only called when - * ICANON is off; it copies characters straight from the tty queue to - * user space directly. It can be profitably called twice; once to - * drain the space from the tail pointer to the (physical) end of the - * buffer, and once to drain the space from the (physical) beginning of - * the buffer to head pointer. +/** + * copy_from_read_buf - copy read data directly + * @tty: terminal device + * @b: user data + * @nr: size of data + * + * Helper function to speed up read_chan. It is only called when + * ICANON is off; it copies characters straight from the tty queue to + * user space directly. It can be profitably called twice; once to + * drain the space from the tail pointer to the (physical) end of the + * buffer, and once to drain the space from the (physical) beginning of + * the buffer to head pointer. + * + * 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); @@ -970,25 +1165,18 @@ static inline int copy_from_read_buf(struct tty_struct *tty, extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *); -static ssize_t read_chan(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) +/** + * job_control - check job control + * @tty: tty + * @file: file handle + * + * Perform job control management checks on this file/tty descriptor + * and if appropriate send any needed signals and return a negative + * error code if action should be taken. + */ + +static int job_control(struct tty_struct *tty, struct file *file) { - unsigned char __user *b = buf; - DECLARE_WAITQUEUE(wait, current); - int c; - int minimum, time; - ssize_t retval = 0; - ssize_t size; - long timeout; - unsigned long flags; - -do_it_again: - - if (!tty->read_buf) { - printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); - return -EIO; - } - /* Job control check -- must be done at start and after every sleep (POSIX.1 7.1.1.4). */ /* NOTE: not yet done after every sleep pending a thorough @@ -1006,7 +1194,48 @@ do_it_again: return -ERESTARTSYS; } } + return 0; +} + + +/** + * read_chan - read function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Perform reads for the line discipline. We are guaranteed that the + * line discipline will not be closed under us but we may get multiple + * parallel readers and must handle this ourselves. We may also get + * a hangup. Always called in user context, may sleep. + * + * This code must be sure never to sleep through a hangup. + */ + +static ssize_t read_chan(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) +{ + unsigned char __user *b = buf; + DECLARE_WAITQUEUE(wait, current); + int c; + int minimum, time; + ssize_t retval = 0; + ssize_t size; + long timeout; + unsigned long flags; + +do_it_again: + if (!tty->read_buf) { + printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); + return -EIO; + } + + c = job_control(tty, file); + if(c < 0) + return c; + minimum = time = 0; timeout = MAX_SCHEDULE_TIMEOUT; if (!tty->icanon) { @@ -1028,17 +1257,19 @@ 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) { @@ -1081,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); @@ -1150,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)) @@ -1174,13 +1405,30 @@ do_it_again: } else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) goto do_it_again; + n_tty_set_room(tty); + return retval; } +/** + * write_chan - write function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Write function of the terminal device. This is serialized with + * respect to other write callers but not to termios changes, reads + * and other such events. We must be careful with N_TTY as the receive + * code will echo characters, thus calling driver write methods. + * + * This code must be sure never to sleep through a hangup. + */ + 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; @@ -1216,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--; @@ -1224,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; @@ -1246,7 +1498,25 @@ break_out: return (b - buf) ? b - buf : retval; } -/* Called without the kernel lock held - fine */ +/** + * normal_poll - poll method for N_TTY + * @tty: terminal device + * @file: file accessing it + * @wait: poll table + * + * Called when the line discipline is asked to poll() for data or + * for special events. This code is not serialized with respect to + * other events save open/close. + * + * This code must be sure never to sleep through a hangup. + * Called without the kernel lock held - fine + * + * FIXME: if someone changes the VMIN or discipline settings for the + * terminal while another process is in poll() the poll does not + * recompute the new limits. Possibly set_termios should issue + * a read wakeup to fix this bug. + */ + static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) { unsigned int mask = 0; @@ -1287,8 +1557,8 @@ struct tty_ldisc tty_ldisc_N_TTY = { n_tty_ioctl, /* ioctl */ n_tty_set_termios, /* set_termios */ normal_poll, /* poll */ + NULL, /* hangup */ n_tty_receive_buf, /* receive_buf */ - n_tty_receive_room, /* receive_room */ n_tty_write_wakeup /* write_wakeup */ };