1*5427Swnj /* tty_pty.c 4.14 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 { 31*5427Swnj int pt_flags; 32*5427Swnj int pt_gensym; 33*5427Swnj struct proc *pt_selr, *pt_selw; 34*5427Swnj int pt_send; 354484Swnj } pt_ioctl[NPTY]; 362281Stoy 37*5427Swnj #define PF_RCOLL 0x01 38*5427Swnj #define PF_WCOLL 0x02 39*5427Swnj #define PF_NBIO 0x04 40*5427Swnj #define PF_PKT 0x08 /* packet mode */ 41*5427Swnj #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 && 90*5427Swnj (pti = &pt_ioctl[minor(tp->t_dev)])->pt_selw) { 91*5427Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 92*5427Swnj pti->pt_selw = 0; 93*5427Swnj 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 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1214484Swnj 1225408Swnj if (tp->t_state & TS_TTSTOP) 1232281Stoy return; 124*5427Swnj if (pti->pt_selr) { 125*5427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 126*5427Swnj pti->pt_selr = 0; 127*5427Swnj pti->pt_flags &= ~PF_RCOLL; 1284484Swnj } 1292281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1302281Stoy } 1312281Stoy 1322281Stoy /*ARGSUSED*/ 1332281Stoy ptcopen(dev, flag) 1344484Swnj dev_t dev; 1354484Swnj int flag; 1364484Swnj { 1372281Stoy register struct tty *tp; 138*5427Swnj struct pt_ioctl *pti; 1392281Stoy 1404484Swnj if (minor(dev) >= NPTY) { 1412281Stoy u.u_error = ENXIO; 1422281Stoy return; 1432281Stoy } 1442281Stoy tp = &pt_tty[minor(dev)]; 1454484Swnj if (tp->t_oproc) { 1462281Stoy u.u_error = EIO; 1472281Stoy return; 1482281Stoy } 1494484Swnj tp->t_oproc = ptsstart; 1505408Swnj if (tp->t_state & TS_WOPEN) 1512281Stoy wakeup((caddr_t)&tp->t_rawq); 1525408Swnj tp->t_state |= TS_CARR_ON; 153*5427Swnj pti = &pt_ioctl[minor(dev)]; 154*5427Swnj pti->pt_flags = 0; 155*5427Swnj pti->pt_send = 0; 1562281Stoy } 1572281Stoy 1582281Stoy ptcclose(dev) 1594484Swnj dev_t dev; 1604484Swnj { 1612281Stoy register struct tty *tp; 1622281Stoy 1632281Stoy tp = &pt_tty[minor(dev)]; 1645408Swnj if (tp->t_state & TS_ISOPEN) 1652281Stoy gsignal(tp->t_pgrp, SIGHUP); 1665408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 1674484Swnj flushtty(tp, FREAD|FWRITE); 1684484Swnj tp->t_oproc = 0; /* mark closed */ 1692281Stoy } 1702281Stoy 1712281Stoy ptcread(dev) 172*5427Swnj dev_t dev; 1734484Swnj { 1742281Stoy register struct tty *tp; 175*5427Swnj struct pt_ioctl *pti; 1762281Stoy 1772281Stoy tp = &pt_tty[minor(dev)]; 1785408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 1792281Stoy return; 180*5427Swnj pti = &pt_ioctl[minor(dev)]; 181*5427Swnj if (pti->pt_flags & PF_PKT) { 182*5427Swnj if (pti->pt_send) { 183*5427Swnj passc(pti->pt_send); 184*5427Swnj pti->pt_send = 0; 185*5427Swnj return; 186*5427Swnj } 187*5427Swnj passc(0); 188*5427Swnj } 1895411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 190*5427Swnj if (pti->pt_flags&PF_NBIO) { 1915411Swnj u.u_error = EWOULDBLOCK; 1925411Swnj return; 1935411Swnj } 1942281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 1955411Swnj } 1965408Swnj while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 1975408Swnj ; 1985408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 1995408Swnj if (tp->t_state&TS_ASLEEP) { 2005408Swnj tp->t_state &= ~TS_ASLEEP; 2015408Swnj wakeup((caddr_t)&tp->t_outq); 2025408Swnj } 2035408Swnj if (tp->t_wsel) { 2045408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2055408Swnj tp->t_wsel = 0; 2065408Swnj tp->t_state &= ~TS_WCOLL; 2075408Swnj } 2082281Stoy } 2092281Stoy } 2102281Stoy 211*5427Swnj ptsstop(tp, flush) 212*5427Swnj register struct tty *tp; 213*5427Swnj int flush; 214*5427Swnj { 215*5427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 216*5427Swnj 217*5427Swnj if (flush == 0) 218*5427Swnj return; 219*5427Swnj pti->pt_send |= TIOCPKT_FLUSH; 220*5427Swnj ptsstart(tp); 221*5427Swnj } 222*5427Swnj 2235408Swnj ptcselect(dev, rw) 2244484Swnj dev_t dev; 2255408Swnj int rw; 2264484Swnj { 2274484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2284484Swnj struct pt_ioctl *pti; 2294484Swnj struct proc *p; 2304484Swnj 2315408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2324484Swnj return (1); 2335408Swnj switch (rw) { 2345408Swnj 2355408Swnj case FREAD: 2365408Swnj if (tp->t_outq.c_cc) 2375408Swnj return (1); 2385408Swnj pti = &pt_ioctl[minor(dev)]; 239*5427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 240*5427Swnj pti->pt_flags |= PF_RCOLL; 2415408Swnj else 242*5427Swnj pti->pt_selr = u.u_procp; 2435408Swnj return (0); 2445408Swnj 2455408Swnj case FWRITE: 2465408Swnj if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) 2475408Swnj return (1); 2485408Swnj pti = &pt_ioctl[minor(dev)]; 249*5427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 250*5427Swnj pti->pt_flags |= PF_WCOLL; 2515408Swnj else 252*5427Swnj pti->pt_selw = u.u_procp; 2535408Swnj } 2545396Sroot } 2554484Swnj 2562281Stoy ptcwrite(dev) 2575408Swnj dev_t dev; 2584484Swnj { 2592281Stoy register struct tty *tp; 2602281Stoy register char *cp, *ce; 2612281Stoy register int cc; 2622281Stoy char locbuf[BUFSIZ]; 2635408Swnj int cnt = 0; 2642281Stoy 2652281Stoy tp = &pt_tty[minor(dev)]; 2665408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2672281Stoy return; 2684484Swnj while (u.u_count) { 2692281Stoy cc = MIN(u.u_count, BUFSIZ); 2702281Stoy cp = locbuf; 2712281Stoy iomove(cp, (unsigned)cc, B_WRITE); 2724484Swnj if (u.u_error) 2732281Stoy break; 2742281Stoy ce = cp + cc; 2754484Swnj while (cp < ce) { 2764484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 2772281Stoy wakeup((caddr_t)&tp->t_rawq); 2785408Swnj if (tp->t_state & TS_NBIO) { 2795408Swnj u.u_count += ce - cp; 2805408Swnj if (cnt == 0) 2815408Swnj u.u_error = EWOULDBLOCK; 2825408Swnj return; 2835408Swnj } 2842281Stoy /* Better than just flushing it! */ 2852281Stoy /* Wait for something to be read */ 2862281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 2872281Stoy } 2884141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 2895408Swnj cnt++; 2902281Stoy } 2912281Stoy } 2922281Stoy } 2932281Stoy 2942281Stoy /*ARGSUSED*/ 2952281Stoy ptyioctl(dev, cmd, addr, flag) 2964484Swnj caddr_t addr; 2974484Swnj dev_t dev; 2984484Swnj { 2992281Stoy register struct tty *tp; 3002281Stoy 3012281Stoy tp = &pt_tty[minor(dev)]; 3024484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 3035411Swnj if (cdevsw[major(dev)].d_open == ptcopen) { 304*5427Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 305*5427Swnj if (cmd == TIOCPKT) { 306*5427Swnj int packet; 307*5427Swnj if (copyin((caddr_t)addr, &packet, sizeof (packet))) { 308*5427Swnj u.u_error = EFAULT; 309*5427Swnj return; 310*5427Swnj } 311*5427Swnj if (packet) 312*5427Swnj pti->pt_flags |= PF_PKT; 313*5427Swnj else 314*5427Swnj pti->pt_flags &= ~PF_PKT; 315*5427Swnj return; 316*5427Swnj } 3175411Swnj if (cmd == FIONBIO) { 3185411Swnj int nbio; 3195411Swnj if (copyin(addr, &nbio, sizeof (nbio))) { 3205411Swnj u.u_error = EFAULT; 3215411Swnj return; 3225411Swnj } 3235411Swnj if (nbio) 324*5427Swnj pti->pt_flags |= PF_NBIO; 3255411Swnj else 326*5427Swnj pti->pt_flags &= ~PF_NBIO; 3275411Swnj return; 3285411Swnj } 3295411Swnj if (cmd == TIOCSETP) 3305411Swnj while (getc(&tp->t_outq) >= 0); 3315411Swnj } 3324484Swnj if (ttioctl(tp, cmd, addr, dev) == 0) 3332281Stoy u.u_error = ENOTTY; 3342281Stoy } 3352313Stoy #endif 336