include kernel.h for lbolt
[unix-history] / usr / src / sys / kern / tty_pty.c
index f64ea64..353893b 100644 (file)
@@ -1,4 +1,4 @@
-/*     tty_pty.c       4.12    82/01/14        */
+/*     tty_pty.c       4.25    82/09/12        */
 
 /*
  * Pseudo-teletype Driver
 
 /*
  * Pseudo-teletype Driver
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/conf.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/conf.h"
-#include "../h/buf.h"
 #include "../h/file.h"
 #include "../h/proc.h"
 #include "../h/file.h"
 #include "../h/proc.h"
-#undef NPTY
+#include "../h/uio.h"
+#include "../h/kernel.h"
 
 
-#define NPTY 16
+#if NPTY == 1
+#undef NPTY
+#define        NPTY    32              /* crude XXX */
+#endif
 
 #define BUFSIZ 100             /* Chunk size iomoved from user */
 
 
 #define BUFSIZ 100             /* Chunk size iomoved from user */
 
  */
 struct tty pt_tty[NPTY];
 struct pt_ioctl {
  */
 struct tty pt_tty[NPTY];
 struct pt_ioctl {
-       int     pti_flags;
-       struct  clist pti_ioctl, pti_ioans;
-       int     pti_gensym;
-       struct  proc *pti_selr, *pti_selw;
+       int     pt_flags;
+       int     pt_gensym;
+       struct  proc *pt_selr, *pt_selw;
+       int     pt_send;
 } pt_ioctl[NPTY];
 
 } pt_ioctl[NPTY];
 
-#define        PTCRCOLL        0x01
-#define        PTCWCOLL        0x02
+#define        PF_RCOLL        0x01
+#define        PF_WCOLL        0x02
+#define        PF_NBIO         0x04
+#define        PF_PKT          0x08            /* packet mode */
+#define        PF_STOPPED      0x10            /* user told stopped */
+#define        PF_REMOTE       0x20            /* remote and flow controlled input */
+#define        PF_NOSTOP       0x40
 
 /*ARGSUSED*/
 ptsopen(dev, flag)
 
 /*ARGSUSED*/
 ptsopen(dev, flag)
@@ -71,24 +79,54 @@ ptsclose(dev)
 
        tp = &pt_tty[minor(dev)];
        (*linesw[tp->t_line].l_close)(tp);
 
        tp = &pt_tty[minor(dev)];
        (*linesw[tp->t_line].l_close)(tp);
+       ttyclose(tp);
 }
 
 }
 
-ptsread(dev)
+ptsread(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
 {
-       register struct tty *tp;
-       register struct pt_ioctl *pti;
+       register struct tty *tp = &pt_tty[minor(dev)];
+       register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
 
 
-       tp = &pt_tty[minor(dev)];
-       if (tp->t_oproc) {
-               (*linesw[tp->t_line].l_read)(tp);
-               wakeup((caddr_t)&tp->t_rawq.c_cf);
-               if (tp->t_rawq.c_cc < TTYHOG/2 &&
-                   (pti = &pt_ioctl[minor(tp->t_dev)])->pti_selw) {
-                       selwakeup(pti->pti_selw, pti->pti_flags & PTCWCOLL);
-                       pti->pti_selw = 0;
-                       pti->pti_flags &= ~PTCWCOLL;
+again:
+       if (pti->pt_flags & PF_REMOTE) {
+               while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
+                       if (u.u_signal[SIGTTIN] == SIG_IGN ||
+                           u.u_signal[SIGTTIN] == SIG_HOLD ||
+       /*
+                           (u.u_procp->p_flag&SDETACH) ||
+       */
+                           u.u_procp->p_flag&SVFORK)
+                               return;
+                       gsignal(u.u_procp->p_pgrp, SIGTTIN);
+                       sleep((caddr_t)&lbolt, TTIPRI);
                }
                }
+               if (tp->t_rawq.c_cc == 0) {
+                       if (tp->t_state & TS_NBIO) {
+                               u.u_error = EWOULDBLOCK;
+                               return;
+                       }
+                       sleep((caddr_t)&tp->t_rawq, TTIPRI);
+                       goto again;
+               }
+               while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
+                       if (ureadc(getc(&tp->t_rawq), uio) < 0) {
+                               u.u_error = EFAULT;
+                               break;
+                       }
+               if (tp->t_rawq.c_cc == 1)
+                       (void) getc(&tp->t_rawq);
+               if (tp->t_rawq.c_cc)
+                       return;
+       } else
+               if (tp->t_oproc)
+                       (*linesw[tp->t_line].l_read)(tp, uio);
+       wakeup((caddr_t)&tp->t_rawq.c_cf);
+       if (pti->pt_selw) {
+               selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
+               pti->pt_selw = 0;
+               pti->pt_flags &= ~PF_WCOLL;
        }
 }
 
        }
 }
 
