xref: /csrg-svn/sys/kern/tty_pty.c (revision 7823)
1*7823Sroot /*	tty_pty.c	4.24	82/08/22	*/
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"
162427Swnj #include "../h/file.h"
174484Swnj #include "../h/proc.h"
18*7823Sroot #include "../h/uio.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 
84*7823Sroot ptsread(dev, uio)
855396Sroot 	dev_t dev;
86*7823Sroot 	struct uio *uio;
874484Swnj {
885894Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
895894Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
902281Stoy 
915894Swnj again:
925894Swnj 	if (pti->pt_flags & PF_REMOTE) {
935894Swnj 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
945894Swnj 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
955894Swnj 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
965894Swnj 	/*
975894Swnj 			    (u.u_procp->p_flag&SDETACH) ||
985894Swnj 	*/
995894Swnj 			    u.u_procp->p_flag&SVFORK)
1005894Swnj 				return;
1015894Swnj 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
1025894Swnj 			sleep((caddr_t)&lbolt, TTIPRI);
1035408Swnj 		}
1045894Swnj 		if (tp->t_rawq.c_cc == 0) {
1055894Swnj 			if (tp->t_state & TS_NBIO) {
1065894Swnj 				u.u_error = EWOULDBLOCK;
1075894Swnj 				return;
1085894Swnj 			}
1095894Swnj 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1105894Swnj 			goto again;
1115894Swnj 		}
112*7823Sroot 		while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
113*7823Sroot 			if (ureadc(getc(&tp->t_rawq), uio) < 0) {
114*7823Sroot 				u.u_error = EFAULT;
115*7823Sroot 				break;
116*7823Sroot 			}
1175894Swnj 		if (tp->t_rawq.c_cc == 1)
1185894Swnj 			(void) getc(&tp->t_rawq);
1195894Swnj 		if (tp->t_rawq.c_cc)
1205894Swnj 			return;
1215894Swnj 	} else
1225894Swnj 		if (tp->t_oproc)
123*7823Sroot 			(*linesw[tp->t_line].l_read)(tp, uio);
1245894Swnj 	wakeup((caddr_t)&tp->t_rawq.c_cf);
1255894Swnj 	if (pti->pt_selw) {
1265894Swnj 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
1275894Swnj 		pti->pt_selw = 0;
1285894Swnj 		pti->pt_flags &= ~PF_WCOLL;
1292281Stoy 	}
1302281Stoy }
1312281Stoy 
1325408Swnj /*
1335408Swnj  * Write to pseudo-tty.
1345408Swnj  * Wakeups of controlling tty will happen
1355408Swnj  * indirectly, when tty driver calls ptsstart.
1365408Swnj  */
137*7823Sroot ptswrite(dev, uio)
1385396Sroot 	dev_t dev;
139*7823Sroot 	struct uio *uio;
1404484Swnj {
1412281Stoy 	register struct tty *tp;
1422281Stoy 
1432281Stoy 	tp = &pt_tty[minor(dev)];
1444484Swnj 	if (tp->t_oproc)
145*7823Sroot 		(*linesw[tp->t_line].l_write)(tp, uio);
1462281Stoy }
1472281Stoy 
1485408Swnj /*
1495408Swnj  * Start output on pseudo-tty.
1505408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1515408Swnj  */
1522281Stoy ptsstart(tp)
1534484Swnj 	struct tty *tp;
1544484Swnj {
1555574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1564484Swnj 
1575408Swnj 	if (tp->t_state & TS_TTSTOP)
1582281Stoy 		return;
1595574Swnj 	if (pti->pt_flags & PF_STOPPED) {
1605574Swnj 		pti->pt_flags &= ~PF_STOPPED;
1615574Swnj 		pti->pt_send = TIOCPKT_START;
1625574Swnj 	}
1635430Swnj 	ptcwakeup(tp);
1645430Swnj }
1655430Swnj 
1665430Swnj ptcwakeup(tp)
1675430Swnj 	struct tty *tp;
1685430Swnj {
1695430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1705430Swnj 
1715427Swnj 	if (pti->pt_selr) {
1725427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
1735427Swnj 		pti->pt_selr = 0;
1745427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1754484Swnj 	}
1762281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1772281Stoy }
1782281Stoy 
1792281Stoy /*ARGSUSED*/
1802281Stoy ptcopen(dev, flag)
1814484Swnj 	dev_t dev;
1824484Swnj 	int flag;
1834484Swnj {
1842281Stoy 	register struct tty *tp;
1855427Swnj 	struct pt_ioctl *pti;
1862281Stoy 
1874484Swnj 	if (minor(dev) >= NPTY) {
1882281Stoy 		u.u_error = ENXIO;
1892281Stoy 		return;
1902281Stoy 	}
1912281Stoy 	tp = &pt_tty[minor(dev)];
1924484Swnj 	if (tp->t_oproc) {
1932281Stoy 		u.u_error = EIO;
1942281Stoy 		return;
1952281Stoy 	}
1964484Swnj 	tp->t_oproc = ptsstart;
1975408Swnj 	if (tp->t_state & TS_WOPEN)
1982281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1995408Swnj 	tp->t_state |= TS_CARR_ON;
2005427Swnj 	pti = &pt_ioctl[minor(dev)];
2015427Swnj 	pti->pt_flags = 0;
2025427Swnj 	pti->pt_send = 0;
2032281Stoy }
2042281Stoy 
2052281Stoy ptcclose(dev)
2064484Swnj 	dev_t dev;
2074484Swnj {
2082281Stoy 	register struct tty *tp;
2092281Stoy 
2102281Stoy 	tp = &pt_tty[minor(dev)];
2115408Swnj 	if (tp->t_state & TS_ISOPEN)
2122281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
2135408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
2144484Swnj 	flushtty(tp, FREAD|FWRITE);
2154484Swnj 	tp->t_oproc = 0;		/* mark closed */
2162281Stoy }
2172281Stoy 
218*7823Sroot ptcread(dev, uio)
2195427Swnj 	dev_t dev;
220*7823Sroot 	struct uio *uio;
2214484Swnj {
2222281Stoy 	register struct tty *tp;
2235427Swnj 	struct pt_ioctl *pti;
2242281Stoy 
2252281Stoy 	tp = &pt_tty[minor(dev)];
2265408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2272281Stoy 		return;
2285427Swnj 	pti = &pt_ioctl[minor(dev)];
2295427Swnj 	if (pti->pt_flags & PF_PKT) {
2305427Swnj 		if (pti->pt_send) {
231*7823Sroot 			(void) ureadc(pti->pt_send, uio);
2325427Swnj 			pti->pt_send = 0;
2335427Swnj 			return;
2345427Swnj 		}
235*7823Sroot 		(void) ureadc(0, uio);
2365427Swnj 	}
2375411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
2385427Swnj 		if (pti->pt_flags&PF_NBIO) {
2395411Swnj 			u.u_error = EWOULDBLOCK;
2405411Swnj 			return;
2415411Swnj 		}
2422281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2435411Swnj 	}
244*7823Sroot 	while (tp->t_outq.c_cc && uio->uio_resid > 0)
245*7823Sroot 		if (ureadc(getc(&tp->t_outq), uio) < 0) {
246*7823Sroot 			u.u_error = EFAULT;
247*7823Sroot 			break;
248*7823Sroot 		}
2495408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
2505408Swnj 		if (tp->t_state&TS_ASLEEP) {
2515408Swnj 			tp->t_state &= ~TS_ASLEEP;
2525408Swnj 			wakeup((caddr_t)&tp->t_outq);
2535408Swnj 		}
2545408Swnj 		if (tp->t_wsel) {
2555408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2565408Swnj 			tp->t_wsel = 0;
2575408Swnj 			tp->t_state &= ~TS_WCOLL;
2585408Swnj 		}
2592281Stoy 	}
2602281Stoy }
2612281Stoy 
2625427Swnj ptsstop(tp, flush)
2635427Swnj 	register struct tty *tp;
2645427Swnj 	int flush;
2655427Swnj {
2665427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
2675427Swnj 
2685574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
2695574Swnj 	if (flush == 0) {
2705574Swnj 		flush = TIOCPKT_STOP;
2715574Swnj 		pti->pt_flags |= PF_STOPPED;
2725574Swnj 	} else {
2735574Swnj 		pti->pt_flags &= ~PF_STOPPED;
2745574Swnj 	}
2756119Swnj 	pti->pt_send |= flush;
2765430Swnj 	ptcwakeup(tp);
2775427Swnj }
2785427Swnj 
2795408Swnj ptcselect(dev, rw)
2804484Swnj 	dev_t dev;
2815408Swnj 	int rw;
2824484Swnj {
2834484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2845894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2854484Swnj 	struct proc *p;
2865430Swnj 	int s;
2874484Swnj 
2885408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2894484Swnj 		return (1);
2905430Swnj 	s = spl5();
2915408Swnj 	switch (rw) {
2925408Swnj 
2935408Swnj 	case FREAD:
2945430Swnj 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
2955430Swnj 			splx(s);
2965408Swnj 			return (1);
2975430Swnj 		}
2985427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
2995427Swnj 			pti->pt_flags |= PF_RCOLL;
3005408Swnj 		else
3015427Swnj 			pti->pt_selr = u.u_procp;
3025430Swnj 		break;
3035408Swnj 
3045408Swnj 	case FWRITE:
3055894Swnj 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
3065430Swnj 			splx(s);
3075408Swnj 			return (1);
3085430Swnj 		}
3095427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
3105427Swnj 			pti->pt_flags |= PF_WCOLL;
3115408Swnj 		else
3125427Swnj 			pti->pt_selw = u.u_procp;
3135430Swnj 		break;
3145408Swnj 	}
3155430Swnj 	splx(s);
3165430Swnj 	return (0);
3175396Sroot }
3184484Swnj 
319*7823Sroot ptcwrite(dev, uio)
3205408Swnj 	dev_t dev;
321*7823Sroot 	struct uio *uio;
3224484Swnj {
3232281Stoy 	register struct tty *tp;
3242281Stoy 	register char *cp, *ce;
3252281Stoy 	register int cc;
3262281Stoy 	char locbuf[BUFSIZ];
3275408Swnj 	int cnt = 0;
3285894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3292281Stoy 
3302281Stoy 	tp = &pt_tty[minor(dev)];
3315408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
3322281Stoy 		return;
3335894Swnj 	do {
334*7823Sroot 		register struct iovec *iov;
335*7823Sroot 
336*7823Sroot 		if (uio->uio_iovcnt == 0)
337*7823Sroot 			break;
338*7823Sroot 		iov = uio->uio_iov;
339*7823Sroot 		if (iov->iov_len == 0) {
340*7823Sroot 			uio->uio_iovcnt--;
341*7823Sroot 			uio->uio_iov++;
342*7823Sroot 			if (uio->uio_iovcnt < 0)
343*7823Sroot 				panic("ptcwrite");
344*7823Sroot 			continue;
345*7823Sroot 		}
346*7823Sroot 		cc = MIN(iov->iov_len, BUFSIZ);
3472281Stoy 		cp = locbuf;
348*7823Sroot 		u.u_error = uiomove(cp, cc, UIO_WRITE, uio);
3494484Swnj 		if (u.u_error)
3502281Stoy 			break;
3512281Stoy 		ce = cp + cc;
3525894Swnj again:
3535894Swnj 		if (pti->pt_flags & PF_REMOTE) {
3545894Swnj 			if (tp->t_rawq.c_cc) {
3555894Swnj 				if (pti->pt_flags & PF_NBIO) {
356*7823Sroot 					iov->iov_base -= ce - cp;
357*7823Sroot 					iov->iov_len += ce - cp;
358*7823Sroot 					uio->uio_resid += ce - cp;
359*7823Sroot 					uio->uio_offset -= ce - cp;
3605894Swnj 					u.u_error = EWOULDBLOCK;
3615894Swnj 					return;
3625894Swnj 				}
3635894Swnj 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3645894Swnj 				goto again;
3655894Swnj 			}
3666158Ssam 			(void) b_to_q(cp, cc, &tp->t_rawq);
3676158Ssam 			(void) putc(0, &tp->t_rawq);
3685894Swnj 			wakeup((caddr_t)&tp->t_rawq);
3695894Swnj 			return;
3705894Swnj 		}
3714484Swnj 		while (cp < ce) {
3724484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
3732281Stoy 				wakeup((caddr_t)&tp->t_rawq);
3745408Swnj 				if (tp->t_state & TS_NBIO) {
375*7823Sroot 					iov->iov_base -= ce - cp;
376*7823Sroot 					iov->iov_len += ce - cp;
377*7823Sroot 					uio->uio_resid += ce - cp;
378*7823Sroot 					uio->uio_offset -= ce - cp;
3795408Swnj 					if (cnt == 0)
3805408Swnj 						u.u_error = EWOULDBLOCK;
3815408Swnj 					return;
3825408Swnj 				}
3832281Stoy 				/* Better than just flushing it! */
3842281Stoy 				/* Wait for something to be read */
3852281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3865894Swnj 				goto again;
3872281Stoy 			}
3884141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
3895408Swnj 			cnt++;
3902281Stoy 		}
391*7823Sroot 	} while (uio->uio_resid);
3922281Stoy }
3932281Stoy 
3942281Stoy /*ARGSUSED*/
3957626Ssam ptyioctl(dev, cmd, data, flag)
3967626Ssam 	caddr_t data;
3974484Swnj 	dev_t dev;
3984484Swnj {
3996119Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
4006119Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
4012281Stoy 
4024484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
4037626Ssam 	if (cdevsw[major(dev)].d_open == ptcopen)
4047626Ssam 		switch (cmd) {
4057626Ssam 
4067626Ssam 		case TIOCPKT:
4077626Ssam 			if (*(int *)data)
4085427Swnj 				pti->pt_flags |= PF_PKT;
4095427Swnj 			else
4105427Swnj 				pti->pt_flags &= ~PF_PKT;
4115427Swnj 			return;
4127626Ssam 
4137626Ssam 		case TIOCREMOTE:
4147626Ssam 			if (*(int *)data)
4155894Swnj 				pti->pt_flags |= PF_REMOTE;
4165894Swnj 			else
4175894Swnj 				pti->pt_flags &= ~PF_REMOTE;
4185894Swnj 			flushtty(tp, FREAD|FWRITE);
4195894Swnj 			return;
4207626Ssam 
4217626Ssam 		case FIONBIO:
4227626Ssam 			if (*(int *)data)
4235427Swnj 				pti->pt_flags |= PF_NBIO;
4245411Swnj 			else
4255427Swnj 				pti->pt_flags &= ~PF_NBIO;
4265411Swnj 			return;
4277626Ssam 
4287626Ssam 		case TIOCSETP:
4297626Ssam 			while (getc(&tp->t_outq) >= 0)
4307626Ssam 				;
4317626Ssam 			break;
4325411Swnj 		}
4337626Ssam 	if (ttioctl(tp, cmd, data, dev) == 0)
4342281Stoy 		u.u_error = ENOTTY;
4356119Swnj 	{ int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
4366119Swnj 		      tp->t_un.t_chr.t_startc == ('q'&037));
4376119Swnj 	if (pti->pt_flags & PF_NOSTOP) {
4386119Swnj 		if (stop) {
4396119Swnj 			pti->pt_send &= TIOCPKT_NOSTOP;
4406119Swnj 			pti->pt_send |= TIOCPKT_DOSTOP;
4416119Swnj 			pti->pt_flags &= ~PF_NOSTOP;
4426119Swnj 			ptcwakeup(tp);
4436119Swnj 		}
4446119Swnj 	} else {
4456119Swnj 		if (stop == 0) {
4466119Swnj 			pti->pt_send &= ~TIOCPKT_DOSTOP;
4476119Swnj 			pti->pt_send |= TIOCPKT_NOSTOP;
4486119Swnj 			pti->pt_flags |= PF_NOSTOP;
4496119Swnj 			ptcwakeup(tp);
4506119Swnj 		}
4516119Swnj 	}
4526119Swnj 	}
4532281Stoy }
4542313Stoy #endif
455