pty.c revision 31778
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.48 1997/12/06 13:24:10 bde 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
58#ifdef DEVFS
59#include <sys/devfsext.h>
60#endif /*DEVFS*/
61
62#ifdef notyet
63static void ptyattach __P((int n));
64#endif
65static void ptsstart __P((struct tty *tp));
66static void ptcwakeup __P((struct tty *tp, int flag));
67
68static	d_open_t	ptsopen;
69static	d_close_t	ptsclose;
70static	d_read_t	ptsread;
71static	d_write_t	ptswrite;
72static	d_ioctl_t	ptyioctl;
73static	d_stop_t	ptsstop;
74static	d_devtotty_t	ptydevtotty;
75static	d_open_t	ptcopen;
76static	d_close_t	ptcclose;
77static	d_read_t	ptcread;
78static	d_write_t	ptcwrite;
79static	d_poll_t	ptcpoll;
80
81#define CDEV_MAJOR_S 5
82#define CDEV_MAJOR_C 6
83static struct cdevsw pts_cdevsw =
84	{ ptsopen,	ptsclose,	ptsread,	ptswrite,	/*5*/
85	  ptyioctl,	ptsstop,	nullreset,	ptydevtotty,/* ttyp */
86	  ttpoll,	nommap,		NULL,	"pts",	NULL,	-1 };
87
88static struct cdevsw ptc_cdevsw =
89	{ ptcopen,	ptcclose,	ptcread,	ptcwrite,	/*6*/
90	  ptyioctl,	nullstop,	nullreset,	ptydevtotty,/* ptyp */
91	  ptcpoll,	nommap,		NULL,	"ptc",	NULL,	-1 };
92
93
94#if NPTY == 1
95#undef NPTY
96#define	NPTY	32		/* crude XXX */
97#warning	You have only one pty defined, redefining to 32.
98#endif
99
100#ifdef DEVFS
101#define MAXUNITS (8 * 32)
102static	void	*devfs_token_pts[MAXUNITS];
103static	void	*devfs_token_ptc[MAXUNITS];
104static  const	char jnames[] = "pqrsPQRS";
105#if NPTY > MAXUNITS
106#undef NPTY
107#define NPTY MAXUNITS
108#warning	Can't have more than 256 pty's with DEVFS defined.
109#endif
110#endif
111
112#define BUFSIZ 100		/* Chunk size iomoved to/from user */
113
114/*
115 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
116 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
117 */
118static struct	tty pt_tty[NPTY];	/* XXX */
119static struct	pt_ioctl {
120	int	pt_flags;
121	struct	selinfo pt_selr, pt_selw;
122	u_char	pt_send;
123	u_char	pt_ucntl;
124} pt_ioctl[NPTY];		/* XXX */
125static int	npty = NPTY;		/* for pstat -t */
126
127#define	PF_PKT		0x08		/* packet mode */
128#define	PF_STOPPED	0x10		/* user told stopped */
129#define	PF_REMOTE	0x20		/* remote and flow controlled input */
130#define	PF_NOSTOP	0x40
131#define PF_UCNTL	0x80		/* user control mode */
132
133#ifdef notyet
134/*
135 * Establish n (or default if n is 1) ptys in the system.
136 *
137 * XXX cdevsw & pstat require the array `pty[]' to be an array
138 */
139static void
140ptyattach(n)
141	int n;
142{
143	char *mem;
144	register u_long ntb;
145#define	DEFAULT_NPTY	32
146
147	/* maybe should allow 0 => none? */
148	if (n <= 1)
149		n = DEFAULT_NPTY;
150	ntb = n * sizeof(struct tty);
151	mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
152	    M_DEVBUF, M_WAITOK);
153	pt_tty = (struct tty *)mem;
154	mem = (char *)ALIGN(mem + ntb);
155	pt_ioctl = (struct pt_ioctl *)mem;
156	npty = n;
157}
158#endif
159
160/*ARGSUSED*/
161static	int
162ptsopen(dev, flag, devtype, p)
163	dev_t dev;
164	int flag, devtype;
165	struct proc *p;
166{
167	register struct tty *tp;
168	int error;
169
170	if (minor(dev) >= npty)
171		return (ENXIO);
172	tp = &pt_tty[minor(dev)];
173	if ((tp->t_state & TS_ISOPEN) == 0) {
174		ttychars(tp);		/* Set up default chars */
175		tp->t_iflag = TTYDEF_IFLAG;
176		tp->t_oflag = TTYDEF_OFLAG;
177		tp->t_lflag = TTYDEF_LFLAG;
178		tp->t_cflag = TTYDEF_CFLAG;
179		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
180		ttsetwater(tp);		/* would be done in xxparam() */
181	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
182		return (EBUSY);
183	if (tp->t_oproc)			/* Ctrlr still around. */
184		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
185	while ((tp->t_state & TS_CARR_ON) == 0) {
186		if (flag&FNONBLOCK)
187			break;
188		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
189				 "ptsopn", 0);
190		if (error)
191			return (error);
192	}
193	error = (*linesw[tp->t_line].l_open)(dev, tp);
194	if (error == 0)
195		ptcwakeup(tp, FREAD|FWRITE);
196	return (error);
197}
198
199static	int
200ptsclose(dev, flag, mode, p)
201	dev_t dev;
202	int flag, mode;
203	struct proc *p;
204{
205	register struct tty *tp;
206	int err;
207
208	tp = &pt_tty[minor(dev)];
209	err = (*linesw[tp->t_line].l_close)(tp, flag);
210	ptsstop(tp, FREAD|FWRITE);
211	(void) ttyclose(tp);
212	return (err);
213}
214
215static	int
216ptsread(dev, uio, flag)
217	dev_t dev;
218	struct uio *uio;
219	int flag;
220{
221	struct proc *p = curproc;
222	register struct tty *tp = &pt_tty[minor(dev)];
223	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
224	int error = 0;
225
226again:
227	if (pti->pt_flags & PF_REMOTE) {
228		while (isbackground(p, tp)) {
229			if ((p->p_sigignore & sigmask(SIGTTIN)) ||
230			    (p->p_sigmask & sigmask(SIGTTIN)) ||
231			    p->p_pgrp->pg_jobc == 0 ||
232			    p->p_flag & P_PPWAIT)
233				return (EIO);
234			pgsignal(p->p_pgrp, SIGTTIN, 1);
235			error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg",
236					 0);
237			if (error)
238				return (error);
239		}
240		if (tp->t_canq.c_cc == 0) {
241			if (flag & IO_NDELAY)
242				return (EWOULDBLOCK);
243			error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
244					 "ptsin", 0);
245			if (error)
246				return (error);
247			goto again;
248		}
249		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
250			if (ureadc(getc(&tp->t_canq), uio) < 0) {
251				error = EFAULT;
252				break;
253			}
254		if (tp->t_canq.c_cc == 1)
255			(void) getc(&tp->t_canq);
256		if (tp->t_canq.c_cc)
257			return (error);
258	} else
259		if (tp->t_oproc)
260			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
261	ptcwakeup(tp, FWRITE);
262	return (error);
263}
264
265/*
266 * Write to pseudo-tty.
267 * Wakeups of controlling tty will happen
268 * indirectly, when tty driver calls ptsstart.
269 */
270static	int
271ptswrite(dev, uio, flag)
272	dev_t dev;
273	struct uio *uio;
274	int flag;
275{
276	register struct tty *tp;
277
278	tp = &pt_tty[minor(dev)];
279	if (tp->t_oproc == 0)
280		return (EIO);
281	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
282}
283
284/*
285 * Start output on pseudo-tty.
286 * Wake up process selecting or sleeping for input from controlling tty.
287 */
288static void
289ptsstart(tp)
290	struct tty *tp;
291{
292	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
293
294	if (tp->t_state & TS_TTSTOP)
295		return;
296	if (pti->pt_flags & PF_STOPPED) {
297		pti->pt_flags &= ~PF_STOPPED;
298		pti->pt_send = TIOCPKT_START;
299	}
300	ptcwakeup(tp, FREAD);
301}
302
303static void
304ptcwakeup(tp, flag)
305	struct tty *tp;
306	int flag;
307{
308	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
309
310	if (flag & FREAD) {
311		selwakeup(&pti->pt_selr);
312		wakeup(TSA_PTC_READ(tp));
313	}
314	if (flag & FWRITE) {
315		selwakeup(&pti->pt_selw);
316		wakeup(TSA_PTC_WRITE(tp));
317	}
318}
319
320static	int
321ptcopen(dev, flag, devtype, p)
322	dev_t dev;
323	int flag, devtype;
324	struct proc *p;
325{
326	register struct tty *tp;
327	struct pt_ioctl *pti;
328
329	if (minor(dev) >= npty)
330		return (ENXIO);
331	tp = &pt_tty[minor(dev)];
332	if (tp->t_oproc)
333		return (EIO);
334	tp->t_oproc = ptsstart;
335#ifdef sun4c
336	tp->t_stop = ptsstop;
337#endif
338	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
339	tp->t_lflag &= ~EXTPROC;
340	pti = &pt_ioctl[minor(dev)];
341	pti->pt_flags = 0;
342	pti->pt_send = 0;
343	pti->pt_ucntl = 0;
344	return (0);
345}
346
347static	int
348ptcclose(dev, flags, fmt, p)
349	dev_t dev;
350	int flags;
351	int fmt;
352	struct proc *p;
353{
354	register struct tty *tp;
355
356	tp = &pt_tty[minor(dev)];
357	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
358
359	/*
360	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
361	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
362	 * l_modem()s that ignore carrier drop make no sense for ptys but
363	 * may be in use because other parts of the line discipline make
364	 * sense for ptys.  Recover by doing everything that a normal
365	 * ttymodem() would have done except for sending a SIGHUP.
366	 */
367	if (tp->t_state & TS_ISOPEN) {
368		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
369		tp->t_state |= TS_ZOMBIE;
370		ttyflush(tp, FREAD | FWRITE);
371	}
372
373	tp->t_oproc = 0;		/* mark closed */
374	return (0);
375}
376
377static	int
378ptcread(dev, uio, flag)
379	dev_t dev;
380	struct uio *uio;
381	int flag;
382{
383	register struct tty *tp = &pt_tty[minor(dev)];
384	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
385	char buf[BUFSIZ];
386	int error = 0, cc;
387
388	/*
389	 * We want to block until the slave
390	 * is open, and there's something to read;
391	 * but if we lost the slave or we're NBIO,
392	 * then return the appropriate error instead.
393	 */
394	for (;;) {
395		if (tp->t_state&TS_ISOPEN) {
396			if (pti->pt_flags&PF_PKT && pti->pt_send) {
397				error = ureadc((int)pti->pt_send, uio);
398				if (error)
399					return (error);
400				if (pti->pt_send & TIOCPKT_IOCTL) {
401					cc = min(uio->uio_resid,
402						sizeof(tp->t_termios));
403					uiomove((caddr_t)&tp->t_termios, cc,
404						uio);
405				}
406				pti->pt_send = 0;
407				return (0);
408			}
409			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
410				error = ureadc((int)pti->pt_ucntl, uio);
411				if (error)
412					return (error);
413				pti->pt_ucntl = 0;
414				return (0);
415			}
416			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
417				break;
418		}
419		if ((tp->t_state & TS_CONNECTED) == 0)
420			return (0);	/* EOF */
421		if (flag & IO_NDELAY)
422			return (EWOULDBLOCK);
423		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
424		if (error)
425			return (error);
426	}
427	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
428		error = ureadc(0, uio);
429	while (uio->uio_resid > 0 && error == 0) {
430		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
431		if (cc <= 0)
432			break;
433		error = uiomove(buf, cc, uio);
434	}
435	ttwwakeup(tp);
436	return (error);
437}
438
439static	void
440ptsstop(tp, flush)
441	register struct tty *tp;
442	int flush;
443{
444	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
445	int flag;
446
447	/* note: FLUSHREAD and FLUSHWRITE already ok */
448	if (flush == 0) {
449		flush = TIOCPKT_STOP;
450		pti->pt_flags |= PF_STOPPED;
451	} else
452		pti->pt_flags &= ~PF_STOPPED;
453	pti->pt_send |= flush;
454	/* change of perspective */
455	flag = 0;
456	if (flush & FREAD)
457		flag |= FWRITE;
458	if (flush & FWRITE)
459		flag |= FREAD;
460	ptcwakeup(tp, flag);
461}
462
463static	int
464ptcpoll(dev, events, p)
465	dev_t dev;
466	int events;
467	struct proc *p;
468{
469	register struct tty *tp = &pt_tty[minor(dev)];
470	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
471	int revents = 0;
472	int s;
473
474	if ((tp->t_state & TS_CONNECTED) == 0)
475		return (seltrue(dev, events, p) | POLLHUP);
476
477	/*
478	 * Need to block timeouts (ttrstart).
479	 */
480	s = spltty();
481
482	if (events & (POLLIN | POLLRDNORM))
483		if ((tp->t_state & TS_ISOPEN) &&
484		    ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
485		     ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
486		     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
487			revents |= events & (POLLIN | POLLRDNORM);
488
489	if (events & (POLLOUT | POLLWRNORM))
490		if (tp->t_state & TS_ISOPEN &&
491		    ((pti->pt_flags & PF_REMOTE) ?
492		     (tp->t_canq.c_cc == 0) :
493		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
494		      (tp->t_canq.c_cc == 0 && (tp->t_iflag & ICANON)))))
495			revents |= events & (POLLOUT | POLLWRNORM);
496
497	if (events & POLLHUP)
498		if ((tp->t_state & TS_CARR_ON) == 0)
499			revents |= POLLHUP;
500
501	if (revents == 0) {
502		if (events & (POLLIN | POLLRDNORM))
503			selrecord(p, &pti->pt_selr);
504
505		if (events & (POLLOUT | POLLWRNORM))
506			selrecord(p, &pti->pt_selw);
507	}
508	splx(s);
509
510	return (revents);
511}
512
513static	int
514ptcwrite(dev, uio, flag)
515	dev_t dev;
516	register struct uio *uio;
517	int flag;
518{
519	register struct tty *tp = &pt_tty[minor(dev)];
520	register u_char *cp = 0;
521	register int cc = 0;
522	u_char locbuf[BUFSIZ];
523	int cnt = 0;
524	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
525	int error = 0;
526
527again:
528	if ((tp->t_state&TS_ISOPEN) == 0)
529		goto block;
530	if (pti->pt_flags & PF_REMOTE) {
531		if (tp->t_canq.c_cc)
532			goto block;
533		while ((uio->uio_resid > 0 || cc > 0) &&
534		       tp->t_canq.c_cc < TTYHOG - 1) {
535			if (cc == 0) {
536				cc = min(uio->uio_resid, BUFSIZ);
537				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
538				cp = locbuf;
539				error = uiomove((caddr_t)cp, cc, uio);
540				if (error)
541					return (error);
542				/* check again for safety */
543				if ((tp->t_state & TS_ISOPEN) == 0) {
544					/* adjust as usual */
545					uio->uio_resid += cc;
546					return (EIO);
547				}
548			}
549			if (cc > 0) {
550				cc = b_to_q((char *)cp, cc, &tp->t_canq);
551				/*
552				 * XXX we don't guarantee that the canq size
553				 * is >= TTYHOG, so the above b_to_q() may
554				 * leave some bytes uncopied.  However, space
555				 * is guaranteed for the null terminator if
556				 * we don't fail here since (TTYHOG - 1) is
557				 * not a multiple of CBSIZE.
558				 */
559				if (cc > 0)
560					break;
561			}
562		}
563		/* adjust for data copied in but not written */
564		uio->uio_resid += cc;
565		(void) putc(0, &tp->t_canq);
566		ttwakeup(tp);
567		wakeup(TSA_PTS_READ(tp));
568		return (0);
569	}
570	while (uio->uio_resid > 0 || cc > 0) {
571		if (cc == 0) {
572			cc = min(uio->uio_resid, BUFSIZ);
573			cp = locbuf;
574			error = uiomove((caddr_t)cp, cc, uio);
575			if (error)
576				return (error);
577			/* check again for safety */
578			if ((tp->t_state & TS_ISOPEN) == 0) {
579				/* adjust for data copied in but not written */
580				uio->uio_resid += cc;
581				return (EIO);
582			}
583		}
584		while (cc > 0) {
585			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
586			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
587				wakeup(TSA_HUP_OR_INPUT(tp));
588				goto block;
589			}
590			(*linesw[tp->t_line].l_rint)(*cp++, tp);
591			cnt++;
592			cc--;
593		}
594		cc = 0;
595	}
596	return (0);
597block:
598	/*
599	 * Come here to wait for slave to open, for space
600	 * in outq, or space in rawq, or an empty canq.
601	 */
602	if ((tp->t_state & TS_CONNECTED) == 0) {
603		/* adjust for data copied in but not written */
604		uio->uio_resid += cc;
605		return (EIO);
606	}
607	if (flag & IO_NDELAY) {
608		/* adjust for data copied in but not written */
609		uio->uio_resid += cc;
610		if (cnt == 0)
611			return (EWOULDBLOCK);
612		return (0);
613	}
614	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
615	if (error) {
616		/* adjust for data copied in but not written */
617		uio->uio_resid += cc;
618		return (error);
619	}
620	goto again;
621}
622
623static	struct tty *
624ptydevtotty(dev)
625	dev_t		dev;
626{
627	if (minor(dev) >= npty)
628		return (NULL);
629
630	return &pt_tty[minor(dev)];
631}
632
633/*ARGSUSED*/
634static	int
635ptyioctl(dev, cmd, data, flag, p)
636	dev_t dev;
637	int cmd;
638	caddr_t data;
639	int flag;
640	struct proc *p;
641{
642	register struct tty *tp = &pt_tty[minor(dev)];
643	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
644	register u_char *cc = tp->t_cc;
645	int stop, error;
646
647	/*
648	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
649	 * ttywflush(tp) will hang if there are characters in the outq.
650	 */
651	if (cmd == TIOCEXT) {
652		/*
653		 * When the EXTPROC bit is being toggled, we need
654		 * to send an TIOCPKT_IOCTL if the packet driver
655		 * is turned on.
656		 */
657		if (*(int *)data) {
658			if (pti->pt_flags & PF_PKT) {
659				pti->pt_send |= TIOCPKT_IOCTL;
660				ptcwakeup(tp, FREAD);
661			}
662			tp->t_lflag |= EXTPROC;
663		} else {
664			if ((tp->t_lflag & EXTPROC) &&
665			    (pti->pt_flags & PF_PKT)) {
666				pti->pt_send |= TIOCPKT_IOCTL;
667				ptcwakeup(tp, FREAD);
668			}
669			tp->t_lflag &= ~EXTPROC;
670		}
671		return(0);
672	} else
673	if (cdevsw[major(dev)]->d_open == ptcopen)
674		switch (cmd) {
675
676		case TIOCGPGRP:
677			/*
678			 * We aviod calling ttioctl on the controller since,
679			 * in that case, tp must be the controlling terminal.
680			 */
681			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
682			return (0);
683
684		case TIOCPKT:
685			if (*(int *)data) {
686				if (pti->pt_flags & PF_UCNTL)
687					return (EINVAL);
688				pti->pt_flags |= PF_PKT;
689			} else
690				pti->pt_flags &= ~PF_PKT;
691			return (0);
692
693		case TIOCUCNTL:
694			if (*(int *)data) {
695				if (pti->pt_flags & PF_PKT)
696					return (EINVAL);
697				pti->pt_flags |= PF_UCNTL;
698			} else
699				pti->pt_flags &= ~PF_UCNTL;
700			return (0);
701
702		case TIOCREMOTE:
703			if (*(int *)data)
704				pti->pt_flags |= PF_REMOTE;
705			else
706				pti->pt_flags &= ~PF_REMOTE;
707			ttyflush(tp, FREAD|FWRITE);
708			return (0);
709
710#ifdef COMPAT_43
711		case TIOCSETP:
712		case TIOCSETN:
713#endif
714		case TIOCSETD:
715		case TIOCSETA:
716		case TIOCSETAW:
717		case TIOCSETAF:
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	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
734	if (error == ENOIOCTL)
735		 error = ttioctl(tp, cmd, data, flag);
736	if (error == ENOIOCTL) {
737		if (pti->pt_flags & PF_UCNTL &&
738		    (cmd & ~0xff) == UIOCCMD(0)) {
739			if (cmd & 0xff) {
740				pti->pt_ucntl = (u_char)cmd;
741				ptcwakeup(tp, FREAD);
742			}
743			return (0);
744		}
745		error = ENOTTY;
746	}
747	/*
748	 * If external processing and packet mode send ioctl packet.
749	 */
750	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
751		switch(cmd) {
752		case TIOCSETA:
753		case TIOCSETAW:
754		case TIOCSETAF:
755#ifdef COMPAT_43
756		case TIOCSETP:
757		case TIOCSETN:
758#endif
759#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
760		case TIOCSETC:
761		case TIOCSLTC:
762		case TIOCLBIS:
763		case TIOCLBIC:
764		case TIOCLSET:
765#endif
766			pti->pt_send |= TIOCPKT_IOCTL;
767			ptcwakeup(tp, FREAD);
768		default:
769			break;
770		}
771	}
772	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
773		&& CCEQ(cc[VSTART], CTRL('q'));
774	if (pti->pt_flags & PF_NOSTOP) {
775		if (stop) {
776			pti->pt_send &= ~TIOCPKT_NOSTOP;
777			pti->pt_send |= TIOCPKT_DOSTOP;
778			pti->pt_flags &= ~PF_NOSTOP;
779			ptcwakeup(tp, FREAD);
780		}
781	} else {
782		if (!stop) {
783			pti->pt_send &= ~TIOCPKT_DOSTOP;
784			pti->pt_send |= TIOCPKT_NOSTOP;
785			pti->pt_flags |= PF_NOSTOP;
786			ptcwakeup(tp, FREAD);
787		}
788	}
789	return (error);
790}
791
792static ptc_devsw_installed = 0;
793
794static void ptc_drvinit __P((void *unused));
795static void
796ptc_drvinit(unused)
797	void *unused;
798{
799#ifdef DEVFS
800	int i,j,k;
801#endif
802	dev_t dev;
803
804	if( ! ptc_devsw_installed ) {
805		dev = makedev(CDEV_MAJOR_S, 0);
806		cdevsw_add(&dev, &pts_cdevsw, NULL);
807		dev = makedev(CDEV_MAJOR_C, 0);
808		cdevsw_add(&dev, &ptc_cdevsw, NULL);
809		ptc_devsw_installed = 1;
810#ifdef DEVFS
811		for ( i = 0 ; i<NPTY ; i++ ) {
812			j = i / 32;
813			k = i % 32;
814			devfs_token_pts[i] =
815				devfs_add_devswf(&pts_cdevsw,i,
816						DV_CHR,0,0,0666,
817						"tty%c%n",jnames[j],k);
818			devfs_token_ptc[i] =
819				devfs_add_devswf(&ptc_cdevsw,i,
820						DV_CHR,0,0,0666,
821						"pty%c%n",jnames[j],k);
822		}
823#endif
824    	}
825}
826
827SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
828