xref: /csrg-svn/sys/kern/tty_pty.c (revision 6299)
1*6299Swnj /*	tty_pty.c	4.21	82/03/23	*/
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 
205408Swnj #undef	NPTY
216239Sroot #define	NPTY	32		/* crude XXX */
222281Stoy 
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 */
425894Swnj #define	PF_REMOTE	0x20		/* remote and flow controlled input */
436119Swnj #define	PF_NOSTOP	0x40
442281Stoy 
452281Stoy /*ARGSUSED*/
462281Stoy ptsopen(dev, flag)
475396Sroot 	dev_t dev;
484484Swnj {
492281Stoy 	register struct tty *tp;
502281Stoy 
514484Swnj 	if (minor(dev) >= NPTY) {
522281Stoy 		u.u_error = ENXIO;
532281Stoy 		return;
542281Stoy 	}
552281Stoy 	tp = &pt_tty[minor(dev)];
565408Swnj 	if ((tp->t_state & TS_ISOPEN) == 0) {
572427Swnj 		ttychars(tp);		/* Set up default chars */
582427Swnj 		tp->t_flags = 0;	/* No features (nor raw mode) */
595408Swnj 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
602281Stoy 		u.u_error = EBUSY;
612281Stoy 		return;
622281Stoy 	}
634484Swnj 	if (tp->t_oproc)			/* Ctrlr still around. */
645408Swnj 		tp->t_state |= TS_CARR_ON;
655408Swnj 	while ((tp->t_state & TS_CARR_ON) == 0) {
665408Swnj 		tp->t_state |= TS_WOPEN;
672281Stoy 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
682281Stoy 	}
692281Stoy 	(*linesw[tp->t_line].l_open)(dev, tp);
702281Stoy }
712281Stoy 
722281Stoy ptsclose(dev)
735396Sroot 	dev_t dev;
745408Swnj {
752281Stoy 	register struct tty *tp;
762281Stoy 
772281Stoy 	tp = &pt_tty[minor(dev)];
782281Stoy 	(*linesw[tp->t_line].l_close)(tp);
79*6299Swnj 	ttyclose(tp);
802281Stoy }
812281Stoy 
822281Stoy ptsread(dev)
835396Sroot 	dev_t dev;
844484Swnj {
855894Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
865894Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
872281Stoy 
885894Swnj again:
895894Swnj 	if (pti->pt_flags & PF_REMOTE) {
905894Swnj 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
915894Swnj 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
925894Swnj 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
935894Swnj 	/*
945894Swnj 			    (u.u_procp->p_flag&SDETACH) ||
955894Swnj 	*/
965894Swnj 			    u.u_procp->p_flag&SVFORK)
975894Swnj 				return;
985894Swnj 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
995894Swnj 			sleep((caddr_t)&lbolt, TTIPRI);
1005408Swnj 		}
1015894Swnj 		if (tp->t_rawq.c_cc == 0) {
1025894Swnj 			if (tp->t_state & TS_NBIO) {
1035894Swnj 				u.u_error = EWOULDBLOCK;
1045894Swnj 				return;
1055894Swnj 			}
1065894Swnj 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1075894Swnj 			goto again;
1085894Swnj 		}
1095894Swnj 		while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0)
1105894Swnj 			;
1115894Swnj 		if (tp->t_rawq.c_cc == 1)
1125894Swnj 			(void) getc(&tp->t_rawq);
1135894Swnj 		if (tp->t_rawq.c_cc)
1145894Swnj 			return;
1155894Swnj 	} else
1165894Swnj 		if (tp->t_oproc)
1175894Swnj 			(*linesw[tp->t_line].l_read)(tp);
1185894Swnj 	wakeup((caddr_t)&tp->t_rawq.c_cf);
1195894Swnj 	if (pti->pt_selw) {
1205894Swnj 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
1215894Swnj 		pti->pt_selw = 0;
1225894Swnj 		pti->pt_flags &= ~PF_WCOLL;
1232281Stoy 	}
1242281Stoy }
1252281Stoy 
1265408Swnj /*
1275408Swnj  * Write to pseudo-tty.
1285408Swnj  * Wakeups of controlling tty will happen
1295408Swnj  * indirectly, when tty driver calls ptsstart.
1305408Swnj  */
1312281Stoy ptswrite(dev)
1325396Sroot 	dev_t dev;
1334484Swnj {
1342281Stoy 	register struct tty *tp;
1352281Stoy 
1362281Stoy 	tp = &pt_tty[minor(dev)];
1374484Swnj 	if (tp->t_oproc)
1382281Stoy 		(*linesw[tp->t_line].l_write)(tp);
1392281Stoy }
1402281Stoy 
1415408Swnj /*
1425408Swnj  * Start output on pseudo-tty.
1435408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1445408Swnj  */
1452281Stoy ptsstart(tp)
1464484Swnj 	struct tty *tp;
1474484Swnj {
1485574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1494484Swnj 
1505408Swnj 	if (tp->t_state & TS_TTSTOP)
1512281Stoy 		return;
1525574Swnj 	if (pti->pt_flags & PF_STOPPED) {
1535574Swnj 		pti->pt_flags &= ~PF_STOPPED;
1545574Swnj 		pti->pt_send = TIOCPKT_START;
1555574Swnj 	}
1565430Swnj 	ptcwakeup(tp);
1575430Swnj }
1585430Swnj 
1595430Swnj ptcwakeup(tp)
1605430Swnj 	struct tty *tp;
1615430Swnj {
1625430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1635430Swnj 
1645427Swnj 	if (pti->pt_selr) {
1655427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
1665427Swnj 		pti->pt_selr = 0;
1675427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1684484Swnj 	}
1692281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1702281Stoy }
1712281Stoy 
1722281Stoy /*ARGSUSED*/
1732281Stoy ptcopen(dev, flag)
1744484Swnj 	dev_t dev;
1754484Swnj 	int flag;
1764484Swnj {
1772281Stoy 	register struct tty *tp;
1785427Swnj 	struct pt_ioctl *pti;
1792281Stoy 
1804484Swnj 	if (minor(dev) >= NPTY) {
1812281Stoy 		u.u_error = ENXIO;
1822281Stoy 		return;
1832281Stoy 	}
1842281Stoy 	tp = &pt_tty[minor(dev)];
1854484Swnj 	if (tp->t_oproc) {
1862281Stoy 		u.u_error = EIO;
1872281Stoy 		return;
1882281Stoy 	}
1894484Swnj 	tp->t_oproc = ptsstart;
1905408Swnj 	if (tp->t_state & TS_WOPEN)
1912281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1925408Swnj 	tp->t_state |= TS_CARR_ON;
1935427Swnj 	pti = &pt_ioctl[minor(dev)];
1945427Swnj 	pti->pt_flags = 0;
1955427Swnj 	pti->pt_send = 0;
1962281Stoy }
1972281Stoy 
1982281Stoy ptcclose(dev)
1994484Swnj 	dev_t dev;
2004484Swnj {
2012281Stoy 	register struct tty *tp;
2022281Stoy 
2032281Stoy 	tp = &pt_tty[minor(dev)];
2045408Swnj 	if (tp->t_state & TS_ISOPEN)
2052281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
2065408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
2074484Swnj 	flushtty(tp, FREAD|FWRITE);
2084484Swnj 	tp->t_oproc = 0;		/* mark closed */
2092281Stoy }
2102281Stoy 
2112281Stoy ptcread(dev)
2125427Swnj 	dev_t dev;
2134484Swnj {
2142281Stoy 	register struct tty *tp;
2155427Swnj 	struct pt_ioctl *pti;
2162281Stoy 
2172281Stoy 	tp = &pt_tty[minor(dev)];
2185408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2192281Stoy 		return;
2205427Swnj 	pti = &pt_ioctl[minor(dev)];
2215427Swnj 	if (pti->pt_flags & PF_PKT) {
2225427Swnj 		if (pti->pt_send) {
2236158Ssam 			(void) passc(pti->pt_send);
2245427Swnj 			pti->pt_send = 0;
2255427Swnj 			return;
2265427Swnj 		}
2276158Ssam 		(void) passc(0);
2285427Swnj 	}
2295411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
2305427Swnj 		if (pti->pt_flags&PF_NBIO) {
2315411Swnj 			u.u_error = EWOULDBLOCK;
2325411Swnj 			return;
2335411Swnj 		}
2342281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2355411Swnj 	}
2365408Swnj 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
2375408Swnj 		;
2385408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
2395408Swnj 		if (tp->t_state&TS_ASLEEP) {
2405408Swnj 			tp->t_state &= ~TS_ASLEEP;
2415408Swnj 			wakeup((caddr_t)&tp->t_outq);
2425408Swnj 		}
2435408Swnj 		if (tp->t_wsel) {
2445408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2455408Swnj 			tp->t_wsel = 0;
2465408Swnj 			tp->t_state &= ~TS_WCOLL;
2475408Swnj 		}
2482281Stoy 	}
2492281Stoy }
2502281Stoy 
2515427Swnj ptsstop(tp, flush)
2525427Swnj 	register struct tty *tp;
2535427Swnj 	int flush;
2545427Swnj {
2555427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
2565427Swnj 
2575574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
2585574Swnj 	if (flush == 0) {
2595574Swnj 		flush = TIOCPKT_STOP;
2605574Swnj 		pti->pt_flags |= PF_STOPPED;
2615574Swnj 	} else {
2625574Swnj 		pti->pt_flags &= ~PF_STOPPED;
2635574Swnj 	}
2646119Swnj 	pti->pt_send |= flush;
2655430Swnj 	ptcwakeup(tp);
2665427Swnj }
2675427Swnj 
2685408Swnj ptcselect(dev, rw)
2694484Swnj 	dev_t dev;
2705408Swnj 	int rw;
2714484Swnj {
2724484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2735894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2744484Swnj 	struct proc *p;
2755430Swnj 	int s;
2764484Swnj 
2775408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2784484Swnj 		return (1);
2795430Swnj 	s = spl5();
2805408Swnj 	switch (rw) {
2815408Swnj 
2825408Swnj 	case FREAD:
2835430Swnj 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
2845430Swnj 			splx(s);
2855408Swnj 			return (1);
2865430Swnj 		}
2875427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
2885427Swnj 			pti->pt_flags |= PF_RCOLL;
2895408Swnj 		else
2905427Swnj 			pti->pt_selr = u.u_procp;
2915430Swnj 		break;
2925408Swnj 
2935408Swnj 	case FWRITE:
2945894Swnj 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
2955430Swnj 			splx(s);
2965408Swnj 			return (1);
2975430Swnj 		}
2985427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
2995427Swnj 			pti->pt_flags |= PF_WCOLL;
3005408Swnj 		else
3015427Swnj 			pti->pt_selw = u.u_procp;
3025430Swnj 		break;
3035408Swnj 	}
3045430Swnj 	splx(s);
3055430Swnj 	return (0);
3065396Sroot }
3074484Swnj 
3082281Stoy ptcwrite(dev)
3095408Swnj 	dev_t dev;
3104484Swnj {
3112281Stoy 	register struct tty *tp;
3122281Stoy 	register char *cp, *ce;
3132281Stoy 	register int cc;
3142281Stoy 	char locbuf[BUFSIZ];
3155408Swnj 	int cnt = 0;
3165894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3172281Stoy 
3182281Stoy 	tp = &pt_tty[minor(dev)];
3195408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
3202281Stoy 		return;
3215894Swnj 	do {
3222281Stoy 		cc = MIN(u.u_count, BUFSIZ);
3232281Stoy 		cp = locbuf;
3242281Stoy 		iomove(cp, (unsigned)cc, B_WRITE);
3254484Swnj 		if (u.u_error)
3262281Stoy 			break;
3272281Stoy 		ce = cp + cc;
3285894Swnj again:
3295894Swnj 		if (pti->pt_flags & PF_REMOTE) {
3305894Swnj 			if (tp->t_rawq.c_cc) {
3315894Swnj 				if (pti->pt_flags & PF_NBIO) {
3325894Swnj 					u.u_count += ce - cp;
3335894Swnj 					u.u_error = EWOULDBLOCK;
3345894Swnj 					return;
3355894Swnj 				}
3365894Swnj 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3375894Swnj 				goto again;
3385894Swnj 			}
3396158Ssam 			(void) b_to_q(cp, cc, &tp->t_rawq);
3406158Ssam 			(void) putc(0, &tp->t_rawq);
3415894Swnj 			wakeup((caddr_t)&tp->t_rawq);
3425894Swnj 			return;
3435894Swnj 		}
3444484Swnj 		while (cp < ce) {
3454484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
3462281Stoy 				wakeup((caddr_t)&tp->t_rawq);
3475408Swnj 				if (tp->t_state & TS_NBIO) {
3485408Swnj 					u.u_count += ce - cp;
3495408Swnj 					if (cnt == 0)
3505408Swnj 						u.u_error = EWOULDBLOCK;
3515408Swnj 					return;
3525408Swnj 				}
3532281Stoy 				/* Better than just flushing it! */
3542281Stoy 				/* Wait for something to be read */
3552281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3565894Swnj 				goto again;
3572281Stoy 			}
3584141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
3595408Swnj 			cnt++;
3602281Stoy 		}
3615894Swnj 	} while (u.u_count);
3622281Stoy }
3632281Stoy 
3642281Stoy /*ARGSUSED*/
3652281Stoy ptyioctl(dev, cmd, addr, flag)
3664484Swnj 	caddr_t addr;
3674484Swnj 	dev_t dev;
3684484Swnj {
3696119Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
3706119Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3712281Stoy 
3724484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
3735411Swnj 	if (cdevsw[major(dev)].d_open == ptcopen) {
3745427Swnj 		if (cmd == TIOCPKT) {
3755427Swnj 			int packet;
3766158Ssam 			if (copyin((caddr_t)addr, (caddr_t)&packet, sizeof (packet))) {
3775427Swnj 				u.u_error = EFAULT;
3785427Swnj 				return;
3795427Swnj 			}
3805427Swnj 			if (packet)
3815427Swnj 				pti->pt_flags |= PF_PKT;
3825427Swnj 			else
3835427Swnj 				pti->pt_flags &= ~PF_PKT;
3845427Swnj 			return;
3855427Swnj 		}
3865894Swnj 		if (cmd == TIOCREMOTE) {
3875894Swnj 			int remote;
3886158Ssam 			if (copyin((caddr_t)addr, (caddr_t)&remote, sizeof (remote))) {
3895894Swnj 				u.u_error = EFAULT;
3905894Swnj 				return;
3915894Swnj 			}
3925894Swnj 			if (remote)
3935894Swnj 				pti->pt_flags |= PF_REMOTE;
3945894Swnj 			else
3955894Swnj 				pti->pt_flags &= ~PF_REMOTE;
3965894Swnj 			flushtty(tp, FREAD|FWRITE);
3975894Swnj 			return;
3985894Swnj 		}
3995411Swnj 		if (cmd == FIONBIO) {
4005411Swnj 			int nbio;
4016158Ssam 			if (copyin((caddr_t)addr, (caddr_t)&nbio, sizeof (nbio))) {
4025411Swnj 				u.u_error = EFAULT;
4035411Swnj 				return;
4045411Swnj 			}
4055411Swnj 			if (nbio)
4065427Swnj 				pti->pt_flags |= PF_NBIO;
4075411Swnj 			else
4085427Swnj 				pti->pt_flags &= ~PF_NBIO;
4095411Swnj 			return;
4105411Swnj 		}
4115411Swnj 		if (cmd == TIOCSETP)
4125411Swnj 			while (getc(&tp->t_outq) >= 0);
4135411Swnj 	}
4144484Swnj 	if (ttioctl(tp, cmd, addr, dev) == 0)
4152281Stoy 		u.u_error = ENOTTY;
4166119Swnj 	{ int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
4176119Swnj 		      tp->t_un.t_chr.t_startc == ('q'&037));
4186119Swnj 	if (pti->pt_flags & PF_NOSTOP) {
4196119Swnj 		if (stop) {
4206119Swnj 			pti->pt_send &= TIOCPKT_NOSTOP;
4216119Swnj 			pti->pt_send |= TIOCPKT_DOSTOP;
4226119Swnj 			pti->pt_flags &= ~PF_NOSTOP;
4236119Swnj 			ptcwakeup(tp);
4246119Swnj 		}
4256119Swnj 	} else {
4266119Swnj 		if (stop == 0) {
4276119Swnj 			pti->pt_send &= ~TIOCPKT_DOSTOP;
4286119Swnj 			pti->pt_send |= TIOCPKT_NOSTOP;
4296119Swnj 			pti->pt_flags |= PF_NOSTOP;
4306119Swnj 			ptcwakeup(tp);
4316119Swnj 		}
4326119Swnj 	}
4336119Swnj 	}
4342281Stoy }
4352313Stoy #endif
436