xref: /csrg-svn/sys/kern/tty_pty.c (revision 35811)
123390Smckusick /*
229109Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323390Smckusick  * All rights reserved.  The Berkeley software License Agreement
423390Smckusick  * specifies the terms and conditions for redistribution.
523390Smckusick  *
6*35811Smarc  *	@(#)tty_pty.c	7.4 (Berkeley) 10/18/88
723390Smckusick  */
82283Stoy 
92281Stoy /*
102281Stoy  * Pseudo-teletype Driver
112281Stoy  * (Actually two drivers, requiring two entries in 'cdevsw')
122281Stoy  */
132314Stoy #include "pty.h"
142314Stoy 
153206Swnj #if NPTY > 0
1617096Sbloom #include "param.h"
1717096Sbloom #include "systm.h"
1817096Sbloom #include "ioctl.h"
1917096Sbloom #include "tty.h"
2017096Sbloom #include "dir.h"
2117096Sbloom #include "user.h"
2217096Sbloom #include "conf.h"
2317096Sbloom #include "file.h"
2417096Sbloom #include "proc.h"
2517096Sbloom #include "uio.h"
2617096Sbloom #include "kernel.h"
276239Sroot 
287475Ssam #if NPTY == 1
2918651Sbloom #undef NPTY
306239Sroot #define	NPTY	32		/* crude XXX */
317475Ssam #endif
322281Stoy 
3316788Ssam #define BUFSIZ 100		/* Chunk size iomoved to/from user */
344484Swnj 
352281Stoy /*
3618651Sbloom  * pts == /dev/tty[pqrs]?
3718651Sbloom  * ptc == /dev/pty[pqrs]?
382281Stoy  */
394484Swnj struct	tty pt_tty[NPTY];
404484Swnj struct	pt_ioctl {
415427Swnj 	int	pt_flags;
425427Swnj 	struct	proc *pt_selr, *pt_selw;
4318651Sbloom 	u_char	pt_send;
4418651Sbloom 	u_char	pt_ucntl;
454484Swnj } pt_ioctl[NPTY];
4618651Sbloom int	npty = NPTY;		/* for pstat -t */
472281Stoy 
48*35811Smarc #define	PF_RCOLL	0x01
49*35811Smarc #define	PF_WCOLL	0x02
50*35811Smarc #define	PF_NBIO		0x04
51*35811Smarc #define	PF_PKT		0x08		/* packet mode */
52*35811Smarc #define	PF_STOPPED	0x10		/* user told stopped */
53*35811Smarc #define	PF_REMOTE	0x20		/* remote and flow controlled input */
54*35811Smarc #define	PF_NOSTOP	0x40
55*35811Smarc #define PF_UCNTL	0x80		/* user control mode */
562281Stoy 
572281Stoy /*ARGSUSED*/
582281Stoy ptsopen(dev, flag)
595396Sroot 	dev_t dev;
604484Swnj {
612281Stoy 	register struct tty *tp;
6218651Sbloom 	int error;
632281Stoy 
6418651Sbloom #ifdef lint
6518651Sbloom 	npty = npty;
6618651Sbloom #endif
678563Sroot 	if (minor(dev) >= NPTY)
688563Sroot 		return (ENXIO);
692281Stoy 	tp = &pt_tty[minor(dev)];
705408Swnj 	if ((tp->t_state & TS_ISOPEN) == 0) {
712427Swnj 		ttychars(tp);		/* Set up default chars */
72*35811Smarc 		tp->t_iflag = TTYDEF_IFLAG;
73*35811Smarc 		tp->t_oflag = TTYDEF_OFLAG;
74*35811Smarc 		tp->t_lflag = TTYDEF_LFLAG;
75*35811Smarc 		tp->t_cflag = TTYDEF_CFLAG;
76*35811Smarc 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
77*35811Smarc 		ttsetwater(tp);		/* would be done in xxparam() */
788563Sroot 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
798563Sroot 		return (EBUSY);
804484Swnj 	if (tp->t_oproc)			/* Ctrlr still around. */
815408Swnj 		tp->t_state |= TS_CARR_ON;
825408Swnj 	while ((tp->t_state & TS_CARR_ON) == 0) {
835408Swnj 		tp->t_state |= TS_WOPEN;
842281Stoy 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
852281Stoy 	}
8618651Sbloom 	error = (*linesw[tp->t_line].l_open)(dev, tp);
8718651Sbloom 	ptcwakeup(tp, FREAD|FWRITE);
8818651Sbloom 	return (error);
892281Stoy }
902281Stoy 
912281Stoy ptsclose(dev)
925396Sroot 	dev_t dev;
935408Swnj {
942281Stoy 	register struct tty *tp;
952281Stoy 
962281Stoy 	tp = &pt_tty[minor(dev)];
972281Stoy 	(*linesw[tp->t_line].l_close)(tp);
986299Swnj 	ttyclose(tp);
9918651Sbloom 	ptcwakeup(tp, FREAD|FWRITE);
1002281Stoy }
1012281Stoy 
1027823Sroot ptsread(dev, uio)
1035396Sroot 	dev_t dev;
1047823Sroot 	struct uio *uio;
1054484Swnj {
1065894Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
1075894Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
1088521Sroot 	int error = 0;
1092281Stoy 
1105894Swnj again:
1115894Swnj 	if (pti->pt_flags & PF_REMOTE) {
112*35811Smarc 		while (tp == u.u_ttyp &&
113*35811Smarc 		       u.u_procp->p_pgrp->pg_id != tp->t_pgid){
11418651Sbloom 			if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
11518651Sbloom 			    (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
116*35811Smarc 			    !u.u_procp->p_pgrp->pg_jobc ||
1175894Swnj 			    u.u_procp->p_flag&SVFORK)
1188521Sroot 				return (EIO);
119*35811Smarc 			pgsignal(u.u_procp->p_pgrp, SIGTTIN);
1205894Swnj 			sleep((caddr_t)&lbolt, TTIPRI);
1215408Swnj 		}
12218651Sbloom 		if (tp->t_canq.c_cc == 0) {
1238521Sroot 			if (tp->t_state & TS_NBIO)
1248521Sroot 				return (EWOULDBLOCK);
12518651Sbloom 			sleep((caddr_t)&tp->t_canq, TTIPRI);
1265894Swnj 			goto again;
1275894Swnj 		}
12818651Sbloom 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
12918651Sbloom 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
1308521Sroot 				error = EFAULT;
1317823Sroot 				break;
1327823Sroot 			}
13318651Sbloom 		if (tp->t_canq.c_cc == 1)
13418651Sbloom 			(void) getc(&tp->t_canq);
13518651Sbloom 		if (tp->t_canq.c_cc)
1368521Sroot 			return (error);
1375894Swnj 	} else
1385894Swnj 		if (tp->t_oproc)
1398521Sroot 			error = (*linesw[tp->t_line].l_read)(tp, uio);
14018651Sbloom 	ptcwakeup(tp, FWRITE);
1418521Sroot 	return (error);
1422281Stoy }
1432281Stoy 
1445408Swnj /*
1455408Swnj  * Write to pseudo-tty.
1465408Swnj  * Wakeups of controlling tty will happen
1475408Swnj  * indirectly, when tty driver calls ptsstart.
1485408Swnj  */
1497823Sroot ptswrite(dev, uio)
1505396Sroot 	dev_t dev;
1517823Sroot 	struct uio *uio;
1524484Swnj {
153*35811Smarc 	register struct tty *tp;
1542281Stoy 
155*35811Smarc 	tp = &pt_tty[minor(dev)];
1568521Sroot 	if (tp->t_oproc == 0)
1578521Sroot 		return (EIO);
1588521Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
1592281Stoy }
1602281Stoy 
1615408Swnj /*
1625408Swnj  * Start output on pseudo-tty.
1635408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1645408Swnj  */
1652281Stoy ptsstart(tp)
1664484Swnj 	struct tty *tp;
1674484Swnj {
1685574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1694484Swnj 
1705408Swnj 	if (tp->t_state & TS_TTSTOP)
1712281Stoy 		return;
1725574Swnj 	if (pti->pt_flags & PF_STOPPED) {
1735574Swnj 		pti->pt_flags &= ~PF_STOPPED;
1745574Swnj 		pti->pt_send = TIOCPKT_START;
1755574Swnj 	}
17618651Sbloom 	ptcwakeup(tp, FREAD);
1775430Swnj }
1785430Swnj 
17918651Sbloom ptcwakeup(tp, flag)
1805430Swnj 	struct tty *tp;
1815430Swnj {
1825430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1835430Swnj 
18418651Sbloom 	if (flag & FREAD) {
18518651Sbloom 		if (pti->pt_selr) {
18618651Sbloom 			selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
18718651Sbloom 			pti->pt_selr = 0;
18818651Sbloom 			pti->pt_flags &= ~PF_RCOLL;
18918651Sbloom 		}
19018651Sbloom 		wakeup((caddr_t)&tp->t_outq.c_cf);
1914484Swnj 	}
19218651Sbloom 	if (flag & FWRITE) {
19318651Sbloom 		if (pti->pt_selw) {
19418651Sbloom 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
19518651Sbloom 			pti->pt_selw = 0;
19618651Sbloom 			pti->pt_flags &= ~PF_WCOLL;
19718651Sbloom 		}
19818651Sbloom 		wakeup((caddr_t)&tp->t_rawq.c_cf);
19918651Sbloom 	}
2002281Stoy }
2012281Stoy 
2022281Stoy /*ARGSUSED*/
2032281Stoy ptcopen(dev, flag)
2044484Swnj 	dev_t dev;
2054484Swnj 	int flag;
2064484Swnj {
2072281Stoy 	register struct tty *tp;
2085427Swnj 	struct pt_ioctl *pti;
2092281Stoy 
2108563Sroot 	if (minor(dev) >= NPTY)
2118563Sroot 		return (ENXIO);
2122281Stoy 	tp = &pt_tty[minor(dev)];
2138563Sroot 	if (tp->t_oproc)
2148563Sroot 		return (EIO);
2154484Swnj 	tp->t_oproc = ptsstart;
21625390Skarels 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
2175427Swnj 	pti = &pt_ioctl[minor(dev)];
2185427Swnj 	pti->pt_flags = 0;
2195427Swnj 	pti->pt_send = 0;
22018651Sbloom 	pti->pt_ucntl = 0;
2218563Sroot 	return (0);
2222281Stoy }
2232281Stoy 
2242281Stoy ptcclose(dev)
2254484Swnj 	dev_t dev;
2264484Swnj {
2272281Stoy 	register struct tty *tp;
2282281Stoy 
2292281Stoy 	tp = &pt_tty[minor(dev)];
23025390Skarels 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
23132326Skarels 	tp->t_state &= ~TS_CARR_ON;
2324484Swnj 	tp->t_oproc = 0;		/* mark closed */
2332281Stoy }
2342281Stoy 
2357823Sroot ptcread(dev, uio)
2365427Swnj 	dev_t dev;
2377823Sroot 	struct uio *uio;
2384484Swnj {
2398521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
24018651Sbloom 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
24116788Ssam 	char buf[BUFSIZ];
24216788Ssam 	int error = 0, cc;
2432281Stoy 
24418651Sbloom 	/*
24518651Sbloom 	 * We want to block until the slave
24618651Sbloom 	 * is open, and there's something to read;
24718651Sbloom 	 * but if we lost the slave or we're NBIO,
24818651Sbloom 	 * then return the appropriate error instead.
24918651Sbloom 	 */
25018651Sbloom 	for (;;) {
25118651Sbloom 		if (tp->t_state&TS_ISOPEN) {
25218651Sbloom 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
25326358Skarels 				error = ureadc((int)pti->pt_send, uio);
25418651Sbloom 				if (error)
25518651Sbloom 					return (error);
25618651Sbloom 				pti->pt_send = 0;
25718651Sbloom 				return (0);
25818651Sbloom 			}
25918651Sbloom 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
26026358Skarels 				error = ureadc((int)pti->pt_ucntl, uio);
26118651Sbloom 				if (error)
26218651Sbloom 					return (error);
26318651Sbloom 				pti->pt_ucntl = 0;
26418651Sbloom 				return (0);
26518651Sbloom 			}
26618651Sbloom 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
26718651Sbloom 				break;
2685427Swnj 		}
26916788Ssam 		if ((tp->t_state&TS_CARR_ON) == 0)
27016788Ssam 			return (EIO);
2718521Sroot 		if (pti->pt_flags&PF_NBIO)
2728521Sroot 			return (EWOULDBLOCK);
2732281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2745411Swnj 	}
275*35811Smarc 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
27618651Sbloom 		error = ureadc(0, uio);
27716788Ssam 	while (uio->uio_resid > 0 && error == 0) {
27816788Ssam 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
27916788Ssam 		if (cc <= 0)
2807823Sroot 			break;
28116788Ssam 		error = uiomove(buf, cc, UIO_READ, uio);
28216788Ssam 	}
283*35811Smarc 	if (tp->t_outq.c_cc <= tp->t_lowat) {
284*35811Smarc 		if (tp->t_state&TS_ASLEEP) {
285*35811Smarc 			tp->t_state &= ~TS_ASLEEP;
286*35811Smarc 			wakeup((caddr_t)&tp->t_outq);
287*35811Smarc 		}
288*35811Smarc 		if (tp->t_wsel) {
289*35811Smarc 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
290*35811Smarc 			tp->t_wsel = 0;
291*35811Smarc 			tp->t_state &= ~TS_WCOLL;
292*35811Smarc 		}
293*35811Smarc 	}
2948521Sroot 	return (error);
2952281Stoy }
2962281Stoy 
2975427Swnj ptsstop(tp, flush)
2985427Swnj 	register struct tty *tp;
2995427Swnj 	int flush;
3005427Swnj {
3015427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
30218651Sbloom 	int flag;
3035427Swnj 
3045574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
3055574Swnj 	if (flush == 0) {
3065574Swnj 		flush = TIOCPKT_STOP;
3075574Swnj 		pti->pt_flags |= PF_STOPPED;
30818651Sbloom 	} else
3095574Swnj 		pti->pt_flags &= ~PF_STOPPED;
3106119Swnj 	pti->pt_send |= flush;
31118651Sbloom 	/* change of perspective */
31218651Sbloom 	flag = 0;
31318651Sbloom 	if (flush & FREAD)
31418651Sbloom 		flag |= FWRITE;
31518651Sbloom 	if (flush & FWRITE)
31618651Sbloom 		flag |= FREAD;
31723633Sbloom 	ptcwakeup(tp, flag);
3185427Swnj }
3195427Swnj 
3205408Swnj ptcselect(dev, rw)
3214484Swnj 	dev_t dev;
3225408Swnj 	int rw;
3234484Swnj {
3244484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
3255894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3264484Swnj 	struct proc *p;
3275430Swnj 	int s;
3284484Swnj 
32918651Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
3304484Swnj 		return (1);
3315408Swnj 	switch (rw) {
3325408Swnj 
3335408Swnj 	case FREAD:
33425945Skarels 		/*
33525945Skarels 		 * Need to block timeouts (ttrstart).
33625945Skarels 		 */
33725945Skarels 		s = spltty();
33818651Sbloom 		if ((tp->t_state&TS_ISOPEN) &&
33925436Skarels 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
34025436Skarels 			splx(s);
34125436Skarels 			return (1);
34225436Skarels 		}
34325945Skarels 		splx(s);
34425436Skarels 		/* FALLTHROUGH */
34525436Skarels 
34625436Skarels 	case 0:					/* exceptional */
34725436Skarels 		if ((tp->t_state&TS_ISOPEN) &&
34818651Sbloom 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
34925945Skarels 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
3505408Swnj 			return (1);
3515427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
3525427Swnj 			pti->pt_flags |= PF_RCOLL;
3535408Swnj 		else
3545427Swnj 			pti->pt_selr = u.u_procp;
3555430Swnj 		break;
3565408Swnj 
35725436Skarels 
3585408Swnj 	case FWRITE:
35925945Skarels 		if (tp->t_state&TS_ISOPEN) {
36025945Skarels 			if (pti->pt_flags & PF_REMOTE) {
36125945Skarels 			    if (tp->t_canq.c_cc == 0)
36225945Skarels 				return (1);
36325945Skarels 			} else {
36425945Skarels 			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
36525945Skarels 				    return (1);
366*35811Smarc 			    if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
36725945Skarels 				    return (1);
36825945Skarels 			}
3695430Swnj 		}
3705427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
3715427Swnj 			pti->pt_flags |= PF_WCOLL;
3725408Swnj 		else
3735427Swnj 			pti->pt_selw = u.u_procp;
3745430Swnj 		break;
37525436Skarels 
3765408Swnj 	}
3775430Swnj 	return (0);
3785396Sroot }
3794484Swnj 
3807823Sroot ptcwrite(dev, uio)
3815408Swnj 	dev_t dev;
38218651Sbloom 	register struct uio *uio;
3834484Swnj {
3848521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
38518651Sbloom 	register struct iovec *iov;
38618651Sbloom 	register char *cp;
38718651Sbloom 	register int cc = 0;
3882281Stoy 	char locbuf[BUFSIZ];
3895408Swnj 	int cnt = 0;
3905894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3918521Sroot 	int error = 0;
3922281Stoy 
39318651Sbloom again:
39418651Sbloom 	if ((tp->t_state&TS_ISOPEN) == 0)
39518651Sbloom 		goto block;
39623633Sbloom 	if (pti->pt_flags & PF_REMOTE) {
39718651Sbloom 		if (tp->t_canq.c_cc)
39818651Sbloom 			goto block;
39923633Sbloom 		while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
40023633Sbloom 			iov = uio->uio_iov;
40123633Sbloom 			if (iov->iov_len == 0) {
40223633Sbloom 				uio->uio_iovcnt--;
40323633Sbloom 				uio->uio_iov++;
40423633Sbloom 				continue;
40523633Sbloom 			}
40623633Sbloom 			if (cc == 0) {
40723633Sbloom 				cc = MIN(iov->iov_len, BUFSIZ);
40823633Sbloom 				cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
40923633Sbloom 				cp = locbuf;
41023633Sbloom 				error = uiomove(cp, cc, UIO_WRITE, uio);
41123633Sbloom 				if (error)
41223633Sbloom 					return (error);
41323633Sbloom 				/* check again for safety */
41423633Sbloom 				if ((tp->t_state&TS_ISOPEN) == 0)
41523633Sbloom 					return (EIO);
41623633Sbloom 			}
41723633Sbloom 			if (cc)
41823633Sbloom 				(void) b_to_q(cp, cc, &tp->t_canq);
41923633Sbloom 			cc = 0;
4207823Sroot 		}
42118651Sbloom 		(void) putc(0, &tp->t_canq);
42218651Sbloom 		ttwakeup(tp);
42318651Sbloom 		wakeup((caddr_t)&tp->t_canq);
42418651Sbloom 		return (0);
42518651Sbloom 	}
42618651Sbloom 	while (uio->uio_iovcnt > 0) {
42718651Sbloom 		iov = uio->uio_iov;
42818651Sbloom 		if (cc == 0) {
42918651Sbloom 			if (iov->iov_len == 0) {
43018651Sbloom 				uio->uio_iovcnt--;
43118651Sbloom 				uio->uio_iov++;
43218651Sbloom 				continue;
4335894Swnj 			}
43418651Sbloom 			cc = MIN(iov->iov_len, BUFSIZ);
43518651Sbloom 			cp = locbuf;
43618651Sbloom 			error = uiomove(cp, cc, UIO_WRITE, uio);
43718651Sbloom 			if (error)
43818651Sbloom 				return (error);
43918651Sbloom 			/* check again for safety */
44018651Sbloom 			if ((tp->t_state&TS_ISOPEN) == 0)
44118651Sbloom 				return (EIO);
4425894Swnj 		}
44323633Sbloom 		while (cc > 0) {
44423633Sbloom 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
445*35811Smarc 			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
44623633Sbloom 				wakeup((caddr_t)&tp->t_rawq);
44723633Sbloom 				goto block;
44823633Sbloom 			}
4494141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
4505408Swnj 			cnt++;
45123633Sbloom 			cc--;
4522281Stoy 		}
45318651Sbloom 		cc = 0;
45418651Sbloom 	}
45518651Sbloom 	return (0);
45618651Sbloom block:
45718651Sbloom 	/*
45823633Sbloom 	 * Come here to wait for slave to open, for space
45923633Sbloom 	 * in outq, or space in rawq.
46018651Sbloom 	 */
46118651Sbloom 	if ((tp->t_state&TS_CARR_ON) == 0)
46218651Sbloom 		return (EIO);
46318651Sbloom 	if (pti->pt_flags & PF_NBIO) {
46418651Sbloom 		iov->iov_base -= cc;
46518651Sbloom 		iov->iov_len += cc;
46618651Sbloom 		uio->uio_resid += cc;
46718651Sbloom 		uio->uio_offset -= cc;
46823633Sbloom 		if (cnt == 0)
46923633Sbloom 			return (EWOULDBLOCK);
47018651Sbloom 		return (0);
47118651Sbloom 	}
47218651Sbloom 	sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
47318651Sbloom 	goto again;
4742281Stoy }
4752281Stoy 
4762281Stoy /*ARGSUSED*/
4777626Ssam ptyioctl(dev, cmd, data, flag)
4787626Ssam 	caddr_t data;
4794484Swnj 	dev_t dev;
4804484Swnj {
4816119Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
4826119Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
483*35811Smarc 	register u_char *cc = tp->t_cc;
48418651Sbloom 	int stop, error;
48525390Skarels 	extern ttyinput();
4862281Stoy 
48725390Skarels 	/*
48825390Skarels 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
48925390Skarels 	 * ttywflush(tp) will hang if there are characters in the outq.
49025390Skarels 	 */
491*35811Smarc 	if (cdevsw[major(dev)].d_open == ptcopen)
4927626Ssam 		switch (cmd) {
4937626Ssam 
4947626Ssam 		case TIOCPKT:
49518651Sbloom 			if (*(int *)data) {
49618651Sbloom 				if (pti->pt_flags & PF_UCNTL)
49718651Sbloom 					return (EINVAL);
4985427Swnj 				pti->pt_flags |= PF_PKT;
49918651Sbloom 			} else
5005427Swnj 				pti->pt_flags &= ~PF_PKT;
5018563Sroot 			return (0);
5027626Ssam 
50318651Sbloom 		case TIOCUCNTL:
50418651Sbloom 			if (*(int *)data) {
50518651Sbloom 				if (pti->pt_flags & PF_PKT)
50618651Sbloom 					return (EINVAL);
50718651Sbloom 				pti->pt_flags |= PF_UCNTL;
50818651Sbloom 			} else
50918651Sbloom 				pti->pt_flags &= ~PF_UCNTL;
51018651Sbloom 			return (0);
51118651Sbloom 
5127626Ssam 		case TIOCREMOTE:
5137626Ssam 			if (*(int *)data)
5145894Swnj 				pti->pt_flags |= PF_REMOTE;
5155894Swnj 			else
5165894Swnj 				pti->pt_flags &= ~PF_REMOTE;
51712753Ssam 			ttyflush(tp, FREAD|FWRITE);
5188563Sroot 			return (0);
5197626Ssam 
5207626Ssam 		case FIONBIO:
5217626Ssam 			if (*(int *)data)
5225427Swnj 				pti->pt_flags |= PF_NBIO;
5235411Swnj 			else
5245427Swnj 				pti->pt_flags &= ~PF_NBIO;
5258563Sroot 			return (0);
5267626Ssam 
527*35811Smarc 		case TIOCSETP:
52825390Skarels 		case TIOCSETN:
52925390Skarels 		case TIOCSETD:
530*35811Smarc 		case TIOCSETA:
531*35811Smarc 		case TIOCSETAW:
532*35811Smarc 		case TIOCSETAF:
533*35811Smarc 		case TIOCSETAS:
534*35811Smarc 		case TIOCSETAWS:
535*35811Smarc 		case TIOCSETAFS:
5367626Ssam 			while (getc(&tp->t_outq) >= 0)
5377626Ssam 				;
5387626Ssam 			break;
5395411Swnj 		}
540*35811Smarc 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
541*35811Smarc 	if (error < 0)
542*35811Smarc 		 error = ttioctl(tp, cmd, data, flag);
54325390Skarels 	/*
54425390Skarels 	 * Since we use the tty queues internally,
54525390Skarels 	 * pty's can't be switched to disciplines which overwrite
54625390Skarels 	 * the queues.  We can't tell anything about the discipline
54725390Skarels 	 * from here...
54825390Skarels 	 */
54925390Skarels 	if (linesw[tp->t_line].l_rint != ttyinput) {
55025390Skarels 		(*linesw[tp->t_line].l_close)(tp);
55125390Skarels 		tp->t_line = 0;
55225390Skarels 		(void)(*linesw[tp->t_line].l_open)(dev, tp);
55325390Skarels 		error = ENOTTY;
55425390Skarels 	}
55518651Sbloom 	if (error < 0) {
55618651Sbloom 		if (pti->pt_flags & PF_UCNTL &&
55728285Skarels 		    (cmd & ~0xff) == UIOCCMD(0)) {
55818651Sbloom 			if (cmd & 0xff) {
55918651Sbloom 				pti->pt_ucntl = (u_char)cmd;
56018651Sbloom 				ptcwakeup(tp, FREAD);
56118651Sbloom 			}
56218651Sbloom 			return (0);
56318651Sbloom 		}
5648563Sroot 		error = ENOTTY;
56518651Sbloom 	}
566*35811Smarc 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
567*35811Smarc 		&& CCEQ(cc[VSTART], CTRL('q'));
5686119Swnj 	if (pti->pt_flags & PF_NOSTOP) {
5696119Swnj 		if (stop) {
57025478Skarels 			pti->pt_send &= ~TIOCPKT_NOSTOP;
5716119Swnj 			pti->pt_send |= TIOCPKT_DOSTOP;
5726119Swnj 			pti->pt_flags &= ~PF_NOSTOP;
57318651Sbloom 			ptcwakeup(tp, FREAD);
5746119Swnj 		}
5756119Swnj 	} else {
57618651Sbloom 		if (!stop) {
5776119Swnj 			pti->pt_send &= ~TIOCPKT_DOSTOP;
5786119Swnj 			pti->pt_send |= TIOCPKT_NOSTOP;
5796119Swnj 			pti->pt_flags |= PF_NOSTOP;
58018651Sbloom 			ptcwakeup(tp, FREAD);
5816119Swnj 		}
5826119Swnj 	}
5838563Sroot 	return (error);
5842281Stoy }
5852313Stoy #endif
586