xref: /csrg-svn/sys/kern/tty_pty.c (revision 5411)
1*5411Swnj /*	tty_pty.c	4.13	82/01/15	*/
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 {
314484Swnj 	int	pti_flags;
324484Swnj 	struct	clist pti_ioctl, pti_ioans;
334484Swnj 	int	pti_gensym;
345408Swnj 	struct	proc *pti_selr, *pti_selw;
354484Swnj } pt_ioctl[NPTY];
362281Stoy 
374484Swnj #define	PTCRCOLL	0x01
385408Swnj #define	PTCWCOLL	0x02
39*5411Swnj #define	PTCNBIO		0x04
402281Stoy 
412281Stoy /*ARGSUSED*/
422281Stoy ptsopen(dev, flag)
435396Sroot 	dev_t dev;
444484Swnj {
452281Stoy 	register struct tty *tp;
462281Stoy 
474484Swnj 	if (minor(dev) >= NPTY) {
482281Stoy 		u.u_error = ENXIO;
492281Stoy 		return;
502281Stoy 	}
512281Stoy 	tp = &pt_tty[minor(dev)];
525408Swnj 	if ((tp->t_state & TS_ISOPEN) == 0) {
532427Swnj 		ttychars(tp);		/* Set up default chars */
542427Swnj 		tp->t_flags = 0;	/* No features (nor raw mode) */
555408Swnj 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
562281Stoy 		u.u_error = EBUSY;
572281Stoy 		return;
582281Stoy 	}
594484Swnj 	if (tp->t_oproc)			/* Ctrlr still around. */
605408Swnj 		tp->t_state |= TS_CARR_ON;
615408Swnj 	while ((tp->t_state & TS_CARR_ON) == 0) {
625408Swnj 		tp->t_state |= TS_WOPEN;
632281Stoy 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
642281Stoy 	}
652281Stoy 	(*linesw[tp->t_line].l_open)(dev, tp);
662281Stoy }
672281Stoy 
682281Stoy ptsclose(dev)
695396Sroot 	dev_t dev;
705408Swnj {
712281Stoy 	register struct tty *tp;
722281Stoy 
732281Stoy 	tp = &pt_tty[minor(dev)];
742281Stoy 	(*linesw[tp->t_line].l_close)(tp);
752281Stoy }
762281Stoy 
772281Stoy ptsread(dev)
785396Sroot 	dev_t dev;
794484Swnj {
804484Swnj 	register struct tty *tp;
815408Swnj 	register struct pt_ioctl *pti;
822281Stoy 
832281Stoy 	tp = &pt_tty[minor(dev)];
844484Swnj 	if (tp->t_oproc) {
852281Stoy 		(*linesw[tp->t_line].l_read)(tp);
862281Stoy 		wakeup((caddr_t)&tp->t_rawq.c_cf);
875408Swnj 		if (tp->t_rawq.c_cc < TTYHOG/2 &&
885408Swnj 		    (pti = &pt_ioctl[minor(tp->t_dev)])->pti_selw) {
895408Swnj 			selwakeup(pti->pti_selw, pti->pti_flags & PTCWCOLL);
905408Swnj 			pti->pti_selw = 0;
915408Swnj 			pti->pti_flags &= ~PTCWCOLL;
925408Swnj 		}
932281Stoy 	}
942281Stoy }
952281Stoy 
965408Swnj /*
975408Swnj  * Write to pseudo-tty.
985408Swnj  * Wakeups of controlling tty will happen
995408Swnj  * indirectly, when tty driver calls ptsstart.
1005408Swnj  */
1012281Stoy ptswrite(dev)
1025396Sroot 	dev_t dev;
1034484Swnj {
1042281Stoy 	register struct tty *tp;
1052281Stoy 
1062281Stoy 	tp = &pt_tty[minor(dev)];
1074484Swnj 	if (tp->t_oproc)
1082281Stoy 		(*linesw[tp->t_line].l_write)(tp);
1092281Stoy }
1102281Stoy 
1115408Swnj /*
1125408Swnj  * Start output on pseudo-tty.
1135408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1145408Swnj  */
1152281Stoy ptsstart(tp)
1164484Swnj 	struct tty *tp;
1174484Swnj {
1184484Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1194484Swnj 
1205408Swnj 	if (tp->t_state & TS_TTSTOP)
1212281Stoy 		return;
1224484Swnj 	if (pti->pti_selr) {
1234484Swnj 		selwakeup(pti->pti_selr, pti->pti_flags & PTCRCOLL);
1244484Swnj 		pti->pti_selr = 0;
1254484Swnj 		pti->pti_flags &= ~PTCRCOLL;
1264484Swnj 	}
1272281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1282281Stoy }
1292281Stoy 
1302281Stoy /*ARGSUSED*/
1312281Stoy ptcopen(dev, flag)
1324484Swnj 	dev_t dev;
1334484Swnj 	int flag;
1344484Swnj {
1352281Stoy 	register struct tty *tp;
1362281Stoy 
1374484Swnj 	if (minor(dev) >= NPTY) {
1382281Stoy 		u.u_error = ENXIO;
1392281Stoy 		return;
1402281Stoy 	}
1412281Stoy 	tp = &pt_tty[minor(dev)];
1424484Swnj 	if (tp->t_oproc) {
1432281Stoy 		u.u_error = EIO;
1442281Stoy 		return;
1452281Stoy 	}
1464484Swnj 	tp->t_oproc = ptsstart;
1475408Swnj 	if (tp->t_state & TS_WOPEN)
1482281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1495408Swnj 	tp->t_state |= TS_CARR_ON;
1502281Stoy }
1512281Stoy 
1522281Stoy ptcclose(dev)
1534484Swnj 	dev_t dev;
1544484Swnj {
1552281Stoy 	register struct tty *tp;
1562281Stoy 
1572281Stoy 	tp = &pt_tty[minor(dev)];
1585408Swnj 	if (tp->t_state & TS_ISOPEN)
1592281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
1605408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
1614484Swnj 	flushtty(tp, FREAD|FWRITE);
1624484Swnj 	tp->t_oproc = 0;		/* mark closed */
1632281Stoy }
1642281Stoy 
1652281Stoy ptcread(dev)
1662281Stoy dev_t dev;
1674484Swnj {
1682281Stoy 	register struct tty *tp;
1692281Stoy 
1702281Stoy 	tp = &pt_tty[minor(dev)];
1715408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
1722281Stoy 		return;
173*5411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
174*5411Swnj 		if (pt_ioctl[minor(dev)].pti_flags&PTCNBIO) {
175*5411Swnj 			u.u_error = EWOULDBLOCK;
176*5411Swnj 			return;
177*5411Swnj 		}
1782281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
179*5411Swnj 	}
1805408Swnj 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
1815408Swnj 		;
1825408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
1835408Swnj 		if (tp->t_state&TS_ASLEEP) {
1845408Swnj 			tp->t_state &= ~TS_ASLEEP;
1855408Swnj 			wakeup((caddr_t)&tp->t_outq);
1865408Swnj 		}
1875408Swnj 		if (tp->t_wsel) {
1885408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
1895408Swnj 			tp->t_wsel = 0;
1905408Swnj 			tp->t_state &= ~TS_WCOLL;
1915408Swnj 		}
1922281Stoy 	}
1932281Stoy }
1942281Stoy 
1955408Swnj ptcselect(dev, rw)
1964484Swnj 	dev_t dev;
1975408Swnj 	int rw;
1984484Swnj {
1994484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2004484Swnj 	struct pt_ioctl *pti;
2014484Swnj 	struct proc *p;
2024484Swnj 
2035408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2044484Swnj 		return (1);
2055408Swnj 	switch (rw) {
2065408Swnj 
2075408Swnj 	case FREAD:
2085408Swnj 		if (tp->t_outq.c_cc)
2095408Swnj 			return (1);
2105408Swnj 		pti = &pt_ioctl[minor(dev)];
2115408Swnj 		if ((p = pti->pti_selr) && p->p_wchan == (caddr_t)&selwait)
2125408Swnj 			pti->pti_flags |= PTCRCOLL;
2135408Swnj 		else
2145408Swnj 			pti->pti_selr = u.u_procp;
2155408Swnj 		return (0);
2165408Swnj 
2175408Swnj 	case FWRITE:
2185408Swnj 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2)
2195408Swnj 			return (1);
2205408Swnj 		pti = &pt_ioctl[minor(dev)];
2215408Swnj 		if ((p = pti->pti_selw) && p->p_wchan == (caddr_t)&selwait)
2225408Swnj 			pti->pti_flags |= PTCWCOLL;
2235408Swnj 		else
2245408Swnj 			pti->pti_selw = u.u_procp;
2255408Swnj 	}
2265396Sroot }
2274484Swnj 
2282281Stoy ptcwrite(dev)
2295408Swnj 	dev_t dev;
2304484Swnj {
2312281Stoy 	register struct tty *tp;
2322281Stoy 	register char *cp, *ce;
2332281Stoy 	register int cc;
2342281Stoy 	char locbuf[BUFSIZ];
2355408Swnj 	int cnt = 0;
2362281Stoy 
2372281Stoy 	tp = &pt_tty[minor(dev)];
2385408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2392281Stoy 		return;
2404484Swnj 	while (u.u_count) {
2412281Stoy 		cc = MIN(u.u_count, BUFSIZ);
2422281Stoy 		cp = locbuf;
2432281Stoy 		iomove(cp, (unsigned)cc, B_WRITE);
2444484Swnj 		if (u.u_error)
2452281Stoy 			break;
2462281Stoy 		ce = cp + cc;
2474484Swnj 		while (cp < ce) {
2484484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
2492281Stoy 				wakeup((caddr_t)&tp->t_rawq);
2505408Swnj 				if (tp->t_state & TS_NBIO) {
2515408Swnj 					u.u_count += ce - cp;
2525408Swnj 					if (cnt == 0)
2535408Swnj 						u.u_error = EWOULDBLOCK;
2545408Swnj 					return;
2555408Swnj 				}
2562281Stoy 				/* Better than just flushing it! */
2572281Stoy 				/* Wait for something to be read */
2582281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
2592281Stoy 			}
2604141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
2615408Swnj 			cnt++;
2622281Stoy 		}
2632281Stoy 	}
2642281Stoy }
2652281Stoy 
2662281Stoy /*ARGSUSED*/
2672281Stoy ptyioctl(dev, cmd, addr, flag)
2684484Swnj 	caddr_t addr;
2694484Swnj 	dev_t dev;
2704484Swnj {
2712281Stoy 	register struct tty *tp;
2722281Stoy 
2732281Stoy 	tp = &pt_tty[minor(dev)];
2744484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
275*5411Swnj 	if (cdevsw[major(dev)].d_open == ptcopen) {
276*5411Swnj 		if (cmd == FIONBIO) {
277*5411Swnj 			int nbio;
278*5411Swnj 			register struct pt_ioctl *pti;
279*5411Swnj 			if (copyin(addr, &nbio, sizeof (nbio))) {
280*5411Swnj 				u.u_error = EFAULT;
281*5411Swnj 				return;
282*5411Swnj 			}
283*5411Swnj 			pti = &pt_ioctl[minor(dev)];
284*5411Swnj 			if (nbio)
285*5411Swnj 				pti->pti_flags |= PTCNBIO;
286*5411Swnj 			else
287*5411Swnj 				pti->pti_flags &= ~PTCNBIO;
288*5411Swnj 			return;
289*5411Swnj 		}
290*5411Swnj 		if (cmd == TIOCSETP)
291*5411Swnj 			while (getc(&tp->t_outq) >= 0);
292*5411Swnj 	}
2934484Swnj 	if (ttioctl(tp, cmd, addr, dev) == 0)
2942281Stoy 		u.u_error = ENOTTY;
2952281Stoy }
2962313Stoy #endif
297