1*5574Swnj /* tty_pty.c 4.16 82/01/19 */ 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 */ 41*5574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 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 { 120*5574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1214484Swnj 1225408Swnj if (tp->t_state & TS_TTSTOP) 1232281Stoy return; 124*5574Swnj if (pti->pt_flags & PF_STOPPED) { 125*5574Swnj pti->pt_flags &= ~PF_STOPPED; 126*5574Swnj pti->pt_send = TIOCPKT_START; 127*5574Swnj } 1285430Swnj ptcwakeup(tp); 1295430Swnj } 1305430Swnj 1315430Swnj ptcwakeup(tp) 1325430Swnj struct tty *tp; 1335430Swnj { 1345430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1355430Swnj 1365427Swnj if (pti->pt_selr) { 1375427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1385427Swnj pti->pt_selr = 0; 1395427Swnj pti->pt_flags &= ~PF_RCOLL; 1404484Swnj } 1412281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1422281Stoy } 1432281Stoy 1442281Stoy /*ARGSUSED*/ 1452281Stoy ptcopen(dev, flag) 1464484Swnj dev_t dev; 1474484Swnj int flag; 1484484Swnj { 1492281Stoy register struct tty *tp; 1505427Swnj struct pt_ioctl *pti; 1512281Stoy 1524484Swnj if (minor(dev) >= NPTY) { 1532281Stoy u.u_error = ENXIO; 1542281Stoy return; 1552281Stoy } 1562281Stoy tp = &pt_tty[minor(dev)]; 1574484Swnj if (tp->t_oproc) { 1582281Stoy u.u_error = EIO; 1592281Stoy return; 1602281Stoy } 1614484Swnj tp->t_oproc = ptsstart; 1625408Swnj if (tp->t_state & TS_WOPEN) 1632281Stoy wakeup((caddr_t)&tp->t_rawq); 1645408Swnj tp->t_state |= TS_CARR_ON; 1655427Swnj pti = &pt_ioctl[minor(dev)]; 1665427Swnj pti->pt_flags = 0; 1675427Swnj pti->pt_send = 0; 1682281Stoy } 1692281Stoy 1702281Stoy ptcclose(dev) 1714484Swnj dev_t dev; 1724484Swnj { 1732281Stoy register struct tty *tp; 1742281Stoy 1752281Stoy tp = &pt_tty[minor(dev)]; 1765408Swnj if (tp->t_state & TS_ISOPEN) 1772281Stoy gsignal(tp->t_pgrp, SIGHUP); 1785408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 1794484Swnj flushtty(tp, FREAD|FWRITE); 1804484Swnj tp->t_oproc = 0; /* mark closed */ 1812281Stoy } 1822281Stoy 1832281Stoy ptcread(dev) 1845427Swnj dev_t dev; 1854484Swnj { 1862281Stoy register struct tty *tp; 1875427Swnj struct pt_ioctl *pti; 1882281Stoy 1892281Stoy tp = &pt_tty[minor(dev)]; 1905408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 1912281Stoy return; 1925427Swnj pti = &pt_ioctl[minor(dev)]; 1935427Swnj if (pti->pt_flags & PF_PKT) { 1945427Swnj if (pti->pt_send) { 1955427Swnj passc(pti->pt_send); 1965427Swnj pti->pt_send = 0; 1975427Swnj return; 1985427Swnj } 1995427Swnj passc(0); 2005427Swnj } 2015411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2025427Swnj if (pti->pt_flags&PF_NBIO) { 2035411Swnj u.u_error = EWOULDBLOCK; 2045411Swnj return; 2055411Swnj } 2062281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2075411Swnj } 2085408Swnj while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 2095408Swnj ; 2105408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2115408Swnj if (tp->t_state&TS_ASLEEP) { 2125408Swnj tp->t_state &= ~TS_ASLEEP; 2135408Swnj wakeup((caddr_t)&tp->t_outq); 2145408Swnj } 2155408Swnj if (tp->t_wsel) { 2165408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2175408Swnj tp->t_wsel = 0; 2185408Swnj tp->t_state &= ~TS_WCOLL; 2195408Swnj } 2202281Stoy } 2212281Stoy } 2222281Stoy 2235427Swnj ptsstop(tp, flush) 2245427Swnj register struct tty *tp; 2255427Swnj int flush; 2265427Swnj { 2275427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2285427Swnj 229*5574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 230*5574Swnj if (flush == 0) { 231*5574Swnj flush = TIOCPKT_STOP; 232*5574Swnj pti->pt_flags |= PF_STOPPED; 233*5574Swnj } else { 234*5574Swnj pti->pt_flags &= ~PF_STOPPED; 235*5574Swnj } 236*5574Swnj pti->pt_send = flush; 2375430Swnj ptcwakeup(tp); 2385427Swnj } 2395427Swnj 2405408Swnj ptcselect(dev, rw) 2414484Swnj dev_t dev; 2425408Swnj int rw; 2434484Swnj { 2444484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2454484Swnj struct pt_ioctl *pti; 2464484Swnj struct proc *p; 2475430Swnj int s; 2484484Swnj 2495408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2504484Swnj return (1); 2515430Swnj s = spl5(); 2525408Swnj switch (rw) { 2535408Swnj 2545408Swnj case FREAD: 2555430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2565430Swnj splx(s); 2575408Swnj return (1); 2585430Swnj } 2595408Swnj pti = &pt_ioctl[minor(dev)]; 2605427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2615427Swnj pti->pt_flags |= PF_RCOLL; 2625408Swnj else 2635427Swnj pti->pt_selr = u.u_procp; 2645430Swnj break; 2655408Swnj 2665408Swnj case FWRITE: 2675430Swnj if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) { 2685430Swnj splx(s); 2695408Swnj return (1); 2705430Swnj } 2715408Swnj pti = &pt_ioctl[minor(dev)]; 2725427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 2735427Swnj pti->pt_flags |= PF_WCOLL; 2745408Swnj else 2755427Swnj pti->pt_selw = u.u_procp; 2765430Swnj break; 2775408Swnj } 2785430Swnj splx(s); 2795430Swnj return (0); 2805396Sroot } 2814484Swnj 2822281Stoy ptcwrite(dev) 2835408Swnj dev_t dev; 2844484Swnj { 2852281Stoy register struct tty *tp; 2862281Stoy register char *cp, *ce; 2872281Stoy register int cc; 2882281Stoy char locbuf[BUFSIZ]; 2895408Swnj int cnt = 0; 2902281Stoy 2912281Stoy tp = &pt_tty[minor(dev)]; 2925408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2932281Stoy return; 2944484Swnj while (u.u_count) { 2952281Stoy cc = MIN(u.u_count, BUFSIZ); 2962281Stoy cp = locbuf; 2972281Stoy iomove(cp, (unsigned)cc, B_WRITE); 2984484Swnj if (u.u_error) 2992281Stoy break; 3002281Stoy ce = cp + cc; 3014484Swnj while (cp < ce) { 3024484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3032281Stoy wakeup((caddr_t)&tp->t_rawq); 3045408Swnj if (tp->t_state & TS_NBIO) { 3055408Swnj u.u_count += ce - cp; 3065408Swnj if (cnt == 0) 3075408Swnj u.u_error = EWOULDBLOCK; 3085408Swnj return; 3095408Swnj } 3102281Stoy /* Better than just flushing it! */ 3112281Stoy /* Wait for something to be read */ 3122281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3132281Stoy } 3144141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3155408Swnj cnt++; 3162281Stoy } 3172281Stoy } 3182281Stoy } 3192281Stoy 3202281Stoy /*ARGSUSED*/ 3212281Stoy ptyioctl(dev, cmd, addr, flag) 3224484Swnj caddr_t addr; 3234484Swnj dev_t dev; 3244484Swnj { 3252281Stoy register struct tty *tp; 3262281Stoy 3272281Stoy tp = &pt_tty[minor(dev)]; 3284484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 3295411Swnj if (cdevsw[major(dev)].d_open == ptcopen) { 3305427Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3315427Swnj if (cmd == TIOCPKT) { 3325427Swnj int packet; 3335427Swnj if (copyin((caddr_t)addr, &packet, sizeof (packet))) { 3345427Swnj u.u_error = EFAULT; 3355427Swnj return; 3365427Swnj } 3375427Swnj if (packet) 3385427Swnj pti->pt_flags |= PF_PKT; 3395427Swnj else 3405427Swnj pti->pt_flags &= ~PF_PKT; 3415427Swnj return; 3425427Swnj } 3435411Swnj if (cmd == FIONBIO) { 3445411Swnj int nbio; 3455411Swnj if (copyin(addr, &nbio, sizeof (nbio))) { 3465411Swnj u.u_error = EFAULT; 3475411Swnj return; 3485411Swnj } 3495411Swnj if (nbio) 3505427Swnj pti->pt_flags |= PF_NBIO; 3515411Swnj else 3525427Swnj pti->pt_flags &= ~PF_NBIO; 3535411Swnj return; 3545411Swnj } 3555411Swnj if (cmd == TIOCSETP) 3565411Swnj while (getc(&tp->t_outq) >= 0); 3575411Swnj } 3584484Swnj if (ttioctl(tp, cmd, addr, dev) == 0) 3592281Stoy u.u_error = ENOTTY; 3602281Stoy } 3612313Stoy #endif 362