xref: /csrg-svn/sys/kern/tty_pty.c (revision 5574)
1*5574Swnj /*	tty_pty.c	4.16	82/01/19	*/
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 {
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 */
41*5574Swnj #define	PF_STOPPED	0x10		/* user told stopped */
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 &&
905427Swnj 		    (pti = &pt_ioctl[minor(tp->t_dev)])->pt_selw) {
915427Swnj 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
925427Swnj 			pti->pt_selw = 0;
935427Swnj 			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 {
120*5574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1214484Swnj 
1225408Swnj 	if (tp->t_state & TS_TTSTOP)
1232281Stoy 		return;
124*5574Swnj 	if (pti->pt_flags & PF_STOPPED) {
125*5574Swnj 		pti->pt_flags &= ~PF_STOPPED;
126*5574Swnj 		pti->pt_send = TIOCPKT_START;
127*5574Swnj 	}
1285430Swnj 	ptcwakeup(tp);
1295430Swnj }
1305430Swnj 
1315430Swnj ptcwakeup(tp)
1325430Swnj 	struct tty *tp;
1335430Swnj {
1345430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1355430Swnj 
1365427Swnj 	if (pti->pt_selr) {
1375427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
1385427Swnj 		pti->pt_selr = 0;
1395427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1404484Swnj 	}
1412281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1422281Stoy }
1432281Stoy 
1442281Stoy /*ARGSUSED*/
1452281Stoy ptcopen(dev, flag)
1464484Swnj 	dev_t dev;
1474484Swnj 	int flag;
1484484Swnj {
1492281Stoy 	register struct tty *tp;
1505427Swnj 	struct pt_ioctl *pti;
1512281Stoy 
1524484Swnj 	if (minor(dev) >= NPTY) {
1532281Stoy 		u.u_error = ENXIO;
1542281Stoy 		return;
1552281Stoy 	}
1562281Stoy 	tp = &pt_tty[minor(dev)];
1574484Swnj 	if (tp->t_oproc) {
1582281Stoy 		u.u_error = EIO;
1592281Stoy 		return;
1602281Stoy 	}
1614484Swnj 	tp->t_oproc = ptsstart;
1625408Swnj 	if (tp->t_state & TS_WOPEN)
1632281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1645408Swnj 	tp->t_state |= TS_CARR_ON;
1655427Swnj 	pti = &pt_ioctl[minor(dev)];
1665427Swnj 	pti->pt_flags = 0;
1675427Swnj 	pti->pt_send = 0;
1682281Stoy }
1692281Stoy 
1702281Stoy ptcclose(dev)
1714484Swnj 	dev_t dev;
1724484Swnj {
1732281Stoy 	register struct tty *tp;
1742281Stoy 
1752281Stoy 	tp = &pt_tty[minor(dev)];
1765408Swnj 	if (tp->t_state & TS_ISOPEN)
1772281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
1785408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
1794484Swnj 	flushtty(tp, FREAD|FWRITE);
1804484Swnj 	tp->t_oproc = 0;		/* mark closed */
1812281Stoy }
1822281Stoy 
1832281Stoy ptcread(dev)
1845427Swnj 	dev_t dev;
1854484Swnj {
1862281Stoy 	register struct tty *tp;
1875427Swnj 	struct pt_ioctl *pti;
1882281Stoy 
1892281Stoy 	tp = &pt_tty[minor(dev)];
1905408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
1912281Stoy 		return;
1925427Swnj 	pti = &pt_ioctl[minor(dev)];
1935427Swnj 	if (pti->pt_flags & PF_PKT) {
1945427Swnj 		if (pti->pt_send) {
1955427Swnj 			passc(pti->pt_send);
1965427Swnj 			pti->pt_send = 0;
1975427Swnj 			return;
1985427Swnj 		}
1995427Swnj 		passc(0);
2005427Swnj 	}
2015411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
2025427Swnj 		if (pti->pt_flags&PF_NBIO) {
2035411Swnj 			u.u_error = EWOULDBLOCK;
2045411Swnj 			return;
2055411Swnj 		}
2062281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2075411Swnj 	}
2085408Swnj 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
2095408Swnj 		;
2105408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
2115408Swnj 		if (tp->t_state&TS_ASLEEP) {
2125408Swnj 			tp->t_state &= ~TS_ASLEEP;
2135408Swnj 			wakeup((caddr_t)&tp->t_outq);
2145408Swnj 		}
2155408Swnj 		if (tp->t_wsel) {
2165408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2175408Swnj 			tp->t_wsel = 0;
2185408Swnj 			tp->t_state &= ~TS_WCOLL;
2195408Swnj 		}
2202281Stoy 	}
2212281Stoy }
2222281Stoy 
2235427Swnj ptsstop(tp, flush)
2245427Swnj 	register struct tty *tp;
2255427Swnj 	int flush;
2265427Swnj {
2275427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
2285427Swnj 
229*5574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
230*5574Swnj 	if (flush == 0) {
231*5574Swnj 		flush = TIOCPKT_STOP;
232*5574Swnj 		pti->pt_flags |= PF_STOPPED;
233*5574Swnj 	} else {
234*5574Swnj 		pti->pt_flags &= ~PF_STOPPED;
235*5574Swnj 	}
236*5574Swnj 	pti->pt_send = flush;
2375430Swnj 	ptcwakeup(tp);
2385427Swnj }
2395427Swnj 
2405408Swnj ptcselect(dev, rw)
2414484Swnj 	dev_t dev;
2425408Swnj 	int rw;
2434484Swnj {
2444484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2454484Swnj 	struct pt_ioctl *pti;
2464484Swnj 	struct proc *p;
2475430Swnj 	int s;
2484484Swnj 
2495408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2504484Swnj 		return (1);
2515430Swnj 	s = spl5();
2525408Swnj 	switch (rw) {
2535408Swnj 
2545408Swnj 	case FREAD:
2555430Swnj 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
2565430Swnj 			splx(s);
2575408Swnj 			return (1);
2585430Swnj 		}
2595408Swnj 		pti = &pt_ioctl[minor(dev)];
2605427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
2615427Swnj 			pti->pt_flags |= PF_RCOLL;
2625408Swnj 		else
2635427Swnj 			pti->pt_selr = u.u_procp;
2645430Swnj 		break;
2655408Swnj 
2665408Swnj 	case FWRITE:
2675430Swnj 		if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) {
2685430Swnj 			splx(s);
2695408Swnj 			return (1);
2705430Swnj 		}
2715408Swnj 		pti = &pt_ioctl[minor(dev)];
2725427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
2735427Swnj 			pti->pt_flags |= PF_WCOLL;
2745408Swnj 		else
2755427Swnj 			pti->pt_selw = u.u_procp;
2765430Swnj 		break;
2775408Swnj 	}
2785430Swnj 	splx(s);
2795430Swnj 	return (0);
2805396Sroot }
2814484Swnj 
2822281Stoy ptcwrite(dev)
2835408Swnj 	dev_t dev;
2844484Swnj {
2852281Stoy 	register struct tty *tp;
2862281Stoy 	register char *cp, *ce;
2872281Stoy 	register int cc;
2882281Stoy 	char locbuf[BUFSIZ];
2895408Swnj 	int cnt = 0;
2902281Stoy 
2912281Stoy 	tp = &pt_tty[minor(dev)];
2925408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2932281Stoy 		return;
2944484Swnj 	while (u.u_count) {
2952281Stoy 		cc = MIN(u.u_count, BUFSIZ);
2962281Stoy 		cp = locbuf;
2972281Stoy 		iomove(cp, (unsigned)cc, B_WRITE);
2984484Swnj 		if (u.u_error)
2992281Stoy 			break;
3002281Stoy 		ce = cp + cc;
3014484Swnj 		while (cp < ce) {
3024484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
3032281Stoy 				wakeup((caddr_t)&tp->t_rawq);
3045408Swnj 				if (tp->t_state & TS_NBIO) {
3055408Swnj 					u.u_count += ce - cp;
3065408Swnj 					if (cnt == 0)
3075408Swnj 						u.u_error = EWOULDBLOCK;
3085408Swnj 					return;
3095408Swnj 				}
3102281Stoy 				/* Better than just flushing it! */
3112281Stoy 				/* Wait for something to be read */
3122281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3132281Stoy 			}
3144141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
3155408Swnj 			cnt++;
3162281Stoy 		}
3172281Stoy 	}
3182281Stoy }
3192281Stoy 
3202281Stoy /*ARGSUSED*/
3212281Stoy ptyioctl(dev, cmd, addr, flag)
3224484Swnj 	caddr_t addr;
3234484Swnj 	dev_t dev;
3244484Swnj {
3252281Stoy 	register struct tty *tp;
3262281Stoy 
3272281Stoy 	tp = &pt_tty[minor(dev)];
3284484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
3295411Swnj 	if (cdevsw[major(dev)].d_open == ptcopen) {
3305427Swnj 		register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3315427Swnj 		if (cmd == TIOCPKT) {
3325427Swnj 			int packet;
3335427Swnj 			if (copyin((caddr_t)addr, &packet, sizeof (packet))) {
3345427Swnj 				u.u_error = EFAULT;
3355427Swnj 				return;
3365427Swnj 			}
3375427Swnj 			if (packet)
3385427Swnj 				pti->pt_flags |= PF_PKT;
3395427Swnj 			else
3405427Swnj 				pti->pt_flags &= ~PF_PKT;
3415427Swnj 			return;
3425427Swnj 		}
3435411Swnj 		if (cmd == FIONBIO) {
3445411Swnj 			int nbio;
3455411Swnj 			if (copyin(addr, &nbio, sizeof (nbio))) {
3465411Swnj 				u.u_error = EFAULT;
3475411Swnj 				return;
3485411Swnj 			}
3495411Swnj 			if (nbio)
3505427Swnj 				pti->pt_flags |= PF_NBIO;
3515411Swnj 			else
3525427Swnj 				pti->pt_flags &= ~PF_NBIO;
3535411Swnj 			return;
3545411Swnj 		}
3555411Swnj 		if (cmd == TIOCSETP)
3565411Swnj 			while (getc(&tp->t_outq) >= 0);
3575411Swnj 	}
3584484Swnj 	if (ttioctl(tp, cmd, addr, dev) == 0)
3592281Stoy 		u.u_error = ENOTTY;
3602281Stoy }
3612313Stoy #endif
362