1*7475Ssam /* tty_pty.c 4.22 82/07/21 */ 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" 196239Sroot 20*7475Ssam #if NPTY == 1 215408Swnj #undef NPTY 226239Sroot #define NPTY 32 /* crude XXX */ 23*7475Ssam #endif 242281Stoy 252427Swnj #define BUFSIZ 100 /* Chunk size iomoved from user */ 264484Swnj 272281Stoy /* 284484Swnj * pts == /dev/tty[pP]? 294484Swnj * ptc == /dev/ptp[pP]? 302281Stoy */ 314484Swnj struct tty pt_tty[NPTY]; 324484Swnj struct pt_ioctl { 335427Swnj int pt_flags; 345427Swnj int pt_gensym; 355427Swnj struct proc *pt_selr, *pt_selw; 365427Swnj int pt_send; 374484Swnj } pt_ioctl[NPTY]; 382281Stoy 395427Swnj #define PF_RCOLL 0x01 405427Swnj #define PF_WCOLL 0x02 415427Swnj #define PF_NBIO 0x04 425427Swnj #define PF_PKT 0x08 /* packet mode */ 435574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 445894Swnj #define PF_REMOTE 0x20 /* remote and flow controlled input */ 456119Swnj #define PF_NOSTOP 0x40 462281Stoy 472281Stoy /*ARGSUSED*/ 482281Stoy ptsopen(dev, flag) 495396Sroot dev_t dev; 504484Swnj { 512281Stoy register struct tty *tp; 522281Stoy 534484Swnj if (minor(dev) >= NPTY) { 542281Stoy u.u_error = ENXIO; 552281Stoy return; 562281Stoy } 572281Stoy tp = &pt_tty[minor(dev)]; 585408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 592427Swnj ttychars(tp); /* Set up default chars */ 602427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 615408Swnj } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 622281Stoy u.u_error = EBUSY; 632281Stoy return; 642281Stoy } 654484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 665408Swnj tp->t_state |= TS_CARR_ON; 675408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 685408Swnj tp->t_state |= TS_WOPEN; 692281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 702281Stoy } 712281Stoy (*linesw[tp->t_line].l_open)(dev, tp); 722281Stoy } 732281Stoy 742281Stoy ptsclose(dev) 755396Sroot dev_t dev; 765408Swnj { 772281Stoy register struct tty *tp; 782281Stoy 792281Stoy tp = &pt_tty[minor(dev)]; 802281Stoy (*linesw[tp->t_line].l_close)(tp); 816299Swnj ttyclose(tp); 822281Stoy } 832281Stoy 842281Stoy ptsread(dev) 855396Sroot dev_t dev; 864484Swnj { 875894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 885894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 892281Stoy 905894Swnj again: 915894Swnj if (pti->pt_flags & PF_REMOTE) { 925894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 935894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 945894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 955894Swnj /* 965894Swnj (u.u_procp->p_flag&SDETACH) || 975894Swnj */ 985894Swnj u.u_procp->p_flag&SVFORK) 995894Swnj return; 1005894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1015894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1025408Swnj } 1035894Swnj if (tp->t_rawq.c_cc == 0) { 1045894Swnj if (tp->t_state & TS_NBIO) { 1055894Swnj u.u_error = EWOULDBLOCK; 1065894Swnj return; 1075894Swnj } 1085894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1095894Swnj goto again; 1105894Swnj } 1115894Swnj while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0) 1125894Swnj ; 1135894Swnj if (tp->t_rawq.c_cc == 1) 1145894Swnj (void) getc(&tp->t_rawq); 1155894Swnj if (tp->t_rawq.c_cc) 1165894Swnj return; 1175894Swnj } else 1185894Swnj if (tp->t_oproc) 1195894Swnj (*linesw[tp->t_line].l_read)(tp); 1205894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 1215894Swnj if (pti->pt_selw) { 1225894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 1235894Swnj pti->pt_selw = 0; 1245894Swnj pti->pt_flags &= ~PF_WCOLL; 1252281Stoy } 1262281Stoy } 1272281Stoy 1285408Swnj /* 1295408Swnj * Write to pseudo-tty. 1305408Swnj * Wakeups of controlling tty will happen 1315408Swnj * indirectly, when tty driver calls ptsstart. 1325408Swnj */ 1332281Stoy ptswrite(dev) 1345396Sroot dev_t dev; 1354484Swnj { 1362281Stoy register struct tty *tp; 1372281Stoy 1382281Stoy tp = &pt_tty[minor(dev)]; 1394484Swnj if (tp->t_oproc) 1402281Stoy (*linesw[tp->t_line].l_write)(tp); 1412281Stoy } 1422281Stoy 1435408Swnj /* 1445408Swnj * Start output on pseudo-tty. 1455408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1465408Swnj */ 1472281Stoy ptsstart(tp) 1484484Swnj struct tty *tp; 1494484Swnj { 1505574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1514484Swnj 1525408Swnj if (tp->t_state & TS_TTSTOP) 1532281Stoy return; 1545574Swnj if (pti->pt_flags & PF_STOPPED) { 1555574Swnj pti->pt_flags &= ~PF_STOPPED; 1565574Swnj pti->pt_send = TIOCPKT_START; 1575574Swnj } 1585430Swnj ptcwakeup(tp); 1595430Swnj } 1605430Swnj 1615430Swnj ptcwakeup(tp) 1625430Swnj struct tty *tp; 1635430Swnj { 1645430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1655430Swnj 1665427Swnj if (pti->pt_selr) { 1675427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1685427Swnj pti->pt_selr = 0; 1695427Swnj pti->pt_flags &= ~PF_RCOLL; 1704484Swnj } 1712281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1722281Stoy } 1732281Stoy 1742281Stoy /*ARGSUSED*/ 1752281Stoy ptcopen(dev, flag) 1764484Swnj dev_t dev; 1774484Swnj int flag; 1784484Swnj { 1792281Stoy register struct tty *tp; 1805427Swnj struct pt_ioctl *pti; 1812281Stoy 1824484Swnj if (minor(dev) >= NPTY) { 1832281Stoy u.u_error = ENXIO; 1842281Stoy return; 1852281Stoy } 1862281Stoy tp = &pt_tty[minor(dev)]; 1874484Swnj if (tp->t_oproc) { 1882281Stoy u.u_error = EIO; 1892281Stoy return; 1902281Stoy } 1914484Swnj tp->t_oproc = ptsstart; 1925408Swnj if (tp->t_state & TS_WOPEN) 1932281Stoy wakeup((caddr_t)&tp->t_rawq); 1945408Swnj tp->t_state |= TS_CARR_ON; 1955427Swnj pti = &pt_ioctl[minor(dev)]; 1965427Swnj pti->pt_flags = 0; 1975427Swnj pti->pt_send = 0; 1982281Stoy } 1992281Stoy 2002281Stoy ptcclose(dev) 2014484Swnj dev_t dev; 2024484Swnj { 2032281Stoy register struct tty *tp; 2042281Stoy 2052281Stoy tp = &pt_tty[minor(dev)]; 2065408Swnj if (tp->t_state & TS_ISOPEN) 2072281Stoy gsignal(tp->t_pgrp, SIGHUP); 2085408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2094484Swnj flushtty(tp, FREAD|FWRITE); 2104484Swnj tp->t_oproc = 0; /* mark closed */ 2112281Stoy } 2122281Stoy 2132281Stoy ptcread(dev) 2145427Swnj dev_t dev; 2154484Swnj { 2162281Stoy register struct tty *tp; 2175427Swnj struct pt_ioctl *pti; 2182281Stoy 2192281Stoy tp = &pt_tty[minor(dev)]; 2205408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2212281Stoy return; 2225427Swnj pti = &pt_ioctl[minor(dev)]; 2235427Swnj if (pti->pt_flags & PF_PKT) { 2245427Swnj if (pti->pt_send) { 2256158Ssam (void) passc(pti->pt_send); 2265427Swnj pti->pt_send = 0; 2275427Swnj return; 2285427Swnj } 2296158Ssam (void) passc(0); 2305427Swnj } 2315411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2325427Swnj if (pti->pt_flags&PF_NBIO) { 2335411Swnj u.u_error = EWOULDBLOCK; 2345411Swnj return; 2355411Swnj } 2362281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2375411Swnj } 2385408Swnj while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 2395408Swnj ; 2405408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2415408Swnj if (tp->t_state&TS_ASLEEP) { 2425408Swnj tp->t_state &= ~TS_ASLEEP; 2435408Swnj wakeup((caddr_t)&tp->t_outq); 2445408Swnj } 2455408Swnj if (tp->t_wsel) { 2465408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2475408Swnj tp->t_wsel = 0; 2485408Swnj tp->t_state &= ~TS_WCOLL; 2495408Swnj } 2502281Stoy } 2512281Stoy } 2522281Stoy 2535427Swnj ptsstop(tp, flush) 2545427Swnj register struct tty *tp; 2555427Swnj int flush; 2565427Swnj { 2575427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2585427Swnj 2595574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2605574Swnj if (flush == 0) { 2615574Swnj flush = TIOCPKT_STOP; 2625574Swnj pti->pt_flags |= PF_STOPPED; 2635574Swnj } else { 2645574Swnj pti->pt_flags &= ~PF_STOPPED; 2655574Swnj } 2666119Swnj pti->pt_send |= flush; 2675430Swnj ptcwakeup(tp); 2685427Swnj } 2695427Swnj 2705408Swnj ptcselect(dev, rw) 2714484Swnj dev_t dev; 2725408Swnj int rw; 2734484Swnj { 2744484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2755894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2764484Swnj struct proc *p; 2775430Swnj int s; 2784484Swnj 2795408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2804484Swnj return (1); 2815430Swnj s = spl5(); 2825408Swnj switch (rw) { 2835408Swnj 2845408Swnj case FREAD: 2855430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2865430Swnj splx(s); 2875408Swnj return (1); 2885430Swnj } 2895427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2905427Swnj pti->pt_flags |= PF_RCOLL; 2915408Swnj else 2925427Swnj pti->pt_selr = u.u_procp; 2935430Swnj break; 2945408Swnj 2955408Swnj case FWRITE: 2965894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 2975430Swnj splx(s); 2985408Swnj return (1); 2995430Swnj } 3005427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3015427Swnj pti->pt_flags |= PF_WCOLL; 3025408Swnj else 3035427Swnj pti->pt_selw = u.u_procp; 3045430Swnj break; 3055408Swnj } 3065430Swnj splx(s); 3075430Swnj return (0); 3085396Sroot } 3094484Swnj 3102281Stoy ptcwrite(dev) 3115408Swnj dev_t dev; 3124484Swnj { 3132281Stoy register struct tty *tp; 3142281Stoy register char *cp, *ce; 3152281Stoy register int cc; 3162281Stoy char locbuf[BUFSIZ]; 3175408Swnj int cnt = 0; 3185894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3192281Stoy 3202281Stoy tp = &pt_tty[minor(dev)]; 3215408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3222281Stoy return; 3235894Swnj do { 3242281Stoy cc = MIN(u.u_count, BUFSIZ); 3252281Stoy cp = locbuf; 3262281Stoy iomove(cp, (unsigned)cc, B_WRITE); 3274484Swnj if (u.u_error) 3282281Stoy break; 3292281Stoy ce = cp + cc; 3305894Swnj again: 3315894Swnj if (pti->pt_flags & PF_REMOTE) { 3325894Swnj if (tp->t_rawq.c_cc) { 3335894Swnj if (pti->pt_flags & PF_NBIO) { 3345894Swnj u.u_count += ce - cp; 3355894Swnj u.u_error = EWOULDBLOCK; 3365894Swnj return; 3375894Swnj } 3385894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3395894Swnj goto again; 3405894Swnj } 3416158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3426158Ssam (void) putc(0, &tp->t_rawq); 3435894Swnj wakeup((caddr_t)&tp->t_rawq); 3445894Swnj return; 3455894Swnj } 3464484Swnj while (cp < ce) { 3474484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3482281Stoy wakeup((caddr_t)&tp->t_rawq); 3495408Swnj if (tp->t_state & TS_NBIO) { 3505408Swnj u.u_count += ce - cp; 3515408Swnj if (cnt == 0) 3525408Swnj u.u_error = EWOULDBLOCK; 3535408Swnj return; 3545408Swnj } 3552281Stoy /* Better than just flushing it! */ 3562281Stoy /* Wait for something to be read */ 3572281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3585894Swnj goto again; 3592281Stoy } 3604141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3615408Swnj cnt++; 3622281Stoy } 3635894Swnj } while (u.u_count); 3642281Stoy } 3652281Stoy 3662281Stoy /*ARGSUSED*/ 3672281Stoy ptyioctl(dev, cmd, addr, flag) 3684484Swnj caddr_t addr; 3694484Swnj dev_t dev; 3704484Swnj { 3716119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 3726119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3732281Stoy 3744484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 3755411Swnj if (cdevsw[major(dev)].d_open == ptcopen) { 3765427Swnj if (cmd == TIOCPKT) { 3775427Swnj int packet; 3786158Ssam if (copyin((caddr_t)addr, (caddr_t)&packet, sizeof (packet))) { 3795427Swnj u.u_error = EFAULT; 3805427Swnj return; 3815427Swnj } 3825427Swnj if (packet) 3835427Swnj pti->pt_flags |= PF_PKT; 3845427Swnj else 3855427Swnj pti->pt_flags &= ~PF_PKT; 3865427Swnj return; 3875427Swnj } 3885894Swnj if (cmd == TIOCREMOTE) { 3895894Swnj int remote; 3906158Ssam if (copyin((caddr_t)addr, (caddr_t)&remote, sizeof (remote))) { 3915894Swnj u.u_error = EFAULT; 3925894Swnj return; 3935894Swnj } 3945894Swnj if (remote) 3955894Swnj pti->pt_flags |= PF_REMOTE; 3965894Swnj else 3975894Swnj pti->pt_flags &= ~PF_REMOTE; 3985894Swnj flushtty(tp, FREAD|FWRITE); 3995894Swnj return; 4005894Swnj } 4015411Swnj if (cmd == FIONBIO) { 4025411Swnj int nbio; 4036158Ssam if (copyin((caddr_t)addr, (caddr_t)&nbio, sizeof (nbio))) { 4045411Swnj u.u_error = EFAULT; 4055411Swnj return; 4065411Swnj } 4075411Swnj if (nbio) 4085427Swnj pti->pt_flags |= PF_NBIO; 4095411Swnj else 4105427Swnj pti->pt_flags &= ~PF_NBIO; 4115411Swnj return; 4125411Swnj } 4135411Swnj if (cmd == TIOCSETP) 4145411Swnj while (getc(&tp->t_outq) >= 0); 4155411Swnj } 4164484Swnj if (ttioctl(tp, cmd, addr, dev) == 0) 4172281Stoy u.u_error = ENOTTY; 4186119Swnj { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 4196119Swnj tp->t_un.t_chr.t_startc == ('q'&037)); 4206119Swnj if (pti->pt_flags & PF_NOSTOP) { 4216119Swnj if (stop) { 4226119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4236119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4246119Swnj pti->pt_flags &= ~PF_NOSTOP; 4256119Swnj ptcwakeup(tp); 4266119Swnj } 4276119Swnj } else { 4286119Swnj if (stop == 0) { 4296119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4306119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4316119Swnj pti->pt_flags |= PF_NOSTOP; 4326119Swnj ptcwakeup(tp); 4336119Swnj } 4346119Swnj } 4356119Swnj } 4362281Stoy } 4372313Stoy #endif 438