xref: /csrg-svn/sys/kern/tty_pty.c (revision 7626)
1*7626Ssam /*	tty_pty.c	4.23	82/08/01	*/
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 
207475Ssam #if NPTY == 1
215408Swnj #undef	NPTY
226239Sroot #define	NPTY	32		/* crude XXX */
237475Ssam #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*/
367*7626Ssam ptyioctl(dev, cmd, data, flag)
368*7626Ssam 	caddr_t data;
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 ??? */
375*7626Ssam 	if (cdevsw[major(dev)].d_open == ptcopen)
376*7626Ssam 		switch (cmd) {
377*7626Ssam 
378*7626Ssam 		case TIOCPKT:
379*7626Ssam 			if (*(int *)data)
3805427Swnj 				pti->pt_flags |= PF_PKT;
3815427Swnj 			else
3825427Swnj 				pti->pt_flags &= ~PF_PKT;
3835427Swnj 			return;
384*7626Ssam 
385*7626Ssam 		case TIOCREMOTE:
386*7626Ssam 			if (*(int *)data)
3875894Swnj 				pti->pt_flags |= PF_REMOTE;
3885894Swnj 			else
3895894Swnj 				pti->pt_flags &= ~PF_REMOTE;
3905894Swnj 			flushtty(tp, FREAD|FWRITE);
3915894Swnj 			return;
392*7626Ssam 
393*7626Ssam 		case FIONBIO:
394*7626Ssam 			if (*(int *)data)
3955427Swnj 				pti->pt_flags |= PF_NBIO;
3965411Swnj 			else
3975427Swnj 				pti->pt_flags &= ~PF_NBIO;
3985411Swnj 			return;
399*7626Ssam 
400*7626Ssam 		case TIOCSETP:
401*7626Ssam 			while (getc(&tp->t_outq) >= 0)
402*7626Ssam 				;
403*7626Ssam 			break;
4045411Swnj 		}
405*7626Ssam 	if (ttioctl(tp, cmd, data, dev) == 0)
4062281Stoy 		u.u_error = ENOTTY;
4076119Swnj 	{ int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
4086119Swnj 		      tp->t_un.t_chr.t_startc == ('q'&037));
4096119Swnj 	if (pti->pt_flags & PF_NOSTOP) {
4106119Swnj 		if (stop) {
4116119Swnj 			pti->pt_send &= TIOCPKT_NOSTOP;
4126119Swnj 			pti->pt_send |= TIOCPKT_DOSTOP;
4136119Swnj 			pti->pt_flags &= ~PF_NOSTOP;
4146119Swnj 			ptcwakeup(tp);
4156119Swnj 		}
4166119Swnj 	} else {
4176119Swnj 		if (stop == 0) {
4186119Swnj 			pti->pt_send &= ~TIOCPKT_DOSTOP;
4196119Swnj 			pti->pt_send |= TIOCPKT_NOSTOP;
4206119Swnj 			pti->pt_flags |= PF_NOSTOP;
4216119Swnj 			ptcwakeup(tp);
4226119Swnj 		}
4236119Swnj 	}
4246119Swnj 	}
4252281Stoy }
4262313Stoy #endif
427