pty.c revision 9639
121308Sache/*
221308Sache * Copyright (c) 1982, 1986, 1989, 1993
321308Sache *	The Regents of the University of California.  All rights reserved.
421308Sache *
521308Sache * Redistribution and use in source and binary forms, with or without
621308Sache * modification, are permitted provided that the following conditions
721308Sache * are met:
821308Sache * 1. Redistributions of source code must retain the above copyright
921308Sache *    notice, this list of conditions and the following disclaimer.
1058314Sache * 2. Redistributions in binary form must reproduce the above copyright
1121308Sache *    notice, this list of conditions and the following disclaimer in the
1221308Sache *    documentation and/or other materials provided with the distribution.
1321308Sache * 3. All advertising materials mentioning features or use of this software
1421308Sache *    must display the following acknowledgement:
1521308Sache *	This product includes software developed by the University of
1621308Sache *	California, Berkeley and its contributors.
1721308Sache * 4. Neither the name of the University nor the names of its contributors
1821308Sache *    may be used to endorse or promote products derived from this software
1921308Sache *    without specific prior written permission.
2021308Sache *
2158314Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22119614Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2321308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2421308Sache * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2521308Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2621308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2721308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2821308Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2921308Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3021308Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3121308Sache * SUCH DAMAGE.
3221308Sache *
3321308Sache *	@(#)tty_pty.c	8.2 (Berkeley) 9/23/93
3421308Sache * $Id: tty_pty.c,v 1.14 1995/07/22 01:30:32 bde Exp $
3521308Sache */
3621308Sache
3721308Sache/*
3821308Sache * Pseudo-teletype Driver
3921308Sache * (Actually two drivers, requiring two entries in 'cdevsw')
4021308Sache */
4121308Sache#include "pty.h"		/* XXX */
4221308Sache
4321308Sache#include <sys/param.h>
4421308Sache#include <sys/systm.h>
4521308Sache#include <sys/ioctl.h>
4621308Sache#include <sys/proc.h>
4721308Sache#include <sys/tty.h>
4821308Sache#include <sys/conf.h>
4921308Sache#include <sys/file.h>
5021308Sache#include <sys/uio.h>
5121308Sache#include <sys/kernel.h>
5221308Sache#include <sys/vnode.h>
5321308Sache#include <sys/signalvar.h>
5421308Sache
5526497Sache#if NPTY == 1
5626497Sache#undef NPTY
5726497Sache#define	NPTY	32		/* crude XXX */
5826497Sache#endif
5926497Sache
6021308Sache#define BUFSIZ 100		/* Chunk size iomoved to/from user */
6121308Sache
6221308Sache/*
6321308Sache * pts == /dev/tty[pqrs]?
6421308Sache * ptc == /dev/pty[pqrs]?
6521308Sache */
6658314Sachestruct	tty pt_tty[NPTY];	/* XXX */
6758314Sachestruct	pt_ioctl {
68119614Sache	int	pt_flags;
6921308Sache	struct	selinfo pt_selr, pt_selw;
70119614Sache	u_char	pt_send;
71119614Sache	u_char	pt_ucntl;
72119614Sache} pt_ioctl[NPTY];		/* XXX */
7321308Sacheint	npty = NPTY;		/* for pstat -t */
7421308Sache
7521308Sache#define	PF_PKT		0x08		/* packet mode */
7621308Sache#define	PF_STOPPED	0x10		/* user told stopped */
7721308Sache#define	PF_REMOTE	0x20		/* remote and flow controlled input */
7821308Sache#define	PF_NOSTOP	0x40
7921308Sache#define PF_UCNTL	0x80		/* user control mode */
8021308Sache
8121308Sachevoid	ptsstop		__P((struct tty *, int));
8221308Sachevoid	ptcwakeup	__P((struct tty *, int));
8321308Sache
8421308Sache/*
8526497Sache * Establish n (or default if n is 1) ptys in the system.
8626497Sache *
8726497Sache * XXX cdevsw & pstat require the array `pty[]' to be an array
8826497Sache */
8921308Sachevoid
9021308Sacheptyattach(n)
9121308Sache	int n;
9275409Sache{
9375409Sache#ifdef notyet
9475409Sache	char *mem;
9575409Sache	register u_long ntb;
9675409Sache#define	DEFAULT_NPTY	32
9775409Sache
9821308Sache	/* maybe should allow 0 => none? */
9921308Sache	if (n <= 1)
10075409Sache		n = DEFAULT_NPTY;
10121308Sache	ntb = n * sizeof(struct tty);
10221308Sache	mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
10375409Sache	    M_DEVBUF, M_WAITOK);
10475409Sache	pt_tty = (struct tty *)mem;
10575409Sache	mem = (char *)ALIGN(mem + ntb);
10675409Sache	pt_ioctl = (struct pt_ioctl *)mem;
10775409Sache	npty = n;
10821308Sache#endif
10921308Sache}
11075409Sache
11175409Sache/*ARGSUSED*/
11221308Sacheint
11321308Sacheptsopen(dev, flag, devtype, p)
11475409Sache	dev_t dev;
11521308Sache	int flag, devtype;
11621308Sache	struct proc *p;
11721308Sache{
11875409Sache	register struct tty *tp;
11921308Sache	int error;
12075409Sache
12175409Sache	if (minor(dev) >= npty)
12221308Sache		return (ENXIO);
12321308Sache	tp = &pt_tty[minor(dev)];
12421308Sache	if ((tp->t_state & TS_ISOPEN) == 0) {
12521308Sache		ttychars(tp);		/* Set up default chars */
12621308Sache		tp->t_iflag = TTYDEF_IFLAG;
12721308Sache		tp->t_oflag = TTYDEF_OFLAG;
12821308Sache		tp->t_lflag = TTYDEF_LFLAG;
12921308Sache		tp->t_cflag = TTYDEF_CFLAG;
13075409Sache		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
13175409Sache		ttsetwater(tp);		/* would be done in xxparam() */
13275409Sache	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
13321308Sache		return (EBUSY);
13421308Sache	if (tp->t_oproc)			/* Ctrlr still around. */
13575409Sache		tp->t_state |= TS_CARR_ON;
13675409Sache	while ((tp->t_state & TS_CARR_ON) == 0) {
13775409Sache		if (flag&FNONBLOCK)
13875409Sache			break;
13921308Sache		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
14021308Sache				 "ptsopn", 0);
14175409Sache		if (error)
14275409Sache			return (error);
14321308Sache	}
14421308Sache	error = (*linesw[tp->t_line].l_open)(dev, tp);
14575409Sache	if (error == 0)
14675409Sache		ptcwakeup(tp, FREAD|FWRITE);
147119614Sache	return (error);
14821308Sache}
149119614Sache
150119614Sacheint
151119614Sacheptsclose(dev, flag, mode, p)
152119614Sache	dev_t dev;
153119614Sache	int flag, mode;
154119614Sache	struct proc *p;
155119614Sache{
156119614Sache	register struct tty *tp;
157119614Sache	int err;
15821308Sache
15975409Sache	tp = &pt_tty[minor(dev)];
16021308Sache	err = (*linesw[tp->t_line].l_close)(tp, flag);
16121308Sache	ptsstop(tp, FREAD|FWRITE);
16221308Sache	(void) ttyclose(tp);
16321308Sache	return (err);
16421308Sache}
16521308Sache
16621308Sacheint
16758314Sacheptsread(dev, uio, flag)
16858314Sache	dev_t dev;
16958314Sache	struct uio *uio;
17058314Sache	int flag;
17158314Sache{
17258314Sache	struct proc *p = curproc;
17358314Sache	register struct tty *tp = &pt_tty[minor(dev)];
17458314Sache	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
17558314Sache	int error = 0;
17658314Sache
17758314Sacheagain:
17858314Sache	if (pti->pt_flags & PF_REMOTE) {
17958314Sache		while (isbackground(p, tp)) {
18058314Sache			if ((p->p_sigignore & sigmask(SIGTTIN)) ||
18158314Sache			    (p->p_sigmask & sigmask(SIGTTIN)) ||
18258314Sache			    p->p_pgrp->pg_jobc == 0 ||
18321308Sache			    p->p_flag & P_PPWAIT)
18421308Sache				return (EIO);
18521308Sache			pgsignal(p->p_pgrp, SIGTTIN, 1);
18621308Sache			error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg",
18721308Sache					 0);
18821308Sache			if (error)
18921308Sache				return (error);
19021308Sache		}
19121308Sache		if (tp->t_canq.c_cc == 0) {
19221308Sache			if (flag & IO_NDELAY)
19321308Sache				return (EWOULDBLOCK);
19421308Sache			error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
19521308Sache					 "ptsin", 0);
19621308Sache			if (error)
19721308Sache				return (error);
19821308Sache			goto again;
19975409Sache		}
20075409Sache		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
20121308Sache			if (ureadc(getc(&tp->t_canq), uio) < 0) {
20221308Sache				error = EFAULT;
20321308Sache				break;
20426497Sache			}
20575409Sache		if (tp->t_canq.c_cc == 1)
20626497Sache			(void) getc(&tp->t_canq);
20726497Sache		if (tp->t_canq.c_cc)
20821308Sache			return (error);
20921308Sache	} else
21075409Sache		if (tp->t_oproc)
21121308Sache			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
21275409Sache	ptcwakeup(tp, FWRITE);
21375409Sache	return (error);
21421308Sache}
21558314Sache
21675409Sache/*
21775409Sache * Write to pseudo-tty.
21858314Sache * Wakeups of controlling tty will happen
21921308Sache * indirectly, when tty driver calls ptsstart.
22021308Sache */
22121308Sacheint
22221308Sacheptswrite(dev, uio, flag)
22375409Sache	dev_t dev;
22421308Sache	struct uio *uio;
22575409Sache	int flag;
22675409Sache{
22721308Sache	register struct tty *tp;
22858314Sache
22975409Sache	tp = &pt_tty[minor(dev)];
23075409Sache	if (tp->t_oproc == 0)
23158314Sache		return (EIO);
23221308Sache	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
23321308Sache}
23421308Sache
23575409Sache/*
23675409Sache * Start output on pseudo-tty.
23721308Sache * Wake up process selecting or sleeping for input from controlling tty.
23875409Sache */
23975409Sachevoid
24021308Sacheptsstart(tp)
24121308Sache	struct tty *tp;
24221308Sache{
24321308Sache	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
24475409Sache
24521308Sache	if (tp->t_state & TS_TTSTOP)
24658314Sache		return;
24775409Sache	if (pti->pt_flags & PF_STOPPED) {
24821308Sache		pti->pt_flags &= ~PF_STOPPED;
24975409Sache		pti->pt_send = TIOCPKT_START;
25021308Sache	}
25121308Sache	ptcwakeup(tp, FREAD);
25221308Sache}
25321308Sache
25421308Sachevoid
25521308Sacheptcwakeup(tp, flag)
25675409Sache	struct tty *tp;
25775409Sache	int flag;
25821308Sache{
25975409Sache	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
26075409Sache
26175409Sache	if (flag & FREAD) {
26221308Sache		selwakeup(&pti->pt_selr);
26375409Sache		wakeup(TSA_PTC_READ(tp));
26421308Sache	}
26575409Sache	if (flag & FWRITE) {
26621308Sache		selwakeup(&pti->pt_selw);
26721308Sache		wakeup(TSA_PTC_WRITE(tp));
26847558Sache	}
26975409Sache}
27075409Sache
27175409Sache/*ARGSUSED*/
27275409Sache#ifdef __STDC__
27375409Sacheint
27475409Sacheptcopen(dev_t dev, int flag, int devtype, struct proc *p)
27575409Sache#else
27675409Sacheint
27775409Sacheptcopen(dev, flag, devtype, p)
27875409Sache	dev_t dev;
27975409Sache	int flag, devtype;
28075409Sache	struct proc *p;
28175409Sache#endif
28275409Sache{
28375409Sache	register struct tty *tp;
28475409Sache	struct pt_ioctl *pti;
28575409Sache
28647558Sache	if (minor(dev) >= npty)
28747558Sache		return (ENXIO);
28847558Sache	tp = &pt_tty[minor(dev)];
28947558Sache	if (tp->t_oproc)
29047558Sache		return (EIO);
291119614Sache	tp->t_oproc = ptsstart;
292119614Sache#ifdef sun4c
293119614Sache	tp->t_stop = ptsstop;
294119614Sache#endif
29547558Sache	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
29647558Sache	tp->t_lflag &= ~EXTPROC;
29747558Sache	pti = &pt_ioctl[minor(dev)];
29821308Sache	pti->pt_flags = 0;
29975409Sache	pti->pt_send = 0;
30021308Sache	pti->pt_ucntl = 0;
30121308Sache	return (0);
30221308Sache}
30321308Sache
30421308Sacheint
30521308Sacheptcclose(dev)
30621308Sache	dev_t dev;
307119614Sache{
30875409Sache	register struct tty *tp;
30975409Sache
31075409Sache	tp = &pt_tty[minor(dev)];
31175409Sache	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
31275409Sache	tp->t_state &= ~TS_CARR_ON;
31375409Sache	tp->t_oproc = 0;		/* mark closed */
31475409Sache	tp->t_session = 0;
31575409Sache	return (0);
31675409Sache}
317119614Sache
318119614Sacheint
31975409Sacheptcread(dev, uio, flag)
320119614Sache	dev_t dev;
32175409Sache	struct uio *uio;
32275409Sache	int flag;
32375409Sache{
324119614Sache	register struct tty *tp = &pt_tty[minor(dev)];
32575409Sache	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
32675409Sache	char buf[BUFSIZ];
32775409Sache	int error = 0, cc;
32875409Sache
32921308Sache	/*
33075409Sache	 * We want to block until the slave
33121308Sache	 * is open, and there's something to read;
33275409Sache	 * but if we lost the slave or we're NBIO,
33375409Sache	 * then return the appropriate error instead.
33475409Sache	 */
335119614Sache	for (;;) {
336119614Sache		if (tp->t_state&TS_ISOPEN) {
33721308Sache			if (pti->pt_flags&PF_PKT && pti->pt_send) {
33821308Sache				error = ureadc((int)pti->pt_send, uio);
33921308Sache				if (error)
34021308Sache					return (error);
34121308Sache				if (pti->pt_send & TIOCPKT_IOCTL) {
34221308Sache					cc = min(uio->uio_resid,
34321308Sache						sizeof(tp->t_termios));
34421308Sache					uiomove((caddr_t)&tp->t_termios, cc,
34521308Sache						uio);
34621308Sache				}
34758314Sache				pti->pt_send = 0;
34821308Sache				return (0);
34921308Sache			}
35021308Sache			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
351119614Sache				error = ureadc((int)pti->pt_ucntl, uio);
352119614Sache				if (error)
353119614Sache					return (error);
35421308Sache				pti->pt_ucntl = 0;
355119614Sache				return (0);
35658314Sache			}
35721308Sache			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
35821308Sache				break;
35921308Sache		}
36021308Sache		if ((tp->t_state&TS_CARR_ON) == 0)
36121308Sache			return (0);	/* EOF */
36275409Sache		if (flag & IO_NDELAY)
36321308Sache			return (EWOULDBLOCK);
36475409Sache		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
36575409Sache		if (error)
36658314Sache			return (error);
36721308Sache	}
36875409Sache	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
36975409Sache		error = ureadc(0, uio);
37058314Sache	while (uio->uio_resid > 0 && error == 0) {
37175409Sache		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
37221308Sache		if (cc <= 0)
37358314Sache			break;
37458314Sache		error = uiomove(buf, cc, uio);
37521308Sache	}
37658314Sache	ttwwakeup(tp);
37758314Sache	return (error);
37858314Sache}
37958314Sache
38058314Sachevoid
38158314Sacheptsstop(tp, flush)
38258314Sache	register struct tty *tp;
38358314Sache	int flush;
38458314Sache{
38558314Sache	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
386119614Sache	int flag;
38721308Sache
38858314Sache	/* note: FLUSHREAD and FLUSHWRITE already ok */
389119614Sache	if (flush == 0) {
39021308Sache		flush = TIOCPKT_STOP;
39158314Sache		pti->pt_flags |= PF_STOPPED;
39221308Sache	} else
39358314Sache		pti->pt_flags &= ~PF_STOPPED;
39458314Sache	pti->pt_send |= flush;
39521308Sache	/* change of perspective */
39658314Sache	flag = 0;
39721308Sache	if (flush & FREAD)
39858314Sache		flag |= FWRITE;
39958314Sache	if (flush & FWRITE)
40058314Sache		flag |= FREAD;
40158314Sache	ptcwakeup(tp, flag);
40258314Sache}
40358314Sache
40458314Sacheint
40575409Sacheptcselect(dev, rw, p)
40675409Sache	dev_t dev;
40758314Sache	int rw;
40858314Sache	struct proc *p;
40958314Sache{
41058314Sache	register struct tty *tp = &pt_tty[minor(dev)];
41158314Sache	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
41275409Sache	int s;
41358314Sache
41475409Sache	if ((tp->t_state&TS_CARR_ON) == 0)
41575409Sache		return (1);
41658314Sache	switch (rw) {
41758314Sache
41858314Sache	case FREAD:
41975409Sache		/*
42075409Sache		 * Need to block timeouts (ttrstart).
42175409Sache		 */
42275409Sache		s = spltty();
42375409Sache		if ((tp->t_state&TS_ISOPEN) &&
424119614Sache		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
425119614Sache			splx(s);
42675409Sache			return (1);
427119614Sache		}
42821308Sache		splx(s);
42921308Sache		/* FALLTHROUGH */
43021308Sache
43175409Sache	case 0:					/* exceptional */
43258314Sache		if ((tp->t_state&TS_ISOPEN) &&
43358314Sache		    ((pti->pt_flags&PF_PKT && pti->pt_send) ||
43475409Sache		     (pti->pt_flags&PF_UCNTL && pti->pt_ucntl)))
43558314Sache			return (1);
43658314Sache		selrecord(p, &pti->pt_selr);
43775409Sache		break;
43875409Sache
43958314Sache
44021308Sache	case FWRITE:
44121308Sache		if (tp->t_state&TS_ISOPEN) {
44221308Sache			if (pti->pt_flags & PF_REMOTE) {
44321308Sache			    if (tp->t_canq.c_cc == 0)
44421308Sache				return (1);
44521308Sache			} else {
44621308Sache			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
44775409Sache				    return (1);
44875409Sache			    if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
44975409Sache				    return (1);
45021308Sache			}
45175409Sache		}
45275409Sache		selrecord(p, &pti->pt_selw);
45321308Sache		break;
45421308Sache
45521308Sache	}
45621308Sache	return (0);
45721308Sache}
45821308Sache
45921308Sacheint
46021308Sacheptcwrite(dev, uio, flag)
46121308Sache	dev_t dev;
46275409Sache	register struct uio *uio;
46321308Sache	int flag;
46421308Sache{
46521308Sache	register struct tty *tp = &pt_tty[minor(dev)];
46621308Sache	register u_char *cp = 0;
46721308Sache	register int cc = 0;
46875409Sache	u_char locbuf[BUFSIZ];
46921308Sache	int cnt = 0;
47021308Sache	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
47121308Sache	int error = 0;
47221308Sache
473119614Sacheagain:
47421308Sache	if ((tp->t_state&TS_ISOPEN) == 0)
475119614Sache		goto block;
476119614Sache	if (pti->pt_flags & PF_REMOTE) {
477119614Sache		if (tp->t_canq.c_cc)
478119614Sache			goto block;
47921308Sache		while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
480119614Sache			if (cc == 0) {
481119614Sache				cc = min(uio->uio_resid, BUFSIZ);
482119614Sache				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
483119614Sache				cp = locbuf;
484119614Sache				error = uiomove((caddr_t)cp, cc, uio);
485119614Sache				if (error)
486119614Sache					return (error);
487119614Sache				/* check again for safety */
488119614Sache				if ((tp->t_state&TS_ISOPEN) == 0)
489119614Sache					return (EIO);
490119614Sache			}
491119614Sache			if (cc)
492119614Sache				(void) b_to_q((char *)cp, cc, &tp->t_canq);
49375409Sache			cc = 0;
49475409Sache		}
49575409Sache		(void) putc(0, &tp->t_canq);
49675409Sache		ttwakeup(tp);
49721308Sache		wakeup(TSA_PTS_READ(tp));
49875409Sache		return (0);
499119614Sache	}
50021308Sache	while (uio->uio_resid > 0) {
50121308Sache		if (cc == 0) {
50221308Sache			cc = min(uio->uio_resid, BUFSIZ);
50321308Sache			cp = locbuf;
50421308Sache			error = uiomove((caddr_t)cp, cc, uio);
50521308Sache			if (error)
50675409Sache				return (error);
50721308Sache			/* check again for safety */
50821308Sache			if ((tp->t_state&TS_ISOPEN) == 0)
50921308Sache				return (EIO);
51021308Sache		}
51121308Sache		while (cc > 0) {
51221308Sache			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
51321308Sache			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
51421308Sache				wakeup(TSA_CARR_ON(tp));
51521308Sache				goto block;
51621308Sache			}
51721308Sache			(*linesw[tp->t_line].l_rint)(*cp++, tp);
51821308Sache			cnt++;
51921308Sache			cc--;
52026497Sache		}
52126497Sache		cc = 0;
52226497Sache	}
52326497Sache	return (0);
52475409Sacheblock:
52526497Sache	/*
52626497Sache	 * Come here to wait for slave to open, for space
52726497Sache	 * in outq, or space in rawq.
52826497Sache	 */
52926497Sache	if ((tp->t_state&TS_CARR_ON) == 0)
53021308Sache		return (EIO);
53135486Sache	if (flag & IO_NDELAY) {
53235486Sache		/* adjust for data copied in but not written */
53335486Sache		uio->uio_resid += cc;
53435486Sache		if (cnt == 0)
53535486Sache			return (EWOULDBLOCK);
53635486Sache		return (0);
53735486Sache	}
53835486Sache	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
53921308Sache	if (error) {
54021308Sache		/* adjust for data copied in but not written */
54121308Sache		uio->uio_resid += cc;
54221308Sache		return (error);
54321308Sache	}
54421308Sache	goto again;
54535486Sache}
54658314Sache
54721308Sachestruct tty *
54821308Sacheptydevtotty(dev)
54921308Sache	dev_t		dev;
55075409Sache{
55121308Sache	if (minor(dev) >= npty)
55221308Sache		return (NULL);
55321308Sache
55421308Sache	return &pt_tty[minor(dev)];
55521308Sache}
55621308Sache
55721308Sache/*ARGSUSED*/
55821308Sacheint
55921308Sacheptyioctl(dev, cmd, data, flag, p)
56021308Sache	dev_t dev;
56121308Sache	int cmd;
56221308Sache	caddr_t data;
56375409Sache	int flag;
56421308Sache	struct proc *p;
56575409Sache{
56621308Sache	register struct tty *tp = &pt_tty[minor(dev)];
56721308Sache	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
56821308Sache	register u_char *cc = tp->t_cc;
56921308Sache	int stop, error;
57021308Sache
57121308Sache	/*
57221308Sache	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
57321308Sache	 * ttywflush(tp) will hang if there are characters in the outq.
57475409Sache	 */
57521308Sache	if (cmd == TIOCEXT) {
57621308Sache		/*
57775409Sache		 * When the EXTPROC bit is being toggled, we need
57875409Sache		 * to send an TIOCPKT_IOCTL if the packet driver
57921308Sache		 * is turned on.
58021308Sache		 */
58121308Sache		if (*(int *)data) {
58221308Sache			if (pti->pt_flags & PF_PKT) {
58321308Sache				pti->pt_send |= TIOCPKT_IOCTL;
58421308Sache				ptcwakeup(tp, FREAD);
58521308Sache			}
58675409Sache			tp->t_lflag |= EXTPROC;
58721308Sache		} else {
58821308Sache			if ((tp->t_state & EXTPROC) &&
58921308Sache			    (pti->pt_flags & PF_PKT)) {
59021308Sache				pti->pt_send |= TIOCPKT_IOCTL;
59121308Sache				ptcwakeup(tp, FREAD);
59221308Sache			}
59321308Sache			tp->t_lflag &= ~EXTPROC;
59421308Sache		}
59521308Sache		return(0);
59675409Sache	} else
59721308Sache	if (cdevsw[major(dev)].d_open == ptcopen)
59875409Sache		switch (cmd) {
59921308Sache
60021308Sache		case TIOCGPGRP:
60121308Sache			/*
60221308Sache			 * We aviod calling ttioctl on the controller since,
60321308Sache			 * in that case, tp must be the controlling terminal.
60421308Sache			 */
60521308Sache			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
60621308Sache			return (0);
60721308Sache
60821308Sache		case TIOCPKT:
60921308Sache			if (*(int *)data) {
61021308Sache				if (pti->pt_flags & PF_UCNTL)
61121308Sache					return (EINVAL);
61221308Sache				pti->pt_flags |= PF_PKT;
61321308Sache			} else
61421308Sache				pti->pt_flags &= ~PF_PKT;
61521308Sache			return (0);
61621308Sache
61721308Sache		case TIOCUCNTL:
61826497Sache			if (*(int *)data) {
61921308Sache				if (pti->pt_flags & PF_PKT)
62021308Sache					return (EINVAL);
62158314Sache				pti->pt_flags |= PF_UCNTL;
62275409Sache			} else
62375409Sache				pti->pt_flags &= ~PF_UCNTL;
62458314Sache			return (0);
62521308Sache
62621308Sache		case TIOCREMOTE:
62721308Sache			if (*(int *)data)
62821308Sache				pti->pt_flags |= PF_REMOTE;
62921308Sache			else
63021308Sache				pti->pt_flags &= ~PF_REMOTE;
63158314Sache			ttyflush(tp, FREAD|FWRITE);
63275409Sache			return (0);
63375409Sache
63475409Sache#ifdef COMPAT_43
63575409Sache		case TIOCSETP:
63658314Sache		case TIOCSETN:
63721308Sache#endif
638119614Sache		case TIOCSETD:
639119614Sache		case TIOCSETA:
640119614Sache		case TIOCSETAW:
641119614Sache		case TIOCSETAF:
642119614Sache			ndflush(&tp->t_outq, tp->t_outq.c_cc);
643119614Sache			break;
644119614Sache
645119614Sache		case TIOCSIG:
646119614Sache			if (*(unsigned int *)data >= NSIG)
647119614Sache				return(EINVAL);
648119614Sache			if ((tp->t_lflag&NOFLSH) == 0)
649119614Sache				ttyflush(tp, FREAD|FWRITE);
650119614Sache			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
651119614Sache			if ((*(unsigned int *)data == SIGINFO) &&
652119614Sache			    ((tp->t_lflag&NOKERNINFO) == 0))
653119614Sache				ttyinfo(tp);
654119614Sache			return(0);
655119614Sache		}
656119614Sache	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
657119614Sache	if (error < 0)
658119614Sache		 error = ttioctl(tp, cmd, data, flag);
659119614Sache	if (error < 0) {
660119614Sache		if (pti->pt_flags & PF_UCNTL &&
661119614Sache		    (cmd & ~0xff) == UIOCCMD(0)) {
662119614Sache			if (cmd & 0xff) {
663119614Sache				pti->pt_ucntl = (u_char)cmd;
664				ptcwakeup(tp, FREAD);
665			}
666			return (0);
667		}
668		error = ENOTTY;
669	}
670	/*
671	 * If external processing and packet mode send ioctl packet.
672	 */
673	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
674		switch(cmd) {
675		case TIOCSETA:
676		case TIOCSETAW:
677		case TIOCSETAF:
678#ifdef COMPAT_43
679		case TIOCSETP:
680		case TIOCSETN:
681#endif
682#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
683		case TIOCSETC:
684		case TIOCSLTC:
685		case TIOCLBIS:
686		case TIOCLBIC:
687		case TIOCLSET:
688#endif
689			pti->pt_send |= TIOCPKT_IOCTL;
690			ptcwakeup(tp, FREAD);
691		default:
692			break;
693		}
694	}
695	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
696		&& CCEQ(cc[VSTART], CTRL('q'));
697	if (pti->pt_flags & PF_NOSTOP) {
698		if (stop) {
699			pti->pt_send &= ~TIOCPKT_NOSTOP;
700			pti->pt_send |= TIOCPKT_DOSTOP;
701			pti->pt_flags &= ~PF_NOSTOP;
702			ptcwakeup(tp, FREAD);
703		}
704	} else {
705		if (!stop) {
706			pti->pt_send &= ~TIOCPKT_DOSTOP;
707			pti->pt_send |= TIOCPKT_NOSTOP;
708			pti->pt_flags |= PF_NOSTOP;
709			ptcwakeup(tp, FREAD);
710		}
711	}
712	return (error);
713}
714