xref: /csrg-svn/sys/kern/tty_pty.c (revision 5427)
1*5427Swnj /*	tty_pty.c	4.14	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 {
31*5427Swnj 	int	pt_flags;
32*5427Swnj 	int	pt_gensym;
33*5427Swnj 	struct	proc *pt_selr, *pt_selw;
34*5427Swnj 	int	pt_send;
354484Swnj } pt_ioctl[NPTY];
362281Stoy 
37*5427Swnj #define	PF_RCOLL	0x01
38*5427Swnj #define	PF_WCOLL	0x02
39*5427Swnj #define	PF_NBIO		0x04
40*5427Swnj #define	PF_PKT		0x08		/* packet mode */
41*5427Swnj #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 &&
90*5427Swnj 		    (pti = &pt_ioctl[minor(tp->t_dev)])->pt_selw) {
91*5427Swnj 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
92*5427Swnj 			pti->pt_selw = 0;
93*5427Swnj 			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 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1214484Swnj 
1225408Swnj 	if (tp->t_state & TS_TTSTOP)
1232281Stoy 		return;
124*5427Swnj 	if (pti->pt_selr) {
125*5427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
126*5427Swnj 		pti->pt_selr = 0;
127*5427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1284484Swnj 	}
1292281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1302281Stoy }
1312281Stoy 
1322281Stoy /*ARGSUSED*/
1332281Stoy ptcopen(dev, flag)
1344484Swnj 	dev_t dev;
1354484Swnj 	int flag;
1364484Swnj {
1372281Stoy 	register struct tty *tp;
138*5427Swnj 	struct pt_ioctl *pti;
1392281Stoy 
1404484Swnj 	if (minor(dev) >= NPTY) {
1412281Stoy 		u.u_error = ENXIO;
1422281Stoy 		return;
1432281Stoy 	}
1442281Stoy 	tp = &pt_tty[minor(dev)];
1454484Swnj 	if (tp->t_oproc) {
1462281Stoy 		u.u_error = EIO;
1472281Stoy 		return;
1482281Stoy 	}
1494484Swnj 	tp->t_oproc = ptsstart;
1505408Swnj 	if (tp->t_state & TS_WOPEN)
1512281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1525408Swnj 	tp->t_state |= TS_CARR_ON;
153*5427Swnj 	pti = &pt_ioctl[minor(dev)];
154*5427Swnj 	pti->pt_flags = 0;
155*5427Swnj 	pti->pt_send = 0;
1562281Stoy }
1572281Stoy 
1582281Stoy ptcclose(dev)
1594484Swnj 	dev_t dev;
1604484Swnj {
1612281Stoy 	register struct tty *tp;
1622281Stoy 
1632281Stoy 	tp = &pt_tty[minor(dev)];
1645408Swnj 	if (tp->t_state & TS_ISOPEN)
1652281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
1665408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
1674484Swnj 	flushtty(tp, FREAD|FWRITE);
1684484Swnj 	tp->t_oproc = 0;		/* mark closed */
1692281Stoy }
1702281Stoy 
1712281Stoy ptcread(dev)
172*5427Swnj 	dev_t dev;
1734484Swnj {
1742281Stoy 	register struct tty *tp;
175*5427Swnj 	struct pt_ioctl *pti;
1762281Stoy 
1772281Stoy 	tp = &pt_tty[minor(dev)];
1785408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
1792281Stoy 		return;
180*5427Swnj 	pti = &pt_ioctl[minor(dev)];
181*5427Swnj 	if (pti->pt_flags & PF_PKT) {
182*5427Swnj 		if (pti->pt_send) {
183*5427Swnj 			passc(pti->pt_send);
184*5427Swnj 			pti->pt_send = 0;
185*5427Swnj 			return;
186*5427Swnj 		}
187*5427Swnj 		passc(0);
188*5427Swnj 	}
1895411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
190*5427Swnj 		if (pti->pt_flags&PF_NBIO) {
1915411Swnj 			u.u_error = EWOULDBLOCK;
1925411Swnj 			return;
1935411Swnj 		}
1942281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
1955411Swnj 	}
1965408Swnj 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
1975408Swnj 		;
1985408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
1995408Swnj 		if (tp->t_state&TS_ASLEEP) {
2005408Swnj 			tp->t_state &= ~TS_ASLEEP;
2015408Swnj 			wakeup((caddr_t)&tp->t_outq);
2025408Swnj 		}
2035408Swnj 		if (tp->t_wsel) {
2045408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2055408Swnj 			tp->t_wsel = 0;
2065408Swnj 			tp->t_state &= ~TS_WCOLL;
2075408Swnj 		}
2082281Stoy 	}
2092281Stoy }
2102281Stoy 
211*5427Swnj ptsstop(tp, flush)
212*5427Swnj 	register struct tty *tp;
213*5427Swnj 	int flush;
214*5427Swnj {
215*5427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
216*5427Swnj 
217*5427Swnj 	if (flush == 0)
218*5427Swnj 		return;
219*5427Swnj 	pti->pt_send |= TIOCPKT_FLUSH;
220*5427Swnj 	ptsstart(tp);
221*5427Swnj }
222*5427Swnj 
2235408Swnj ptcselect(dev, rw)
2244484Swnj 	dev_t dev;
2255408Swnj 	int rw;
2264484Swnj {
2274484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2284484Swnj 	struct pt_ioctl *pti;
2294484Swnj 	struct proc *p;
2304484Swnj 
2315408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2324484Swnj 		return (1);
2335408Swnj 	switch (rw) {
2345408Swnj 
2355408Swnj 	case FREAD:
2365408Swnj 		if (tp->t_outq.c_cc)
2375408Swnj 			return (1);
2385408Swnj 		pti = &pt_ioctl[minor(dev)];
239*5427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
240*5427Swnj 			pti->pt_flags |= PF_RCOLL;
2415408Swnj 		else
242*5427Swnj 			pti->pt_selr = u.u_procp;
2435408Swnj 		return (0);
2445408Swnj 
2455408Swnj 	case FWRITE:
2465408Swnj 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2)
2475408Swnj 			return (1);
2485408Swnj 		pti = &pt_ioctl[minor(dev)];
249*5427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
250*5427Swnj 			pti->pt_flags |= PF_WCOLL;
2515408Swnj 		else
252*5427Swnj 			pti->pt_selw = u.u_procp;
2535408Swnj 	}
2545396Sroot }
2554484Swnj 
2562281Stoy ptcwrite(dev)
2575408Swnj 	dev_t dev;
2584484Swnj {
2592281Stoy 	register struct tty *tp;
2602281Stoy 	register char *cp, *ce;
2612281Stoy 	register int cc;
2622281Stoy 	char locbuf[BUFSIZ];
2635408Swnj 	int cnt = 0;
2642281Stoy 
2652281Stoy 	tp = &pt_tty[minor(dev)];
2665408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2672281Stoy 		return;
2684484Swnj 	while (u.u_count) {
2692281Stoy 		cc = MIN(u.u_count, BUFSIZ);
2702281Stoy 		cp = locbuf;
2712281Stoy 		iomove(cp, (unsigned)cc, B_WRITE);
2724484Swnj 		if (u.u_error)
2732281Stoy 			break;
2742281Stoy 		ce = cp + cc;
2754484Swnj 		while (cp < ce) {
2764484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
2772281Stoy 				wakeup((caddr_t)&tp->t_rawq);
2785408Swnj 				if (tp->t_state & TS_NBIO) {
2795408Swnj 					u.u_count += ce - cp;
2805408Swnj 					if (cnt == 0)
2815408Swnj 						u.u_error = EWOULDBLOCK;
2825408Swnj 					return;
2835408Swnj 				}
2842281Stoy 				/* Better than just flushing it! */
2852281Stoy 				/* Wait for something to be read */
2862281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
2872281Stoy 			}
2884141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
2895408Swnj 			cnt++;
2902281Stoy 		}
2912281Stoy 	}
2922281Stoy }
2932281Stoy 
2942281Stoy /*ARGSUSED*/
2952281Stoy ptyioctl(dev, cmd, addr, flag)
2964484Swnj 	caddr_t addr;
2974484Swnj 	dev_t dev;
2984484Swnj {
2992281Stoy 	register struct tty *tp;
3002281Stoy 
3012281Stoy 	tp = &pt_tty[minor(dev)];
3024484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
3035411Swnj 	if (cdevsw[major(dev)].d_open == ptcopen) {
304*5427Swnj 		register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
305*5427Swnj 		if (cmd == TIOCPKT) {
306*5427Swnj 			int packet;
307*5427Swnj 			if (copyin((caddr_t)addr, &packet, sizeof (packet))) {
308*5427Swnj 				u.u_error = EFAULT;
309*5427Swnj 				return;
310*5427Swnj 			}
311*5427Swnj 			if (packet)
312*5427Swnj 				pti->pt_flags |= PF_PKT;
313*5427Swnj 			else
314*5427Swnj 				pti->pt_flags &= ~PF_PKT;
315*5427Swnj 			return;
316*5427Swnj 		}
3175411Swnj 		if (cmd == FIONBIO) {
3185411Swnj 			int nbio;
3195411Swnj 			if (copyin(addr, &nbio, sizeof (nbio))) {
3205411Swnj 				u.u_error = EFAULT;
3215411Swnj 				return;
3225411Swnj 			}
3235411Swnj 			if (nbio)
324*5427Swnj 				pti->pt_flags |= PF_NBIO;
3255411Swnj 			else
326*5427Swnj 				pti->pt_flags &= ~PF_NBIO;
3275411Swnj 			return;
3285411Swnj 		}
3295411Swnj 		if (cmd == TIOCSETP)
3305411Swnj 			while (getc(&tp->t_outq) >= 0);
3315411Swnj 	}
3324484Swnj 	if (ttioctl(tp, cmd, addr, dev) == 0)
3332281Stoy 		u.u_error = ENOTTY;
3342281Stoy }
3352313Stoy #endif
336