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