This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / char / pty.c
index a473864..9826bbd 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <linux/bitops.h>
+#include <asm/bitops.h>
 #include <linux/devpts_fs.h>
 
 /* These are global because they are accessed in tty_io.c */
@@ -55,9 +55,9 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
        if (!tty->link)
                return;
        tty->link->packet = 0;
-       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
        wake_up_interruptible(&tty->link->read_wait);
        wake_up_interruptible(&tty->link->write_wait);
+       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
        if (tty->driver->subtype == PTY_TYPE_MASTER) {
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
@@ -103,18 +103,51 @@ static void pty_unthrottle(struct tty_struct * tty)
  * not our partners. We can't just take the other one blindly without
  * risking deadlocks.  There is also the small matter of TTY_DONT_FLIP
  */
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct * tty, int from_user,
+                      const unsigned char *buf, int count)
 {
        struct tty_struct *to = tty->link;
-       int     c;
+       int     c=0, n, room;
+       char    *temp_buffer;
 
        if (!to || tty->stopped)
                return 0;
 
-       c = to->ldisc.receive_room(to);
-       if (c > count)
-               c = count;
-       to->ldisc.receive_buf(to, buf, NULL, c);
+       if (from_user) {
+               down(&tty->flip.pty_sem);
+               temp_buffer = &tty->flip.char_buf[0];
+               while (count > 0) {
+                       /* check space so we don't copy needlessly */ 
+                       n = to->ldisc.receive_room(to);
+                       if (n > count)
+                               n = count;
+                       if (!n) break;
+
+                       n  = min(n, PTY_BUF_SIZE);
+                       n -= copy_from_user(temp_buffer, buf, n);
+                       if (!n) {
+                               if (!c)
+                                       c = -EFAULT;
+                               break;
+                       }
+
+                       /* check again in case the buffer filled up */
+                       room = to->ldisc.receive_room(to);
+                       if (n > room)
+                               n = room;
+                       if (!n) break;
+                       buf   += n; 
+                       c     += n;
+                       count -= n;
+                       to->ldisc.receive_buf(to, temp_buffer, NULL, n);
+               }
+               up(&tty->flip.pty_sem);
+       } else {
+               c = to->ldisc.receive_room(to);
+               if (c > count)
+                       c = count;
+               to->ldisc.receive_buf(to, buf, NULL, c);
+       }
        
        return c;
 }