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