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