@@ -97,14 +135,15 @@ ptsread(dev)
  * Wakeups of controlling tty will happen
  * indirectly, when tty driver calls ptsstart.
  */
  * Wakeups of controlling tty will happen
  * indirectly, when tty driver calls ptsstart.
  */
-ptswrite(dev)
+ptswrite(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        register struct tty *tp;
 
        tp = &pt_tty[minor(dev)];
        if (tp->t_oproc)
 {
        register struct tty *tp;
 
        tp = &pt_tty[minor(dev)];
        if (tp->t_oproc)
-               (*linesw[tp->t_line].l_write)(tp);
+               (*linesw[tp->t_line].l_write)(tp, uio);
 }
 
 /*
 }
 
 /*
@@ -114,14 +153,26 @@ ptswrite(dev)
 ptsstart(tp)
        struct tty *tp;
 {
 ptsstart(tp)
        struct tty *tp;
 {
-       struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
+       register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
 
        if (tp->t_state & TS_TTSTOP)
                return;
 
        if (tp->t_state & TS_TTSTOP)
                return;
-       if (pti->pti_selr) {
-               selwakeup(pti->pti_selr, pti->pti_flags & PTCRCOLL);
-               pti->pti_selr = 0;
-               pti->pti_flags &= ~PTCRCOLL;
+       if (pti->pt_flags & PF_STOPPED) {
+               pti->pt_flags &= ~PF_STOPPED;
+               pti->pt_send = TIOCPKT_START;
+       }
+       ptcwakeup(tp);
+}
+
+ptcwakeup(tp)
+       struct tty *tp;
+{
+       struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
+
+       if (pti->pt_selr) {
+               selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
+               pti->pt_selr = 0;
+               pti->pt_flags &= ~PF_RCOLL;
        }
        wakeup((caddr_t)&tp->t_outq.c_cf);
 }
        }
        wakeup((caddr_t)&tp->t_outq.c_cf);
 }
@@ -132,6 +183,7 @@ ptcopen(dev, flag)
        int flag;
 {
        register struct tty *tp;
        int flag;
 {
        register struct tty *tp;
+       struct pt_ioctl *pti;
 
        if (minor(dev) >= NPTY) {
                u.u_error = ENXIO;
 
        if (minor(dev) >= NPTY) {
                u.u_error = ENXIO;
@@ -146,6 +198,9 @@ ptcopen(dev, flag)
        if (tp->t_state & TS_WOPEN)
                wakeup((caddr_t)&tp->t_rawq);
        tp->t_state |= TS_CARR_ON;
        if (tp->t_state & TS_WOPEN)
                wakeup((caddr_t)&tp->t_rawq);
        tp->t_state |= TS_CARR_ON;
+       pti = &pt_ioctl[minor(dev)];
+       pti->pt_flags = 0;
+       pti->pt_send = 0;
 }
 
 ptcclose(dev)
 }
 
 ptcclose(dev)
@@ -161,18 +216,37 @@ ptcclose(dev)
        tp->t_oproc = 0;                /* mark closed */
 }
 
        tp->t_oproc = 0;                /* mark closed */
 }
 
-ptcread(dev)
-dev_t dev;
+ptcread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
 {
        register struct tty *tp;
 {
        register struct tty *tp;
+       struct pt_ioctl *pti;
 
        tp = &pt_tty[minor(dev)];
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
                return;
 
        tp = &pt_tty[minor(dev)];
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
                return;
-       while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP))
+       pti = &pt_ioctl[minor(dev)];
+       if (pti->pt_flags & PF_PKT) {
+               if (pti->pt_send) {
+                       (void) ureadc(pti->pt_send, uio);
+                       pti->pt_send = 0;
+                       return;
+               }
+               (void) ureadc(0, uio);
+       }
+       while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
+               if (pti->pt_flags&PF_NBIO) {
+                       u.u_error = EWOULDBLOCK;
+                       return;
+               }
                sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
                sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
