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