1*5430Swnj /* tty_pty.c 4.15 82/01/17 */ 22283Stoy 32281Stoy /* 42281Stoy * Pseudo-teletype Driver 52281Stoy * (Actually two drivers, requiring two entries in 'cdevsw') 62281Stoy */ 72314Stoy #include "pty.h" 82314Stoy 93206Swnj #if NPTY > 0 102281Stoy #include "../h/param.h" 112281Stoy #include "../h/systm.h" 122281Stoy #include "../h/tty.h" 132281Stoy #include "../h/dir.h" 142281Stoy #include "../h/user.h" 152281Stoy #include "../h/conf.h" 162281Stoy #include "../h/buf.h" 172427Swnj #include "../h/file.h" 184484Swnj #include "../h/proc.h" 195408Swnj #undef NPTY 202281Stoy 214484Swnj #define NPTY 16 224484Swnj 232427Swnj #define BUFSIZ 100 /* Chunk size iomoved from user */ 244484Swnj 252281Stoy /* 264484Swnj * pts == /dev/tty[pP]? 274484Swnj * ptc == /dev/ptp[pP]? 282281Stoy */ 294484Swnj struct tty pt_tty[NPTY]; 304484Swnj struct pt_ioctl { 315427Swnj int pt_flags; 325427Swnj int pt_gensym; 335427Swnj struct proc *pt_selr, *pt_selw; 345427Swnj int pt_send; 354484Swnj } pt_ioctl[NPTY]; 362281Stoy 375427Swnj #define PF_RCOLL 0x01 385427Swnj #define PF_WCOLL 0x02 395427Swnj #define PF_NBIO 0x04 405427Swnj #define PF_PKT 0x08 /* packet mode */ 415427Swnj #define PF_FLOWCTL 0x10 /* peers flow control mode */ 422281Stoy 432281Stoy /*ARGSUSED*/ 442281Stoy ptsopen(dev, flag) 455396Sroot dev_t dev; 464484Swnj { 472281Stoy register struct tty *tp; 482281Stoy 494484Swnj if (minor(dev) >= NPTY) { 502281Stoy u.u_error = ENXIO; 512281Stoy return; 522281Stoy } 532281Stoy tp = &pt_tty[minor(dev)]; 545408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 552427Swnj ttychars(tp); /* Set up default chars */ 562427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 575408Swnj } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 582281Stoy u.u_error = EBUSY; 592281Stoy return; 602281Stoy } 614484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 625408Swnj tp->t_state |= TS_CARR_ON; 635408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 645408Swnj tp->t_state |= TS_WOPEN; 652281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 662281Stoy } 672281Stoy (*linesw[tp->t_line].l_open)(dev, tp); 682281Stoy } 692281Stoy 702281Stoy ptsclose(dev) 715396Sroot dev_t dev; 725408Swnj { 732281Stoy register struct tty *tp; 742281Stoy 752281Stoy tp = &pt_tty[minor(dev)]; 762281Stoy (*linesw[tp->t_line].l_close)(tp); 772281Stoy } 782281Stoy 792281Stoy ptsread(dev) 805396Sroot dev_t dev; 814484Swnj { 824484Swnj register struct tty *tp; 835408Swnj register struct pt_ioctl *pti; 842281Stoy 852281Stoy tp = &pt_tty[minor(dev)]; 864484Swnj if (tp->t_oproc) { 872281Stoy (*linesw[tp->t_line].l_read)(tp); 882281Stoy wakeup((caddr_t)&tp->t_rawq.c_cf); 895408Swnj if (tp->t_rawq.c_cc < TTYHOG/2 && 905427Swnj (pti = &pt_ioctl[minor(tp->t_dev)])->pt_selw) { 915427Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 925427Swnj pti->pt_selw = 0; 935427Swnj pti->pt_flags &= ~PF_WCOLL; 945408Swnj } 952281Stoy } 962281Stoy } 972281Stoy 985408Swnj /* 995408Swnj * Write to pseudo-tty. 1005408Swnj * Wakeups of controlling tty will happen 1015408Swnj * indirectly, when tty driver calls ptsstart. 1025408Swnj */ 1032281Stoy ptswrite(dev) 1045396Sroot dev_t dev; 1054484Swnj { 1062281Stoy register struct tty *tp; 1072281Stoy 1082281Stoy tp = &pt_tty[minor(dev)]; 1094484Swnj if (tp->t_oproc) 1102281Stoy (*linesw[tp->t_line].l_write)(tp); 1112281Stoy } 1122281Stoy 1135408Swnj /* 1145408Swnj * Start output on pseudo-tty. 1155408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1165408Swnj */ 1172281Stoy ptsstart(tp) 1184484Swnj struct tty *tp; 1194484Swnj { 1204484Swnj 1215408Swnj if (tp->t_state & TS_TTSTOP) 1222281Stoy return; 123*5430Swnj ptcwakeup(tp); 124*5430Swnj } 125*5430Swnj 126*5430Swnj ptcwakeup(tp) 127*5430Swnj struct tty *tp; 128*5430Swnj { 129*5430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 130*5430Swnj 1315427Swnj if (pti->pt_selr) { 1325427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1335427Swnj pti->pt_selr = 0; 1345427Swnj pti->pt_flags &= ~PF_RCOLL; 1354484Swnj } 1362281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1372281Stoy } 1382281Stoy 1392281Stoy /*ARGSUSED*/ 1402281Stoy ptcopen(dev, flag) 1414484Swnj dev_t dev; 1424484Swnj int flag; 1434484Swnj { 1442281Stoy register struct tty *tp; 1455427Swnj struct pt_ioctl *pti; 1462281Stoy 1474484Swnj if (minor(dev) >= NPTY) { 1482281Stoy u.u_error = ENXIO; 1492281Stoy return; 1502281Stoy } 1512281Stoy tp = &pt_tty[minor(dev)]; 1524484Swnj if (tp->t_oproc) { 1532281Stoy u.u_error = EIO; 1542281Stoy return; 1552281Stoy } 1564484Swnj tp->t_oproc = ptsstart; 1575408Swnj if (tp->t_state & TS_WOPEN) 1582281Stoy wakeup((caddr_t)&tp->t_rawq); 1595408Swnj tp->t_state |= TS_CARR_ON; 1605427Swnj pti = &pt_ioctl[minor(dev)]; 1615427Swnj pti->pt_flags = 0; 1625427Swnj pti->pt_send = 0; 1632281Stoy } 1642281Stoy 1652281Stoy ptcclose(dev) 1664484Swnj dev_t dev; 1674484Swnj { 1682281Stoy register struct tty *tp; 1692281Stoy 1702281Stoy tp = &pt_tty[minor(dev)]; 1715408Swnj if (tp->t_state & TS_ISOPEN) 1722281Stoy gsignal(tp->t_pgrp, SIGHUP); 1735408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 1744484Swnj flushtty(tp, FREAD|FWRITE); 1754484Swnj tp->t_oproc = 0; /* mark closed */ 1762281Stoy } 1772281Stoy 1782281Stoy ptcread(dev) 1795427Swnj dev_t dev; 1804484Swnj { 1812281Stoy register struct tty *tp; 1825427Swnj struct pt_ioctl *pti; 1832281Stoy 1842281Stoy tp = &pt_tty[minor(dev)]; 1855408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 1862281Stoy return; 1875427Swnj pti = &pt_ioctl[minor(dev)]; 1885427Swnj if (pti->pt_flags & PF_PKT) { 1895427Swnj if (pti->pt_send) { 1905427Swnj passc(pti->pt_send); 1915427Swnj pti->pt_send = 0; 1925427Swnj return; 1935427Swnj } 1945427Swnj passc(0); 1955427Swnj } 1965411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 1975427Swnj if (pti->pt_flags&PF_NBIO) { 1985411Swnj u.u_error = EWOULDBLOCK; 1995411Swnj return; 2005411Swnj } 2012281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2025411Swnj } 2035408Swnj while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 2045408Swnj ; 2055408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2065408Swnj if (tp->t_state&TS_ASLEEP) { 2075408Swnj tp->t_state &= ~TS_ASLEEP; 2085408Swnj wakeup((caddr_t)&tp->t_outq); 2095408Swnj } 2105408Swnj if (tp->t_wsel) { 2115408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2125408Swnj tp->t_wsel = 0; 2135408Swnj tp->t_state &= ~TS_WCOLL; 2145408Swnj } 2152281Stoy } 2162281Stoy } 2172281Stoy 2185427Swnj ptsstop(tp, flush) 2195427Swnj register struct tty *tp; 2205427Swnj int flush; 2215427Swnj { 2225427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2235427Swnj 2245427Swnj if (flush == 0) 2255427Swnj return; 226*5430Swnj pti->pt_send |= flush; 227*5430Swnj ptcwakeup(tp); 2285427Swnj } 2295427Swnj 2305408Swnj ptcselect(dev, rw) 2314484Swnj dev_t dev; 2325408Swnj int rw; 2334484Swnj { 2344484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2354484Swnj struct pt_ioctl *pti; 2364484Swnj struct proc *p; 237*5430Swnj int s; 2384484Swnj 2395408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2404484Swnj return (1); 241*5430Swnj s = spl5(); 2425408Swnj switch (rw) { 2435408Swnj 2445408Swnj case FREAD: 245*5430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 246*5430Swnj splx(s); 2475408Swnj return (1); 248*5430Swnj } 2495408Swnj pti = &pt_ioctl[minor(dev)]; 2505427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2515427Swnj pti->pt_flags |= PF_RCOLL; 2525408Swnj else 2535427Swnj pti->pt_selr = u.u_procp; 254*5430Swnj break; 2555408Swnj 2565408Swnj case FWRITE: 257*5430Swnj if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) { 258*5430Swnj splx(s); 2595408Swnj return (1); 260*5430Swnj } 2615408Swnj pti = &pt_ioctl[minor(dev)]; 2625427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 2635427Swnj pti->pt_flags |= PF_WCOLL; 2645408Swnj else 2655427Swnj pti->pt_selw = u.u_procp; 266*5430Swnj break; 2675408Swnj } 268*5430Swnj splx(s); 269*5430Swnj return (0); 2705396Sroot } 2714484Swnj 2722281Stoy ptcwrite(dev) 2735408Swnj dev_t dev; 2744484Swnj { 2752281Stoy register struct tty *tp; 2762281Stoy register char *cp, *ce; 2772281Stoy register int cc; 2782281Stoy char locbuf[BUFSIZ]; 2795408Swnj int cnt = 0; 2802281Stoy 2812281Stoy tp = &pt_tty[minor(dev)]; 2825408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2832281Stoy return; 2844484Swnj while (u.u_count) { 2852281Stoy cc = MIN(u.u_count, BUFSIZ); 2862281Stoy cp = locbuf; 2872281Stoy iomove(cp, (unsigned)cc, B_WRITE); 2884484Swnj if (u.u_error) 2892281Stoy break; 2902281Stoy ce = cp + cc; 2914484Swnj while (cp < ce) { 2924484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 2932281Stoy wakeup((caddr_t)&tp->t_rawq); 2945408Swnj if (tp->t_state & TS_NBIO) { 2955408Swnj u.u_count += ce - cp; 2965408Swnj if (cnt == 0) 2975408Swnj u.u_error = EWOULDBLOCK; 2985408Swnj return; 2995408Swnj } 3002281Stoy /* Better than just flushing it! */ 3012281Stoy /* Wait for something to be read */ 3022281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3032281Stoy } 3044141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3055408Swnj cnt++; 3062281Stoy } 3072281Stoy } 3082281Stoy } 3092281Stoy 3102281Stoy /*ARGSUSED*/ 3112281Stoy ptyioctl(dev, cmd, addr, flag) 3124484Swnj caddr_t addr; 3134484Swnj dev_t dev; 3144484Swnj { 3152281Stoy register struct tty *tp; 3162281Stoy 3172281Stoy tp = &pt_tty[minor(dev)]; 3184484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 3195411Swnj if (cdevsw[major(dev)].d_open == ptcopen) { 3205427Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3215427Swnj if (cmd == TIOCPKT) { 3225427Swnj int packet; 3235427Swnj if (copyin((caddr_t)addr, &packet, sizeof (packet))) { 3245427Swnj u.u_error = EFAULT; 3255427Swnj return; 3265427Swnj } 3275427Swnj if (packet) 3285427Swnj pti->pt_flags |= PF_PKT; 3295427Swnj else 3305427Swnj pti->pt_flags &= ~PF_PKT; 3315427Swnj return; 3325427Swnj } 3335411Swnj if (cmd == FIONBIO) { 3345411Swnj int nbio; 3355411Swnj if (copyin(addr, &nbio, sizeof (nbio))) { 3365411Swnj u.u_error = EFAULT; 3375411Swnj return; 3385411Swnj } 3395411Swnj if (nbio) 3405427Swnj pti->pt_flags |= PF_NBIO; 3415411Swnj else 3425427Swnj pti->pt_flags &= ~PF_NBIO; 3435411Swnj return; 3445411Swnj } 3455411Swnj if (cmd == TIOCSETP) 3465411Swnj while (getc(&tp->t_outq) >= 0); 3475411Swnj } 3484484Swnj if (ttioctl(tp, cmd, addr, dev) == 0) 3492281Stoy u.u_error = ENOTTY; 3502281Stoy } 3512313Stoy #endif 352