xref: /netbsd-src/sys/kern/tty_pty.c (revision 020c240b453cba5a4a8b05f3989e85e4868bc36e)
1 /*
2  * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
3  * 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  *	from: @(#)tty_pty.c	7.21 (Berkeley) 5/30/91
34  *	$Id: tty_pty.c,v 1.7 1993/06/27 06:06:47 andrew Exp $
35  */
36 
37 /*
38  * Pseudo-teletype Driver
39  * (Actually two drivers, requiring two entries in 'cdevsw')
40  */
41 #include "pty.h"
42 
43 #if NPTY > 0
44 #include "param.h"
45 #include "systm.h"
46 #include "ioctl.h"
47 #include "select.h"
48 #include "tty.h"
49 #include "conf.h"
50 #include "file.h"
51 #include "malloc.h"
52 #include "proc.h"
53 #include "uio.h"
54 #include "kernel.h"
55 #include "vnode.h"
56 
57 #if NPTY == 1
58 #undef NPTY
59 #define	NPTY	32		/* crude XXX */
60 #endif
61 
62 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
63 
64 /*
65  * pts == /dev/tty[pqrs]?
66  * ptc == /dev/pty[pqrs]?
67  */
68 struct	tty *pt_tty[NPTY];
69 struct	pt_ioctl {
70 	int	pt_flags;
71 	struct selinfo pt_selr, pt_selw;
72 	u_char	pt_send;
73 	u_char	pt_ucntl;
74 } pt_ioctl[NPTY];
75 int	npty = NPTY;		/* for pstat -t */
76 
77 #define	PF_RCOLL	0x01
78 #define	PF_WCOLL	0x02
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 
85 void ptcwakeup __P((struct tty *tp, int flag));
86 
87 /*ARGSUSED*/
88 int
89 ptsopen(dev, flag, devtype, p)
90 	dev_t dev;
91 	int flag, devtype;
92 	struct proc *p;
93 {
94 	register struct tty *tp;
95 	int error;
96 
97 #ifdef lint
98 	npty = npty;
99 #endif
100 	if (minor(dev) >= NPTY)
101 		return (ENXIO);
102 	if(!pt_tty[minor(dev)]) {
103 		MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
104 		bzero(tp, sizeof(struct tty));
105 		pt_tty[minor(dev)] = tp;
106 	} else
107 		tp = pt_tty[minor(dev)];
108 	if ((tp->t_state & TS_ISOPEN) == 0) {
109 		tp->t_state |= TS_WOPEN;
110 		ttychars(tp);		/* Set up default chars */
111 		tp->t_iflag = TTYDEF_IFLAG;
112 		tp->t_oflag = TTYDEF_OFLAG;
113 		tp->t_lflag = TTYDEF_LFLAG;
114 		tp->t_cflag = TTYDEF_CFLAG;
115 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
116 		ttsetwater(tp);		/* would be done in xxparam() */
117 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
118 		return (EBUSY);
119 	if (tp->t_oproc)			/* Ctrlr still around. */
120 		tp->t_state |= TS_CARR_ON;
121 	while ((tp->t_state & TS_CARR_ON) == 0) {
122 		tp->t_state |= TS_WOPEN;
123 		if (flag&FNONBLOCK)
124 			break;
125 		if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
126 		    ttopen, 0))
127 			return (error);
128 	}
129 	error = (*linesw[tp->t_line].l_open)(dev, tp);
130 	ptcwakeup(tp, FREAD|FWRITE);
131 	return (error);
132 }
133 
134 int
135 ptsclose(dev, flag, mode, p)
136 	dev_t dev;
137 	int flag, mode;
138 	struct proc *p;
139 {
140 	register struct tty *tp;
141 
142 	tp = pt_tty[minor(dev)];
143 	(*linesw[tp->t_line].l_close)(tp, flag);
144 	ttyclose(tp);
145 	ptcwakeup(tp, FREAD|FWRITE);
146 	return(0);
147 }
148 
149 int
150 ptsread(dev, uio, flag)
151 	dev_t dev;
152 	struct uio *uio;
153 	int flag;
154 {
155 	struct proc *p = curproc;
156 	register struct tty *tp = pt_tty[minor(dev)];
157 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
158 	int error = 0;
159 
160 again:
161 	if (pti->pt_flags & PF_REMOTE) {
162 		while (isbackground(p, tp)) {
163 			if ((p->p_sigignore & sigmask(SIGTTIN)) ||
164 			    (p->p_sigmask & sigmask(SIGTTIN)) ||
165 			    p->p_pgrp->pg_jobc == 0 ||
166 			    p->p_flag&SPPWAIT)
167 				return (EIO);
168 			pgsignal(p->p_pgrp, SIGTTIN, 1);
169 			if (error = ttysleep(tp, (caddr_t)&lbolt,
170 			    TTIPRI | PCATCH, ttybg, 0))
171 				return (error);
172 		}
173 		if (RB_LEN(&tp->t_can) == 0) {
174 			if (flag & IO_NDELAY)
175 				return (EWOULDBLOCK);
176 			if (error = ttysleep(tp, (caddr_t)&tp->t_can,
177 			    TTIPRI | PCATCH, ttyin, 0))
178 				return (error);
179 			goto again;
180 		}
181 		while (RB_LEN(&tp->t_can) > 1 && uio->uio_resid > 0)
182 			if (ureadc(rbgetc(&tp->t_can), uio) < 0) {
183 				error = EFAULT;
184 				break;
185 			}
186 		if (RB_LEN(&tp->t_can) == 1)
187 			(void) rbgetc(&tp->t_can);
188 		if (RB_LEN(&tp->t_can))
189 			return (error);
190 	} else
191 		if (tp->t_oproc)
192 			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
193 	ptcwakeup(tp, FWRITE);
194 	return (error);
195 }
196 
197 /*
198  * Write to pseudo-tty.
199  * Wakeups of controlling tty will happen
200  * indirectly, when tty driver calls ptsstart.
201  */
202 int
203 ptswrite(dev, uio, flag)
204 	dev_t dev;
205 	struct uio *uio;
206 	int flag;
207 {
208 	register struct tty *tp;
209 
210 	tp = pt_tty[minor(dev)];
211 	if (tp->t_oproc == 0)
212 		return (EIO);
213 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
214 }
215 
216 /*
217  * Start output on pseudo-tty.
218  * Wake up process selecting or sleeping for input from controlling tty.
219  */
220 int
221 ptsstart(tp)
222 	struct tty *tp;
223 {
224 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
225 
226 	if (tp->t_state & TS_TTSTOP)
227 		return 0;	/* XXX should we return 1? */
228 	if (pti->pt_flags & PF_STOPPED) {
229 		pti->pt_flags &= ~PF_STOPPED;
230 		pti->pt_send = TIOCPKT_START;
231 	}
232 	ptcwakeup(tp, FREAD);
233 
234 	return 0;
235 }
236 
237 void
238 ptcwakeup(tp, flag)
239 	struct tty *tp;
240 	int flag;
241 {
242 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
243 
244 	if (flag & FREAD) {
245 		selwakeup(&pti->pt_selr);
246 		wakeup((caddr_t)&tp->t_out.rb_tl);
247 	}
248 	if (flag & FWRITE) {
249 		selwakeup(&pti->pt_selw);
250 		wakeup((caddr_t)&tp->t_raw.rb_hd);
251 	}
252 }
253 
254 /*ARGSUSED*/
255 #ifdef __STDC__
256 int
257 ptcopen(dev_t dev, int flag, int devtype, struct proc *p)
258 #else
259 int
260 ptcopen(dev, flag, devtype, p)
261 	dev_t dev;
262 	int flag, devtype;
263 	struct proc *p;
264 #endif
265 {
266 	register struct tty *tp;
267 	struct pt_ioctl *pti;
268 
269 	if (minor(dev) >= NPTY)
270 		return (ENXIO);
271 	if(!pt_tty[minor(dev)]) {
272 		MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
273 		bzero(tp, sizeof(struct tty));
274 		pt_tty[minor(dev)] = tp;
275 	} else
276 		tp = pt_tty[minor(dev)];
277 	if (tp->t_oproc)
278 		return (EIO);
279 	tp->t_oproc = ptsstart;
280 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
281 	tp->t_lflag &= ~EXTPROC;
282 	pti = &pt_ioctl[minor(dev)];
283 	pti->pt_flags = 0;
284 	pti->pt_send = 0;
285 	pti->pt_ucntl = 0;
286 	return (0);
287 }
288 
289 extern struct tty *constty;	/* -hv- 06.Oct.92*/
290 
291 int
292 ptcclose(dev)
293 	dev_t dev;
294 {
295 	register struct tty *tp;
296 
297 	tp = pt_tty[minor(dev)];
298 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
299 	tp->t_state &= ~TS_CARR_ON;
300 	tp->t_oproc = 0;		/* mark closed */
301 	tp->t_session = 0;
302 
303 /* XXX -hv- 6.Oct.92 this prevents the "hanging console bug" with X11 */
304 	if (constty==tp)
305 		constty = 0;
306 
307 #if 0
308 	/*
309 	 * currently, we do not free the pty structures once they have
310 	 * been allocated. Two reasons: cheap to keep them around, and
311 	 * I don't want to spend my time finding the exact variables that
312 	 * will tell me if the slave/master are closed and if I can free
313 	 * them. <deraadt@fsa.ca>
314 	 */
315 	FREE(tp, M_TTYS);
316 	pt_tty[minor(dev)] = (struct tty *)NULL;
317 #endif
318 	return (0);
319 }
320 
321 int
322 ptcread(dev, uio, flag)
323 	dev_t dev;
324 	struct uio *uio;
325 	int flag;
326 {
327 	register struct tty *tp = pt_tty[minor(dev)];
328 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
329 	char buf[BUFSIZ];
330 	int error = 0, cc;
331 
332 	/*
333 	 * We want to block until the slave
334 	 * is open, and there's something to read;
335 	 * but if we lost the slave or we're NBIO,
336 	 * then return the appropriate error instead.
337 	 */
338 	for (;;) {
339 		if (tp->t_state&TS_ISOPEN) {
340 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
341 				error = ureadc((int)pti->pt_send, uio);
342 				if (error)
343 					return (error);
344 				if (pti->pt_send & TIOCPKT_IOCTL) {
345 					cc = MIN(uio->uio_resid,
346 						sizeof(tp->t_termios));
347 					uiomove((caddr_t)&tp->t_termios, cc,
348 						uio);
349 				}
350 				pti->pt_send = 0;
351 				return (0);
352 			}
353 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
354 				error = ureadc((int)pti->pt_ucntl, uio);
355 				if (error)
356 					return (error);
357 				pti->pt_ucntl = 0;
358 				return (0);
359 			}
360 			if (RB_LEN(&tp->t_out) && (tp->t_state&TS_TTSTOP) == 0)
361 				break;
362 		}
363 		if ((tp->t_state&TS_CARR_ON) == 0)
364 			return (0);	/* EOF */
365 		if (flag & IO_NDELAY)
366 			return (EWOULDBLOCK);
367 		if (error = tsleep((caddr_t)&tp->t_out.rb_tl, TTIPRI | PCATCH,
368 		    ttyin, 0))
369 			return (error);
370 	}
371 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
372 		error = ureadc(0, uio);
373 	while (uio->uio_resid > 0 && error == 0) {
374 #ifdef was
375 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
376 #else
377 		cc = min(MIN(uio->uio_resid, BUFSIZ), RB_CONTIGGET(&tp->t_out));
378 		if (cc) {
379 			rbunpack(tp->t_out.rb_hd, buf, cc);
380 			tp->t_out.rb_hd =
381 				RB_ROLLOVER(&tp->t_out, tp->t_out.rb_hd+cc);
382 		}
383 #endif
384 		if (cc <= 0)
385 			break;
386 		error = uiomove(buf, cc, uio);
387 	}
388 	if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
389 		if (tp->t_state&TS_ASLEEP) {
390 			tp->t_state &= ~TS_ASLEEP;
391 			wakeup((caddr_t)&tp->t_out);
392 		}
393 		selwakeup(&tp->t_wsel);
394 	}
395 	return (error);
396 }
397 
398 void
399 ptsstop(tp, flush)
400 	register struct tty *tp;
401 	int flush;
402 {
403 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
404 	int flag;
405 
406 	/* note: FLUSHREAD and FLUSHWRITE already ok */
407 	if (flush == 0) {
408 		flush = TIOCPKT_STOP;
409 		pti->pt_flags |= PF_STOPPED;
410 	} else
411 		pti->pt_flags &= ~PF_STOPPED;
412 	pti->pt_send |= flush;
413 	/* change of perspective */
414 	flag = 0;
415 	if (flush & FREAD)
416 		flag |= FWRITE;
417 	if (flush & FWRITE)
418 		flag |= FREAD;
419 	ptcwakeup(tp, flag);
420 }
421 
422 int
423 ptcselect(dev, rw, p)
424 	dev_t dev;
425 	int rw;
426 	struct proc *p;
427 {
428 	register struct tty *tp = pt_tty[minor(dev)];
429 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
430 	int s;
431 
432 	if ((tp->t_state&TS_CARR_ON) == 0)
433 		return (1);
434 	switch (rw) {
435 
436 	case FREAD:
437 		/*
438 		 * Need to block timeouts (ttrstart).
439 		 */
440 		s = spltty();
441 		if ((tp->t_state&TS_ISOPEN) &&
442 		     RB_LEN(&tp->t_out) && (tp->t_state&TS_TTSTOP) == 0) {
443 			splx(s);
444 			return (1);
445 		}
446 		splx(s);
447 		/* FALLTHROUGH */
448 
449 	case 0:					/* exceptional */
450 		if ((tp->t_state&TS_ISOPEN) &&
451 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
452 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
453 			return (1);
454 		selrecord(p, &pti->pt_selr);
455 		break;
456 
457 
458 	case FWRITE:
459 		if (tp->t_state&TS_ISOPEN) {
460 			if (pti->pt_flags & PF_REMOTE) {
461 			    if (RB_LEN(&tp->t_can) == 0)
462 				return (1);
463 			} else {
464 			    if (RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can) < TTYHOG-2)
465 				    return (1);
466 			    if (RB_LEN(&tp->t_can) == 0 && (tp->t_iflag&ICANON))
467 				    return (1);
468 			}
469 		}
470 		selrecord(p, &pti->pt_selw);
471 		break;
472 
473 	}
474 	return (0);
475 }
476 
477 int
478 ptcwrite(dev, uio, flag)
479 	dev_t dev;
480 	register struct uio *uio;
481 	int flag;
482 {
483 	register struct tty *tp = pt_tty[minor(dev)];
484 	register u_char *cp;
485 	register int cc = 0;
486 	u_char locbuf[BUFSIZ];
487 	int cnt = 0;
488 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
489 	int error = 0;
490 
491 again:
492 	if ((tp->t_state&TS_ISOPEN) == 0)
493 		goto block;
494 	if (pti->pt_flags & PF_REMOTE) {
495 		if (RB_LEN(&tp->t_can))
496 			goto block;
497 		while (uio->uio_resid > 0 && RB_LEN(&tp->t_can) < TTYHOG - 1) {
498 			if (cc == 0) {
499 				cc = min(uio->uio_resid, BUFSIZ);
500 				cc = min(cc, TTYHOG - 1 - RB_CONTIGPUT(&tp->t_can));
501 				cp = locbuf;
502 				error = uiomove((caddr_t)cp, cc, uio);
503 				if (error)
504 					return (error);
505 				/* check again for safety */
506 				if ((tp->t_state&TS_ISOPEN) == 0)
507 					return (EIO);
508 			}
509 #ifdef was
510 			if (cc)
511 				(void) b_to_q((char *)cp, cc, &tp->t_canq);
512 #else
513 			if (cc) {
514 				rbpack(cp, tp->t_can.rb_tl, cc);
515 				tp->t_can.rb_tl =
516 				  RB_ROLLOVER(&tp->t_can, tp->t_can.rb_tl+cc);
517 			}
518 #endif
519 			cc = 0;
520 		}
521 		(void) putc(0, &tp->t_can);
522 		ttwakeup(tp);
523 		wakeup((caddr_t)&tp->t_can);
524 		return (0);
525 	}
526 	while (uio->uio_resid > 0) {
527 		if (cc == 0) {
528 			cc = min(uio->uio_resid, BUFSIZ);
529 			cp = locbuf;
530 			error = uiomove((caddr_t)cp, cc, uio);
531 			if (error)
532 				return (error);
533 			/* check again for safety */
534 			if ((tp->t_state&TS_ISOPEN) == 0)
535 				return (EIO);
536 		}
537 		while (cc > 0) {
538 			if ((RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can)) >= TTYHOG - 2 &&
539 			   (RB_LEN(&tp->t_can) > 0 || !(tp->t_iflag&ICANON))) {
540 				wakeup((caddr_t)&tp->t_raw);
541 				goto block;
542 			}
543 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
544 			cnt++;
545 			cc--;
546 		}
547 		cc = 0;
548 	}
549 	return (0);
550 block:
551 	/*
552 	 * Come here to wait for slave to open, for space
553 	 * in outq, or space in rawq.
554 	 */
555 	if ((tp->t_state&TS_CARR_ON) == 0)
556 		return (EIO);
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 	if (error = tsleep((caddr_t)&tp->t_raw.rb_hd, TTOPRI | PCATCH,
565 	    ttyout, 0)) {
566 		/* adjust for data copied in but not written */
567 		uio->uio_resid += cc;
568 		return (error);
569 	}
570 	goto again;
571 }
572 
573 /*ARGSUSED*/
574 int
575 ptyioctl(dev, cmd, data, flag)
576 	caddr_t data;
577 	int cmd, flag;
578 	dev_t dev;
579 {
580 	register struct tty *tp = pt_tty[minor(dev)];
581 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
582 	register u_char *cc = tp->t_cc;
583 	int stop, error;
584 
585 	/*
586 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
587 	 * ttywflush(tp) will hang if there are characters in the outq.
588 	 */
589 	if (cmd == TIOCEXT) {
590 		/*
591 		 * When the EXTPROC bit is being toggled, we need
592 		 * to send an TIOCPKT_IOCTL if the packet driver
593 		 * is turned on.
594 		 */
595 		if (*(int *)data) {
596 			if (pti->pt_flags & PF_PKT) {
597 				pti->pt_send |= TIOCPKT_IOCTL;
598 				ptcwakeup(tp, FREAD);
599 			}
600 			tp->t_lflag |= EXTPROC;
601 		} else {
602 			if ((tp->t_state & EXTPROC) &&
603 			    (pti->pt_flags & PF_PKT)) {
604 				pti->pt_send |= TIOCPKT_IOCTL;
605 				ptcwakeup(tp, FREAD);
606 			}
607 			tp->t_lflag &= ~EXTPROC;
608 		}
609 		return(0);
610 	} else
611 	if (cdevsw[major(dev)].d_open == ptcopen)
612 		switch (cmd) {
613 
614 		case TIOCGPGRP:
615 			/*
616 			 * We aviod calling ttioctl on the controller since,
617 			 * in that case, tp must be the controlling terminal.
618 			 */
619 			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
620 			return (0);
621 
622 		case TIOCPKT:
623 			if (*(int *)data) {
624 				if (pti->pt_flags & PF_UCNTL)
625 					return (EINVAL);
626 				pti->pt_flags |= PF_PKT;
627 			} else
628 				pti->pt_flags &= ~PF_PKT;
629 			return (0);
630 
631 		case TIOCUCNTL:
632 			if (*(int *)data) {
633 				if (pti->pt_flags & PF_PKT)
634 					return (EINVAL);
635 				pti->pt_flags |= PF_UCNTL;
636 			} else
637 				pti->pt_flags &= ~PF_UCNTL;
638 			return (0);
639 
640 		case TIOCREMOTE:
641 			if (*(int *)data)
642 				pti->pt_flags |= PF_REMOTE;
643 			else
644 				pti->pt_flags &= ~PF_REMOTE;
645 			ttyflush(tp, FREAD|FWRITE);
646 			return (0);
647 
648 #ifdef COMPAT_43
649 	/* wkt */
650 		case TIOCSETP:
651 		case TIOCSETN:
652 #endif
653 		case TIOCSETD:
654 		case TIOCSETA:
655 		case TIOCSETAW:
656 		case TIOCSETAF:
657 			while (rbgetc(&tp->t_out) >= 0)
658 				;
659 			break;
660 
661 		case TIOCSIG:
662 			if (*(unsigned int *)data >= NSIG)
663 				return(EINVAL);
664 			if ((tp->t_lflag&NOFLSH) == 0)
665 				ttyflush(tp, FREAD|FWRITE);
666 			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
667 			if ((*(unsigned int *)data == SIGINFO) &&
668 			    ((tp->t_lflag&NOKERNINFO) == 0))
669 				ttyinfo(tp);
670 			return(0);
671 		}
672 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
673 	if (error < 0)
674 		 error = ttioctl(tp, cmd, data, flag);
675 	/*
676 	 * Since we use the tty queues internally,
677 	 * pty's can't be switched to disciplines which overwrite
678 	 * the queues.  We can't tell anything about the discipline
679 	 * from here...
680 	 */
681 	if (linesw[tp->t_line].l_rint != ttyinput) {
682 		(*linesw[tp->t_line].l_close)(tp, flag);
683 		tp->t_line = TTYDISC;
684 		(void)(*linesw[tp->t_line].l_open)(dev, tp);
685 		error = ENOTTY;
686 	}
687 	if (error < 0) {
688 		if (pti->pt_flags & PF_UCNTL &&
689 		    (cmd & ~0xff) == UIOCCMD(0)) {
690 			if (cmd & 0xff) {
691 				pti->pt_ucntl = (u_char)cmd;
692 				ptcwakeup(tp, FREAD);
693 			}
694 			return (0);
695 		}
696 		error = ENOTTY;
697 	}
698 	/*
699 	 * If external processing and packet mode send ioctl packet.
700 	 */
701 	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
702 		switch(cmd) {
703 		case TIOCSETA:
704 		case TIOCSETAW:
705 		case TIOCSETAF:
706 #ifdef	COMPAT_43
707 	/* wkt */
708 		case TIOCSETP:
709 		case TIOCSETN:
710 		case TIOCSETC:
711 		case TIOCSLTC:
712 		case TIOCLBIS:
713 		case TIOCLBIC:
714 		case TIOCLSET:
715 #endif
716 			pti->pt_send |= TIOCPKT_IOCTL;
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 #endif
741