-       while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
-               ;
+       }
+       while (tp->t_outq.c_cc && uio->uio_resid > 0)
+               if (ureadc(getc(&tp->t_outq), uio) < 0) {
+                       u.u_error = EFAULT;
+                       break;
+               }
        if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
                if (tp->t_state&TS_ASLEEP) {
                        tp->t_state &= ~TS_ASLEEP;
        if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
                if (tp->t_state&TS_ASLEEP) {
                        tp->t_state &= ~TS_ASLEEP;
@@ -186,63 +260,123 @@ dev_t dev;
        }
 }
 
        }
 }
 
+ptsstop(tp, flush)
+       register struct tty *tp;
+       int flush;
+{
+       struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
+
+       /* note: FLUSHREAD and FLUSHWRITE already ok */
+       if (flush == 0) {
+               flush = TIOCPKT_STOP;
+               pti->pt_flags |= PF_STOPPED;
+       } else {
+               pti->pt_flags &= ~PF_STOPPED;
+       }
+       pti->pt_send |= flush;
+       ptcwakeup(tp);
+}
+
 ptcselect(dev, rw)
        dev_t dev;
        int rw;
 {
        register struct tty *tp = &pt_tty[minor(dev)];
 ptcselect(dev, rw)
        dev_t dev;
        int rw;
 {
        register struct tty *tp = &pt_tty[minor(dev)];
-       struct pt_ioctl *pti;
+       struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
        struct proc *p;
        struct proc *p;
+       int s;
 
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
                return (1);
 
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
                return (1);
+       s = spl5();
        switch (rw) {
 
        case FREAD:
        switch (rw) {
 
        case FREAD:
-               if (tp->t_outq.c_cc)
+               if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
+                       splx(s);
                        return (1);
                        return (1);
-               pti = &pt_ioctl[minor(dev)];
-               if ((p = pti->pti_selr) && p->p_wchan == (caddr_t)&selwait)
-                       pti->pti_flags |= PTCRCOLL;
+               }
+               if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
+                       pti->pt_flags |= PF_RCOLL;
                else
                else
-                       pti->pti_selr = u.u_procp;
-               return (0);
+                       pti->pt_selr = u.u_procp;
+               break;
 
        case FWRITE:
 
        case FWRITE:
-               if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2)
+               if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
+                       splx(s);
                        return (1);
                        return (1);
-               pti = &pt_ioctl[minor(dev)];
-               if ((p = pti->pti_selw) && p->p_wchan == (caddr_t)&selwait)
-                       pti->pti_flags |= PTCWCOLL;
+               }
+               if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
+                       pti->pt_flags |= PF_WCOLL;
                else
                else
-                       pti->pti_selw = u.u_procp;
+                       pti->pt_selw = u.u_procp;
+               break;
        }
        }
+       splx(s);
+       return (0);
 }
 
 }
 
