xref: /csrg-svn/sys/kern/tty_pty.c (revision 5430)
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