pty.c revision 49536
1/*
2 * Copyright (c) 1982, 1986, 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
34 * $Id: tty_pty.c,v 1.61 1999/05/31 11:27:38 phk Exp $
35 */
36
37/*
38 * Pseudo-teletype Driver
39 * (Actually two drivers, requiring two entries in 'cdevsw')
40 */
41#include "pty.h"		/* XXX */
42#include "opt_compat.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
47#include <sys/ioctl_compat.h>
48#endif
49#include <sys/proc.h>
50#include <sys/tty.h>
51#include <sys/conf.h>
52#include <sys/fcntl.h>
53#include <sys/poll.h>
54#include <sys/kernel.h>
55#include <sys/vnode.h>
56#include <sys/signalvar.h>
57#include <sys/malloc.h>
58
59MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
60
61static void ptsstart __P((struct tty *tp));
62static void ptcwakeup __P((struct tty *tp, int flag));
63static void ptyinit __P((int n));
64
65static	d_open_t	ptsopen;
66static	d_close_t	ptsclose;
67static	d_read_t	ptsread;
68static	d_write_t	ptswrite;
69static	d_ioctl_t	ptyioctl;
70static	d_stop_t	ptsstop;
71static	d_devtotty_t	ptydevtotty;
72static	d_open_t	ptcopen;
73static	d_close_t	ptcclose;
74static	d_read_t	ptcread;
75static	d_write_t	ptcwrite;
76static	d_poll_t	ptcpoll;
77
78#define	CDEV_MAJOR_S	5
79static struct cdevsw pts_cdevsw = {
80	/* open */	ptsopen,
81	/* close */	ptsclose,
82	/* read */	ptsread,
83	/* write */	ptswrite,
84	/* ioctl */	ptyioctl,
85	/* stop */	ptsstop,
86	/* reset */	noreset,
87	/* devtotty */	ptydevtotty,
88	/* poll */	ttpoll,
89	/* mmap */	nommap,
90	/* strategy */	nostrategy,
91	/* name */	"pts",
92	/* parms */	noparms,
93	/* maj */	CDEV_MAJOR_S,
94	/* dump */	nodump,
95	/* psize */	nopsize,
96	/* flags */	D_TTY,
97	/* maxio */	0,
98	/* bmaj */	-1
99};
100
101#define	CDEV_MAJOR_C	6
102static struct cdevsw ptc_cdevsw = {
103	/* open */	ptcopen,
104	/* close */	ptcclose,
105	/* read */	ptcread,
106	/* write */	ptcwrite,
107	/* ioctl */	ptyioctl,
108	/* stop */	nostop,
109	/* reset */	noreset,
110	/* devtotty */	ptydevtotty,
111	/* poll */	ptcpoll,
112	/* mmap */	nommap,
113	/* strategy */	nostrategy,
114	/* name */	"ptc",
115	/* parms */	noparms,
116	/* maj */	CDEV_MAJOR_C,
117	/* dump */	nodump,
118	/* psize */	nopsize,
119	/* flags */	D_TTY,
120	/* maxio */	0,
121	/* bmaj */	-1
122};
123
124#define BUFSIZ 100		/* Chunk size iomoved to/from user */
125
126struct	pt_ioctl {
127	int	pt_flags;
128	struct	selinfo pt_selr, pt_selw;
129	u_char	pt_send;
130	u_char	pt_ucntl;
131	struct tty pt_tty;
132};
133
134#define	PF_PKT		0x08		/* packet mode */
135#define	PF_STOPPED	0x10		/* user told stopped */
136#define	PF_REMOTE	0x20		/* remote and flow controlled input */
137#define	PF_NOSTOP	0x40
138#define PF_UCNTL	0x80		/* user control mode */
139
140/*
141 * This function creates and initializes a pts/ptc pair
142 *
143 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
144 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
145 *
146 * XXX: define and add mapping of upper minor bits to allow more
147 *      than 256 ptys.
148 */
149static void
150ptyinit(n)
151	int n;
152{
153	dev_t devs, devc;
154	char *names = "pqrsPQRS";
155	struct pt_ioctl *pt;
156
157	/* For now we only map the lower 8 bits of the minor */
158	if (n & ~0xff)
159		return;
160
161	devs = make_dev(&pts_cdevsw, n,
162	    0, 0, 0666, "tty%c%r", names[n / 32], n % 32);
163	devc = make_dev(&ptc_cdevsw, n,
164	    0, 0, 0666, "pty%c%r", names[n / 32], n % 32);
165
166	pt = malloc(sizeof(*pt), M_PTY, M_WAITOK);
167	bzero(pt, sizeof(*pt));
168	devs->si_drv1 = devc->si_drv1 = pt;
169	devs->si_tty_tty = devc->si_tty_tty = &pt->pt_tty;
170}
171
172/*ARGSUSED*/
173static	int
174ptsopen(dev, flag, devtype, p)
175	dev_t dev;
176	int flag, devtype;
177	struct proc *p;
178{
179	register struct tty *tp;
180	int error;
181
182	if (!dev->si_drv1)
183		ptyinit(minor(dev));
184	if (!dev->si_drv1)
185		return(ENXIO);
186	tp = dev->si_tty_tty;
187	if ((tp->t_state & TS_ISOPEN) == 0) {
188		ttychars(tp);		/* Set up default chars */
189		tp->t_iflag = TTYDEF_IFLAG;
190		tp->t_oflag = TTYDEF_OFLAG;
191		tp->t_lflag = TTYDEF_LFLAG;
192		tp->t_cflag = TTYDEF_CFLAG;
193		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
194	} else if (tp->t_state & TS_XCLUDE && suser(p))
195		return (EBUSY);
196	if (tp->t_oproc)			/* Ctrlr still around. */
197		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
198	while ((tp->t_state & TS_CARR_ON) == 0) {
199		if (flag&FNONBLOCK)
200			break;
201		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
202				 "ptsopn", 0);
203		if (error)
204			return (error);
205	}
206	error = (*linesw[tp->t_line].l_open)(dev, tp);
207	if (error == 0)
208		ptcwakeup(tp, FREAD|FWRITE);
209	return (error);
210}
211
212static	int
213ptsclose(dev, flag, mode, p)
214	dev_t dev;
215	int flag, mode;
216	struct proc *p;
217{
218	register struct tty *tp;
219	int err;
220
221	tp = dev->si_tty_tty;
222	err = (*linesw[tp->t_line].l_close)(tp, flag);
223	ptsstop(tp, FREAD|FWRITE);
224	(void) ttyclose(tp);
225	return (err);
226}
227
228static	int
229ptsread(dev, uio, flag)
230	dev_t dev;
231	struct uio *uio;
232	int flag;
233{
234	struct proc *p = curproc;
235	register struct tty *tp = dev->si_tty_tty;
236	register struct pt_ioctl *pti = dev->si_drv1;
237	int error = 0;
238
239again:
240	if (pti->pt_flags & PF_REMOTE) {
241		while (isbackground(p, tp)) {
242			if ((p->p_sigignore & sigmask(SIGTTIN)) ||
243			    (p->p_sigmask & sigmask(SIGTTIN)) ||
244			    p->p_pgrp->pg_jobc == 0 ||
245			    p->p_flag & P_PPWAIT)
246				return (EIO);
247			pgsignal(p->p_pgrp, SIGTTIN, 1);
248			error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg",
249					 0);
250			if (error)
251				return (error);
252		}
253		if (tp->t_canq.c_cc == 0) {
254			if (flag & IO_NDELAY)
255				return (EWOULDBLOCK);
256			error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
257					 "ptsin", 0);
258			if (error)
259				return (error);
260			goto again;
261		}
262		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
263			if (ureadc(getc(&tp->t_canq), uio) < 0) {
264				error = EFAULT;
265				break;
266			}
267		if (tp->t_canq.c_cc == 1)
268			(void) getc(&tp->t_canq);
269		if (tp->t_canq.c_cc)
270			return (error);
271	} else
272		if (tp->t_oproc)
273			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
274	ptcwakeup(tp, FWRITE);
275	return (error);
276}
277
278/*
279 * Write to pseudo-tty.
280 * Wakeups of controlling tty will happen
281 * indirectly, when tty driver calls ptsstart.
282 */
283static	int
284ptswrite(dev, uio, flag)
285	dev_t dev;
286	struct uio *uio;
287	int flag;
288{
289	register struct tty *tp;
290
291	tp = dev->si_tty_tty;
292	if (tp->t_oproc == 0)
293		return (EIO);
294	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
295}
296
297/*
298 * Start output on pseudo-tty.
299 * Wake up process selecting or sleeping for input from controlling tty.
300 */
301static void
302ptsstart(tp)
303	struct tty *tp;
304{
305	register struct pt_ioctl *pti = tp->t_dev->si_drv1;
306
307	if (tp->t_state & TS_TTSTOP)
308		return;
309	if (pti->pt_flags & PF_STOPPED) {
310		pti->pt_flags &= ~PF_STOPPED;
311		pti->pt_send = TIOCPKT_START;
312	}
313	ptcwakeup(tp, FREAD);
314}
315
316static void
317ptcwakeup(tp, flag)
318	struct tty *tp;
319	int flag;
320{
321	struct pt_ioctl *pti = tp->t_dev->si_drv1;
322
323	if (flag & FREAD) {
324		selwakeup(&pti->pt_selr);
325		wakeup(TSA_PTC_READ(tp));
326	}
327	if (flag & FWRITE) {
328		selwakeup(&pti->pt_selw);
329		wakeup(TSA_PTC_WRITE(tp));
330	}
331}
332
333static	int
334ptcopen(dev, flag, devtype, p)
335	dev_t dev;
336	int flag, devtype;
337	struct proc *p;
338{
339	register struct tty *tp;
340	struct pt_ioctl *pti;
341
342	if (!dev->si_drv1)
343		ptyinit(minor(dev));
344	if (!dev->si_drv1)
345		return(ENXIO);
346	tp = dev->si_tty_tty;
347	if (tp->t_oproc)
348		return (EIO);
349	tp->t_oproc = ptsstart;
350	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
351	tp->t_lflag &= ~EXTPROC;
352	pti = dev->si_drv1;
353	pti->pt_flags = 0;
354	pti->pt_send = 0;
355	pti->pt_ucntl = 0;
356	return (0);
357}
358
359static	int
360ptcclose(dev, flags, fmt, p)
361	dev_t dev;
362	int flags;
363	int fmt;
364	struct proc *p;
365{
366	register struct tty *tp;
367
368	tp = dev->si_tty_tty;
369	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
370
371	/*
372	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
373	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
374	 * l_modem()s that ignore carrier drop make no sense for ptys but
375	 * may be in use because other parts of the line discipline make
376	 * sense for ptys.  Recover by doing everything that a normal
377	 * ttymodem() would have done except for sending a SIGHUP.
378	 */
379	if (tp->t_state & TS_ISOPEN) {
380		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
381		tp->t_state |= TS_ZOMBIE;
382		ttyflush(tp, FREAD | FWRITE);
383	}
384
385	tp->t_oproc = 0;		/* mark closed */
386	return (0);
387}
388
389static	int
390ptcread(dev, uio, flag)
391	dev_t dev;
392	struct uio *uio;
393	int flag;
394{
395	register struct tty *tp = dev->si_tty_tty;
396	struct pt_ioctl *pti = dev->si_drv1;
397	char buf[BUFSIZ];
398	int error = 0, cc;
399
400	/*
401	 * We want to block until the slave
402	 * is open, and there's something to read;
403	 * but if we lost the slave or we're NBIO,
404	 * then return the appropriate error instead.
405	 */
406	for (;;) {
407		if (tp->t_state&TS_ISOPEN) {
408			if (pti->pt_flags&PF_PKT && pti->pt_send) {
409				error = ureadc((int)pti->pt_send, uio);
410				if (error)
411					return (error);
412				if (pti->pt_send & TIOCPKT_IOCTL) {
413					cc = min(uio->uio_resid,
414						sizeof(tp->t_termios));
415					uiomove((caddr_t)&tp->t_termios, cc,
416						uio);
417				}
418				pti->pt_send = 0;
419				return (0);
420			}
421			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
422				error = ureadc((int)pti->pt_ucntl, uio);
423				if (error)
424					return (error);
425				pti->pt_ucntl = 0;
426				return (0);
427			}
428			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
429				break;
430		}
431		if ((tp->t_state & TS_CONNECTED) == 0)
432			return (0);	/* EOF */
433		if (flag & IO_NDELAY)
434			return (EWOULDBLOCK);
435		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
436		if (error)
437			return (error);
438	}
439	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
440		error = ureadc(0, uio);
441	while (uio->uio_resid > 0 && error == 0) {
442		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
443		if (cc <= 0)
444			break;
445		error = uiomove(buf, cc, uio);
446	}
447	ttwwakeup(tp);
448	return (error);
449}
450
451static	void
452ptsstop(tp, flush)
453	register struct tty *tp;
454	int flush;
455{
456	struct pt_ioctl *pti = tp->t_dev->si_drv1;
457	int flag;
458
459	/* note: FLUSHREAD and FLUSHWRITE already ok */
460	if (flush == 0) {
461		flush = TIOCPKT_STOP;
462		pti->pt_flags |= PF_STOPPED;
463	} else
464		pti->pt_flags &= ~PF_STOPPED;
465	pti->pt_send |= flush;
466	/* change of perspective */
467	flag = 0;
468	if (flush & FREAD)
469		flag |= FWRITE;
470	if (flush & FWRITE)
471		flag |= FREAD;
472	ptcwakeup(tp, flag);
473}
474
475static	int
476ptcpoll(dev, events, p)
477	dev_t dev;
478	int events;
479	struct proc *p;
480{
481	register struct tty *tp = dev->si_tty_tty;
482	struct pt_ioctl *pti = dev->si_drv1;
483	int revents = 0;
484	int s;
485
486	if ((tp->t_state & TS_CONNECTED) == 0)
487		return (seltrue(dev, events, p) | POLLHUP);
488
489	/*
490	 * Need to block timeouts (ttrstart).
491	 */
492	s = spltty();
493
494	if (events & (POLLIN | POLLRDNORM))
495		if ((tp->t_state & TS_ISOPEN) &&
496		    ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
497		     ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
498		     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
499			revents |= events & (POLLIN | POLLRDNORM);
500
501	if (events & (POLLOUT | POLLWRNORM))
502		if (tp->t_state & TS_ISOPEN &&
503		    ((pti->pt_flags & PF_REMOTE) ?
504		     (tp->t_canq.c_cc == 0) :
505		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
506		      (tp->t_canq.c_cc == 0 && (tp->t_iflag & ICANON)))))
507			revents |= events & (POLLOUT | POLLWRNORM);
508
509	if (events & POLLHUP)
510		if ((tp->t_state & TS_CARR_ON) == 0)
511			revents |= POLLHUP;
512
513	if (revents == 0) {
514		if (events & (POLLIN | POLLRDNORM))
515			selrecord(p, &pti->pt_selr);
516
517		if (events & (POLLOUT | POLLWRNORM))
518			selrecord(p, &pti->pt_selw);
519	}
520	splx(s);
521
522	return (revents);
523}
524
525static	int
526ptcwrite(dev, uio, flag)
527	dev_t dev;
528	register struct uio *uio;
529	int flag;
530{
531	register struct tty *tp = dev->si_tty_tty;
532	register u_char *cp = 0;
533	register int cc = 0;
534	u_char locbuf[BUFSIZ];
535	int cnt = 0;
536	struct pt_ioctl *pti = dev->si_drv1;
537	int error = 0;
538
539again:
540	if ((tp->t_state&TS_ISOPEN) == 0)
541		goto block;
542	if (pti->pt_flags & PF_REMOTE) {
543		if (tp->t_canq.c_cc)
544			goto block;
545		while ((uio->uio_resid > 0 || cc > 0) &&
546		       tp->t_canq.c_cc < TTYHOG - 1) {
547			if (cc == 0) {
548				cc = min(uio->uio_resid, BUFSIZ);
549				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
550				cp = locbuf;
551				error = uiomove((caddr_t)cp, cc, uio);
552				if (error)
553					return (error);
554				/* check again for safety */
555				if ((tp->t_state & TS_ISOPEN) == 0) {
556					/* adjust as usual */
557					uio->uio_resid += cc;
558					return (EIO);
559				}
560			}
561			if (cc > 0) {
562				cc = b_to_q((char *)cp, cc, &tp->t_canq);
563				/*
564				 * XXX we don't guarantee that the canq size
565				 * is >= TTYHOG, so the above b_to_q() may
566				 * leave some bytes uncopied.  However, space
567				 * is guaranteed for the null terminator if
568				 * we don't fail here since (TTYHOG - 1) is
569				 * not a multiple of CBSIZE.
570				 */
571				if (cc > 0)
572					break;
573			}
574		}
575		/* adjust for data copied in but not written */
576		uio->uio_resid += cc;
577		(void) putc(0, &tp->t_canq);
578		ttwakeup(tp);
579		wakeup(TSA_PTS_READ(tp));
580		return (0);
581	}
582	while (uio->uio_resid > 0 || cc > 0) {
583		if (cc == 0) {
584			cc = min(uio->uio_resid, BUFSIZ);
585			cp = locbuf;
586			error = uiomove((caddr_t)cp, cc, uio);
587			if (error)
588				return (error);
589			/* check again for safety */
590			if ((tp->t_state & TS_ISOPEN) == 0) {
591				/* adjust for data copied in but not written */
592				uio->uio_resid += cc;
593				return (EIO);
594			}
595		}
596		while (cc > 0) {
597			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
598			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
599				wakeup(TSA_HUP_OR_INPUT(tp));
600				goto block;
601			}
602			(*linesw[tp->t_line].l_rint)(*cp++, tp);
603			cnt++;
604			cc--;
605		}
606		cc = 0;
607	}
608	return (0);
609block:
610	/*
611	 * Come here to wait for slave to open, for space
612	 * in outq, or space in rawq, or an empty canq.
613	 */
614	if ((tp->t_state & TS_CONNECTED) == 0) {
615		/* adjust for data copied in but not written */
616		uio->uio_resid += cc;
617		return (EIO);
618	}
619	if (flag & IO_NDELAY) {
620		/* adjust for data copied in but not written */
621		uio->uio_resid += cc;
622		if (cnt == 0)
623			return (EWOULDBLOCK);
624		return (0);
625	}
626	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
627	if (error) {
628		/* adjust for data copied in but not written */
629		uio->uio_resid += cc;
630		return (error);
631	}
632	goto again;
633}
634
635static	struct tty *
636ptydevtotty(dev)
637	dev_t		dev;
638{
639	if (minor(dev) & ~0xff)
640		return (NULL);
641
642	return dev->si_tty_tty;
643}
644
645/*ARGSUSED*/
646static	int
647ptyioctl(dev, cmd, data, flag, p)
648	dev_t dev;
649	u_long cmd;
650	caddr_t data;
651	int flag;
652	struct proc *p;
653{
654	register struct tty *tp = dev->si_tty_tty;
655	register struct pt_ioctl *pti = dev->si_drv1;
656	register u_char *cc = tp->t_cc;
657	int stop, error;
658
659	if (devsw(dev)->d_open == ptcopen) {
660		switch (cmd) {
661
662		case TIOCGPGRP:
663			/*
664			 * We avoid calling ttioctl on the controller since,
665			 * in that case, tp must be the controlling terminal.
666			 */
667			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
668			return (0);
669
670		case TIOCPKT:
671			if (*(int *)data) {
672				if (pti->pt_flags & PF_UCNTL)
673					return (EINVAL);
674				pti->pt_flags |= PF_PKT;
675			} else
676				pti->pt_flags &= ~PF_PKT;
677			return (0);
678
679		case TIOCUCNTL:
680			if (*(int *)data) {
681				if (pti->pt_flags & PF_PKT)
682					return (EINVAL);
683				pti->pt_flags |= PF_UCNTL;
684			} else
685				pti->pt_flags &= ~PF_UCNTL;
686			return (0);
687
688		case TIOCREMOTE:
689			if (*(int *)data)
690				pti->pt_flags |= PF_REMOTE;
691			else
692				pti->pt_flags &= ~PF_REMOTE;
693			ttyflush(tp, FREAD|FWRITE);
694			return (0);
695		}
696
697		/*
698		 * The rest of the ioctls shouldn't be called until
699		 * the slave is open.
700		 */
701		if ((tp->t_state & TS_ISOPEN) == 0)
702			return (EAGAIN);
703
704		switch (cmd) {
705#ifdef COMPAT_43
706		case TIOCSETP:
707		case TIOCSETN:
708#endif
709		case TIOCSETD:
710		case TIOCSETA:
711		case TIOCSETAW:
712		case TIOCSETAF:
713			/*
714			 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
715			 * ttywflush(tp) will hang if there are characters in
716			 * the outq.
717			 */
718			ndflush(&tp->t_outq, tp->t_outq.c_cc);
719			break;
720
721		case TIOCSIG:
722			if (*(unsigned int *)data >= NSIG ||
723			    *(unsigned int *)data == 0)
724				return(EINVAL);
725			if ((tp->t_lflag&NOFLSH) == 0)
726				ttyflush(tp, FREAD|FWRITE);
727			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
728			if ((*(unsigned int *)data == SIGINFO) &&
729			    ((tp->t_lflag&NOKERNINFO) == 0))
730				ttyinfo(tp);
731			return(0);
732		}
733	}
734	if (cmd == TIOCEXT) {
735		/*
736		 * When the EXTPROC bit is being toggled, we need
737		 * to send an TIOCPKT_IOCTL if the packet driver
738		 * is turned on.
739		 */
740		if (*(int *)data) {
741			if (pti->pt_flags & PF_PKT) {
742				pti->pt_send |= TIOCPKT_IOCTL;
743				ptcwakeup(tp, FREAD);
744			}
745			tp->t_lflag |= EXTPROC;
746		} else {
747			if ((tp->t_lflag & EXTPROC) &&
748			    (pti->pt_flags & PF_PKT)) {
749				pti->pt_send |= TIOCPKT_IOCTL;
750				ptcwakeup(tp, FREAD);
751			}
752			tp->t_lflag &= ~EXTPROC;
753		}
754		return(0);
755	}
756	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
757	if (error == ENOIOCTL)
758		 error = ttioctl(tp, cmd, data, flag);
759	if (error == ENOIOCTL) {
760		if (pti->pt_flags & PF_UCNTL &&
761		    (cmd & ~0xff) == UIOCCMD(0)) {
762			if (cmd & 0xff) {
763				pti->pt_ucntl = (u_char)cmd;
764				ptcwakeup(tp, FREAD);
765			}
766			return (0);
767		}
768		error = ENOTTY;
769	}
770	/*
771	 * If external processing and packet mode send ioctl packet.
772	 */
773	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
774		switch(cmd) {
775		case TIOCSETA:
776		case TIOCSETAW:
777		case TIOCSETAF:
778#ifdef COMPAT_43
779		case TIOCSETP:
780		case TIOCSETN:
781#endif
782#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
783		case TIOCSETC:
784		case TIOCSLTC:
785		case TIOCLBIS:
786		case TIOCLBIC:
787		case TIOCLSET:
788#endif
789			pti->pt_send |= TIOCPKT_IOCTL;
790			ptcwakeup(tp, FREAD);
791		default:
792			break;
793		}
794	}
795	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
796		&& CCEQ(cc[VSTART], CTRL('q'));
797	if (pti->pt_flags & PF_NOSTOP) {
798		if (stop) {
799			pti->pt_send &= ~TIOCPKT_NOSTOP;
800			pti->pt_send |= TIOCPKT_DOSTOP;
801			pti->pt_flags &= ~PF_NOSTOP;
802			ptcwakeup(tp, FREAD);
803		}
804	} else {
805		if (!stop) {
806			pti->pt_send &= ~TIOCPKT_DOSTOP;
807			pti->pt_send |= TIOCPKT_NOSTOP;
808			pti->pt_flags |= PF_NOSTOP;
809			ptcwakeup(tp, FREAD);
810		}
811	}
812	return (error);
813}
814
815
816static void ptc_drvinit __P((void *unused));
817
818static void
819ptc_drvinit(unused)
820	void *unused;
821{
822	static int ptc_devsw_installed;
823
824	if( ! ptc_devsw_installed ) {
825		cdevsw_add(&pts_cdevsw);
826		cdevsw_add(&ptc_cdevsw);
827		ptc_devsw_installed = 1;
828    	}
829}
830
831SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
832