-ptcwrite(dev)
+ptcwrite(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        register struct tty *tp;
        register char *cp, *ce;
        register int cc;
        char locbuf[BUFSIZ];
        int cnt = 0;
 {
        register struct tty *tp;
        register char *cp, *ce;
        register int cc;
        char locbuf[BUFSIZ];
        int cnt = 0;
+       struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
 
        tp = &pt_tty[minor(dev)];
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
                return;
 
        tp = &pt_tty[minor(dev)];
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
                return;
-       while (u.u_count) {
-               cc = MIN(u.u_count, BUFSIZ);
+       do {
+               register struct iovec *iov;
+
+               if (uio->uio_iovcnt == 0)
+                       break;
+               iov = uio->uio_iov;
+               if (iov->iov_len == 0) {
+                       uio->uio_iovcnt--;      
+                       uio->uio_iov++;
+                       if (uio->uio_iovcnt < 0)
+                               panic("ptcwrite");
+                       continue;
+               }
+               cc = MIN(iov->iov_len, BUFSIZ);
                cp = locbuf;
                cp = locbuf;
-               iomove(cp, (unsigned)cc, B_WRITE);
+               u.u_error = uiomove(cp, cc, UIO_WRITE, uio);
                if (u.u_error)
                        break;
                ce = cp + cc;
                if (u.u_error)
                        break;
                ce = cp + cc;
+again:
+               if (pti->pt_flags & PF_REMOTE) {
+                       if (tp->t_rawq.c_cc) {
+                               if (pti->pt_flags & PF_NBIO) {
+                                       iov->iov_base -= ce - cp;
+                                       iov->iov_len += ce - cp;
+                                       uio->uio_resid += ce - cp;
+                                       uio->uio_offset -= ce - cp;
+                                       u.u_error = EWOULDBLOCK;
+                                       return;
+                               }
+                               sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
+                               goto again;
+                       }
+                       (void) b_to_q(cp, cc, &tp->t_rawq);
+                       (void) putc(0, &tp->t_rawq);
+                       wakeup((caddr_t)&tp->t_rawq);
+                       return;
+               }
                while (cp < ce) {
                        while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
                                wakeup((caddr_t)&tp->t_rawq);
                                if (tp->t_state & TS_NBIO) {
                while (cp < ce) {
                        while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
                                wakeup((caddr_t)&tp->t_rawq);
                                if (tp->t_state & TS_NBIO) {
-                                       u.u_count += ce - cp;
+                                       iov->iov_base -= ce - cp;
+                                       iov->iov_len += ce - cp;
+                                       uio->uio_resid += ce - cp;
+                                       uio->uio_offset -= ce - cp;
                                        if (cnt == 0)
                                                u.u_error = EWOULDBLOCK;
                                        return;
                                        if (cnt == 0)
                                                u.u_error = EWOULDBLOCK;
                                        return;
@@ -250,25 +384,72 @@ ptcwrite(dev)
                                /* Better than just flushing it! */
                                /* Wait for something to be read */
                                sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
                                /* Better than just flushing it! */
                                /* Wait for something to be read */
                                sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
+                               goto again;
                        }
                        (*linesw[tp->t_line].l_rint)(*cp++, tp);
                        cnt++;
                }
                        }
                        (*linesw[tp->t_line].l_rint)(*cp++, tp);
                        cnt++;
                }
-       }
+       } while (uio->uio_resid);
 }
 
 /*ARGSUSED*/
 }
 
 /*ARGSUSED*/
-ptyioctl(dev, cmd, addr, flag)
-       caddr_t addr;
+ptyioctl(dev, cmd, data, flag)
+       caddr_t data;
        dev_t dev;
 {
        dev_t dev;
 {
-       register struct tty *tp;
+       register struct tty *tp = &pt_tty[minor(dev)];
+       register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
 
 
-       tp = &pt_tty[minor(dev)];
        /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
        /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
-       if (cdevsw[major(dev)].d_open == ptcopen && cmd == TIOCSETP)
-               while (getc(&tp->t_outq) >= 0);
-       if (ttioctl(tp, cmd, addr, dev) == 0)
+       if (cdevsw[major(dev)].d_open == ptcopen)
+               switch (cmd) {
+
+               case TIOCPKT:
+                       if (*(int *)data)
+                               pti->pt_flags |= PF_PKT;
+                       else
+                               pti->pt_flags &= ~PF_PKT;
+                       return;
+
+               case TIOCREMOTE:
+                       if (*(int *)data)
+                               pti->pt_flags |= PF_REMOTE;
+                       else
+                               pti->pt_flags &= ~PF_REMOTE;
+                       flushtty(tp, FREAD|FWRITE);
+                       return;
+
+               case FIONBIO:
+                       if (*(int *)data)
+                               pti->pt_flags |= PF_NBIO;
+                       else
+                               pti->pt_flags &= ~PF_NBIO;
+                       return;
+
+               case TIOCSETP:
+                       while (getc(&tp->t_outq) >= 0)
+                               ;
+                       break;
+               }
+       if (ttioctl(tp, cmd, data, dev) == 0)
                u.u_error = ENOTTY;
                u.u_error = ENOTTY;
+       { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
+                     tp->t_un.t_chr.t_startc == ('q'&037));
+       if (pti->pt_flags & PF_NOSTOP) {
+               if (stop) {
+                       pti->pt_send &= TIOCPKT_NOSTOP;
+                       pti->pt_send |= TIOCPKT_DOSTOP;
+                       pti->pt_flags &= ~PF_NOSTOP;
+                       ptcwakeup(tp);
+               }
+       } else {
+               if (stop == 0) {
+                       pti->pt_send &= ~TIOCPKT_DOSTOP;
+                       pti->pt_send |= TIOCPKT_NOSTOP;
+                       pti->pt_flags |= PF_NOSTOP;
+                       ptcwakeup(tp);
+               }
+       }
+       }
 }
 #endif
 }
 #endif