1*5894Swnj /* tty_pty.c 4.17 82/02/18 */ 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 */ 415574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 42*5894Swnj #define PF_REMOTE 0x20 /* remote and flow controlled input */ 432281Stoy 442281Stoy /*ARGSUSED*/ 452281Stoy ptsopen(dev, flag) 465396Sroot dev_t dev; 474484Swnj { 482281Stoy register struct tty *tp; 492281Stoy 504484Swnj if (minor(dev) >= NPTY) { 512281Stoy u.u_error = ENXIO; 522281Stoy return; 532281Stoy } 542281Stoy tp = &pt_tty[minor(dev)]; 555408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 562427Swnj ttychars(tp); /* Set up default chars */ 572427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 585408Swnj } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 592281Stoy u.u_error = EBUSY; 602281Stoy return; 612281Stoy } 624484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 635408Swnj tp->t_state |= TS_CARR_ON; 645408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 655408Swnj tp->t_state |= TS_WOPEN; 662281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 672281Stoy } 682281Stoy (*linesw[tp->t_line].l_open)(dev, tp); 692281Stoy } 702281Stoy 712281Stoy ptsclose(dev) 725396Sroot dev_t dev; 735408Swnj { 742281Stoy register struct tty *tp; 752281Stoy 762281Stoy tp = &pt_tty[minor(dev)]; 772281Stoy (*linesw[tp->t_line].l_close)(tp); 782281Stoy } 792281Stoy 802281Stoy ptsread(dev) 815396Sroot dev_t dev; 824484Swnj { 83*5894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 84*5894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 852281Stoy 86*5894Swnj again: 87*5894Swnj if (pti->pt_flags & PF_REMOTE) { 88*5894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 89*5894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 90*5894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 91*5894Swnj /* 92*5894Swnj (u.u_procp->p_flag&SDETACH) || 93*5894Swnj */ 94*5894Swnj u.u_procp->p_flag&SVFORK) 95*5894Swnj return; 96*5894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 97*5894Swnj sleep((caddr_t)&lbolt, TTIPRI); 985408Swnj } 99*5894Swnj if (tp->t_rawq.c_cc == 0) { 100*5894Swnj if (tp->t_state & TS_NBIO) { 101*5894Swnj u.u_error = EWOULDBLOCK; 102*5894Swnj return; 103*5894Swnj } 104*5894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 105*5894Swnj goto again; 106*5894Swnj } 107*5894Swnj while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0) 108*5894Swnj ; 109*5894Swnj if (tp->t_rawq.c_cc == 1) 110*5894Swnj (void) getc(&tp->t_rawq); 111*5894Swnj if (tp->t_rawq.c_cc) 112*5894Swnj return; 113*5894Swnj } else 114*5894Swnj if (tp->t_oproc) 115*5894Swnj (*linesw[tp->t_line].l_read)(tp); 116*5894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 117*5894Swnj if (pti->pt_selw) { 118*5894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 119*5894Swnj pti->pt_selw = 0; 120*5894Swnj pti->pt_flags &= ~PF_WCOLL; 1212281Stoy } 1222281Stoy } 1232281Stoy 1245408Swnj /* 1255408Swnj * Write to pseudo-tty. 1265408Swnj * Wakeups of controlling tty will happen 1275408Swnj * indirectly, when tty driver calls ptsstart. 1285408Swnj */ 1292281Stoy ptswrite(dev) 1305396Sroot dev_t dev; 1314484Swnj { 1322281Stoy register struct tty *tp; 1332281Stoy 1342281Stoy tp = &pt_tty[minor(dev)]; 1354484Swnj if (tp->t_oproc) 1362281Stoy (*linesw[tp->t_line].l_write)(tp); 1372281Stoy } 1382281Stoy 1395408Swnj /* 1405408Swnj * Start output on pseudo-tty. 1415408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1425408Swnj */ 1432281Stoy ptsstart(tp) 1444484Swnj struct tty *tp; 1454484Swnj { 1465574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1474484Swnj 1485408Swnj if (tp->t_state & TS_TTSTOP) 1492281Stoy return; 1505574Swnj if (pti->pt_flags & PF_STOPPED) { 1515574Swnj pti->pt_flags &= ~PF_STOPPED; 1525574Swnj pti->pt_send = TIOCPKT_START; 1535574Swnj } 1545430Swnj ptcwakeup(tp); 1555430Swnj } 1565430Swnj 1575430Swnj ptcwakeup(tp) 1585430Swnj struct tty *tp; 1595430Swnj { 1605430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1615430Swnj 1625427Swnj if (pti->pt_selr) { 1635427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1645427Swnj pti->pt_selr = 0; 1655427Swnj pti->pt_flags &= ~PF_RCOLL; 1664484Swnj } 1672281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1682281Stoy } 1692281Stoy 1702281Stoy /*ARGSUSED*/ 1712281Stoy ptcopen(dev, flag) 1724484Swnj dev_t dev; 1734484Swnj int flag; 1744484Swnj { 1752281Stoy register struct tty *tp; 1765427Swnj struct pt_ioctl *pti; 1772281Stoy 1784484Swnj if (minor(dev) >= NPTY) { 1792281Stoy u.u_error = ENXIO; 1802281Stoy return; 1812281Stoy } 1822281Stoy tp = &pt_tty[minor(dev)]; 1834484Swnj if (tp->t_oproc) { 1842281Stoy u.u_error = EIO; 1852281Stoy return; 1862281Stoy } 1874484Swnj tp->t_oproc = ptsstart; 1885408Swnj if (tp->t_state & TS_WOPEN) 1892281Stoy wakeup((caddr_t)&tp->t_rawq); 1905408Swnj tp->t_state |= TS_CARR_ON; 1915427Swnj pti = &pt_ioctl[minor(dev)]; 1925427Swnj pti->pt_flags = 0; 1935427Swnj pti->pt_send = 0; 1942281Stoy } 1952281Stoy 1962281Stoy ptcclose(dev) 1974484Swnj dev_t dev; 1984484Swnj { 1992281Stoy register struct tty *tp; 2002281Stoy 2012281Stoy tp = &pt_tty[minor(dev)]; 2025408Swnj if (tp->t_state & TS_ISOPEN) 2032281Stoy gsignal(tp->t_pgrp, SIGHUP); 2045408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2054484Swnj flushtty(tp, FREAD|FWRITE); 2064484Swnj tp->t_oproc = 0; /* mark closed */ 2072281Stoy } 2082281Stoy 2092281Stoy ptcread(dev) 2105427Swnj dev_t dev; 2114484Swnj { 2122281Stoy register struct tty *tp; 2135427Swnj struct pt_ioctl *pti; 2142281Stoy 2152281Stoy tp = &pt_tty[minor(dev)]; 2165408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2172281Stoy return; 2185427Swnj pti = &pt_ioctl[minor(dev)]; 2195427Swnj if (pti->pt_flags & PF_PKT) { 2205427Swnj if (pti->pt_send) { 2215427Swnj passc(pti->pt_send); 2225427Swnj pti->pt_send = 0; 2235427Swnj return; 2245427Swnj } 2255427Swnj passc(0); 2265427Swnj } 2275411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2285427Swnj if (pti->pt_flags&PF_NBIO) { 2295411Swnj u.u_error = EWOULDBLOCK; 2305411Swnj return; 2315411Swnj } 2322281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2335411Swnj } 2345408Swnj while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 2355408Swnj ; 2365408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2375408Swnj if (tp->t_state&TS_ASLEEP) { 2385408Swnj tp->t_state &= ~TS_ASLEEP; 2395408Swnj wakeup((caddr_t)&tp->t_outq); 2405408Swnj } 2415408Swnj if (tp->t_wsel) { 2425408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2435408Swnj tp->t_wsel = 0; 2445408Swnj tp->t_state &= ~TS_WCOLL; 2455408Swnj } 2462281Stoy } 2472281Stoy } 2482281Stoy 2495427Swnj ptsstop(tp, flush) 2505427Swnj register struct tty *tp; 2515427Swnj int flush; 2525427Swnj { 2535427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2545427Swnj 2555574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2565574Swnj if (flush == 0) { 2575574Swnj flush = TIOCPKT_STOP; 2585574Swnj pti->pt_flags |= PF_STOPPED; 2595574Swnj } else { 2605574Swnj pti->pt_flags &= ~PF_STOPPED; 2615574Swnj } 2625574Swnj pti->pt_send = flush; 2635430Swnj ptcwakeup(tp); 2645427Swnj } 2655427Swnj 2665408Swnj ptcselect(dev, rw) 2674484Swnj dev_t dev; 2685408Swnj int rw; 2694484Swnj { 2704484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 271*5894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2724484Swnj struct proc *p; 2735430Swnj int s; 2744484Swnj 2755408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2764484Swnj return (1); 2775430Swnj s = spl5(); 2785408Swnj switch (rw) { 2795408Swnj 2805408Swnj case FREAD: 2815430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2825430Swnj splx(s); 2835408Swnj return (1); 2845430Swnj } 2855427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2865427Swnj pti->pt_flags |= PF_RCOLL; 2875408Swnj else 2885427Swnj pti->pt_selr = u.u_procp; 2895430Swnj break; 2905408Swnj 2915408Swnj case FWRITE: 292*5894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 2935430Swnj splx(s); 2945408Swnj return (1); 2955430Swnj } 2965427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 2975427Swnj pti->pt_flags |= PF_WCOLL; 2985408Swnj else 2995427Swnj pti->pt_selw = u.u_procp; 3005430Swnj break; 3015408Swnj } 3025430Swnj splx(s); 3035430Swnj return (0); 3045396Sroot } 3054484Swnj 3062281Stoy ptcwrite(dev) 3075408Swnj dev_t dev; 3084484Swnj { 3092281Stoy register struct tty *tp; 3102281Stoy register char *cp, *ce; 3112281Stoy register int cc; 3122281Stoy char locbuf[BUFSIZ]; 3135408Swnj int cnt = 0; 314*5894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3152281Stoy 3162281Stoy tp = &pt_tty[minor(dev)]; 3175408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3182281Stoy return; 319*5894Swnj do { 3202281Stoy cc = MIN(u.u_count, BUFSIZ); 3212281Stoy cp = locbuf; 3222281Stoy iomove(cp, (unsigned)cc, B_WRITE); 3234484Swnj if (u.u_error) 3242281Stoy break; 3252281Stoy ce = cp + cc; 326*5894Swnj again: 327*5894Swnj if (pti->pt_flags & PF_REMOTE) { 328*5894Swnj if (tp->t_rawq.c_cc) { 329*5894Swnj if (pti->pt_flags & PF_NBIO) { 330*5894Swnj u.u_count += ce - cp; 331*5894Swnj u.u_error = EWOULDBLOCK; 332*5894Swnj return; 333*5894Swnj } 334*5894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 335*5894Swnj goto again; 336*5894Swnj } 337*5894Swnj b_to_q(cp, cc, &tp->t_rawq); 338*5894Swnj putc(0, &tp->t_rawq); 339*5894Swnj wakeup((caddr_t)&tp->t_rawq); 340*5894Swnj return; 341*5894Swnj } 3424484Swnj while (cp < ce) { 3434484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3442281Stoy wakeup((caddr_t)&tp->t_rawq); 3455408Swnj if (tp->t_state & TS_NBIO) { 3465408Swnj u.u_count += ce - cp; 3475408Swnj if (cnt == 0) 3485408Swnj u.u_error = EWOULDBLOCK; 3495408Swnj return; 3505408Swnj } 3512281Stoy /* Better than just flushing it! */ 3522281Stoy /* Wait for something to be read */ 3532281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 354*5894Swnj goto again; 3552281Stoy } 3564141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3575408Swnj cnt++; 3582281Stoy } 359*5894Swnj } while (u.u_count); 3602281Stoy } 3612281Stoy 3622281Stoy /*ARGSUSED*/ 3632281Stoy ptyioctl(dev, cmd, addr, flag) 3644484Swnj caddr_t addr; 3654484Swnj dev_t dev; 3664484Swnj { 3672281Stoy register struct tty *tp; 3682281Stoy 3692281Stoy tp = &pt_tty[minor(dev)]; 3704484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 3715411Swnj if (cdevsw[major(dev)].d_open == ptcopen) { 3725427Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3735427Swnj if (cmd == TIOCPKT) { 3745427Swnj int packet; 3755427Swnj if (copyin((caddr_t)addr, &packet, sizeof (packet))) { 3765427Swnj u.u_error = EFAULT; 3775427Swnj return; 3785427Swnj } 3795427Swnj if (packet) 3805427Swnj pti->pt_flags |= PF_PKT; 3815427Swnj else 3825427Swnj pti->pt_flags &= ~PF_PKT; 3835427Swnj return; 3845427Swnj } 385*5894Swnj if (cmd == TIOCREMOTE) { 386*5894Swnj int remote; 387*5894Swnj if (copyin((caddr_t)addr, &remote, sizeof (remote))) { 388*5894Swnj u.u_error = EFAULT; 389*5894Swnj return; 390*5894Swnj } 391*5894Swnj if (remote) 392*5894Swnj pti->pt_flags |= PF_REMOTE; 393*5894Swnj else 394*5894Swnj pti->pt_flags &= ~PF_REMOTE; 395*5894Swnj flushtty(tp, FREAD|FWRITE); 396*5894Swnj return; 397*5894Swnj } 3985411Swnj if (cmd == FIONBIO) { 3995411Swnj int nbio; 4005411Swnj if (copyin(addr, &nbio, sizeof (nbio))) { 4015411Swnj u.u_error = EFAULT; 4025411Swnj return; 4035411Swnj } 4045411Swnj if (nbio) 4055427Swnj pti->pt_flags |= PF_NBIO; 4065411Swnj else 4075427Swnj pti->pt_flags &= ~PF_NBIO; 4085411Swnj return; 4095411Swnj } 4105411Swnj if (cmd == TIOCSETP) 4115411Swnj while (getc(&tp->t_outq) >= 0); 4125411Swnj } 4134484Swnj if (ttioctl(tp, cmd, addr, dev) == 0) 4142281Stoy u.u_error = ENOTTY; 4152281Stoy } 4162313Stoy #endif 417