n_tty: do O_ONLCR translation as a single write
[safe/jmp/linux-2.6] / drivers / char / n_tty.c
index 4b1e96b..4e28b35 100644 (file)
 #define ECHO_OP_SET_CANON_COL 0x81
 #define ECHO_OP_ERASE_TAB 0x82
 
-static inline unsigned char *alloc_buf(void)
-{
-       gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
-
-       if (PAGE_SIZE != N_TTY_BUF_SIZE)
-               return kmalloc(N_TTY_BUF_SIZE, prio);
-       else
-               return (unsigned char *)__get_free_page(prio);
-}
-
-static inline void free_buf(unsigned char *buf)
-{
-       if (PAGE_SIZE != N_TTY_BUF_SIZE)
-               kfree(buf);
-       else
-               free_page((unsigned long) buf);
-}
-
 static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
                               unsigned char __user *ptr)
 {
@@ -318,8 +300,7 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
                        if (space < 2)
                                return -1;
                        tty->canon_column = tty->column = 0;
-                       tty_put_char(tty, '\r');
-                       tty_put_char(tty, c);
+                       tty->ops->write(tty, "\r\n", 2);
                        return 2;
                }
                tty->canon_column = tty->column;
@@ -872,7 +853,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
 
        /* FIXME: locking needed ? */
        if (tty->read_head == tty->canon_head) {
-               /* echo_char_raw('\a', tty); */ /* what do you think? */
+               /* process_output('\a', tty); */ /* what do you think? */
                return;
        }
        if (c == ERASE_CHAR(tty))
@@ -1148,10 +1129,8 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
                parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
                if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
                        /* beep if no space */
-                       if (L_ECHO(tty)) {
-                               echo_char_raw('\a', tty);
-                               process_echoes(tty);
-                       }
+                       if (L_ECHO(tty))
+                               process_output('\a', tty);
                        return;
                }
                if (L_ECHO(tty)) {
@@ -1255,10 +1234,8 @@ send_signal:
                }
                if (c == '\n') {
                        if (tty->read_cnt >= N_TTY_BUF_SIZE) {
-                               if (L_ECHO(tty)) {
-                                       echo_char_raw('\a', tty);
-                                       process_echoes(tty);
-                               }
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
                                return;
                        }
                        if (L_ECHO(tty) || L_ECHONL(tty)) {
@@ -1280,10 +1257,8 @@ send_signal:
                        parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
                                 ? 1 : 0;
                        if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
-                               if (L_ECHO(tty)) {
-                                       echo_char_raw('\a', tty);
-                                       process_echoes(tty);
-                               }
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
                                return;
                        }
                        /*
@@ -1320,10 +1295,8 @@ handle_newline:
        parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
        if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
                /* beep if no space */
-               if (L_ECHO(tty)) {
-                       echo_char_raw('\a', tty);
-                       process_echoes(tty);
-               }
+               if (L_ECHO(tty))
+                       process_output('\a', tty);
                return;
        }
        if (L_ECHO(tty)) {
@@ -1357,13 +1330,8 @@ handle_newline:
 
 static void n_tty_write_wakeup(struct tty_struct *tty)
 {
-       /* Write out any echoed characters that are still pending */
-       process_echoes(tty);
-
-       if (tty->fasync) {
-               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
                kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
-       }
 }
 
 /**
@@ -1568,11 +1536,11 @@ static void n_tty_close(struct tty_struct *tty)
 {
        n_tty_flush_buffer(tty);
        if (tty->read_buf) {
-               free_buf(tty->read_buf);
+               kfree(tty->read_buf);
                tty->read_buf = NULL;
        }
        if (tty->echo_buf) {
-               free_buf(tty->echo_buf);
+               kfree(tty->echo_buf);
                tty->echo_buf = NULL;
        }
 }
@@ -1594,17 +1562,16 @@ static int n_tty_open(struct tty_struct *tty)
 
        /* These are ugly. Currently a malloc failure here can panic */
        if (!tty->read_buf) {
-               tty->read_buf = alloc_buf();
+               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
                if (!tty->read_buf)
                        return -ENOMEM;
        }
        if (!tty->echo_buf) {
-               tty->echo_buf = alloc_buf();
+               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+
                if (!tty->echo_buf)
                        return -ENOMEM;
        }
-       memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
-       memset(tty->echo_buf, 0, N_TTY_BUF_SIZE);
        reset_buffer_flags(tty);
        tty->column = 0;
        n_tty_set_termios(tty, NULL);
@@ -1615,6 +1582,7 @@ static int n_tty_open(struct tty_struct *tty)
 
 static inline int input_available_p(struct tty_struct *tty, int amt)
 {
+       tty_flush_to_ldisc(tty);
        if (tty->icanon) {
                if (tty->canon_data)
                        return 1;
@@ -2022,6 +1990,8 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
 break_out:
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(&tty->write_wait, &wait);
+       if (b - buf != nr && tty->fasync)
+               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        return (b - buf) ? b - buf : retval;
 }