xref: /original-bsd/sys/kern/tty_pty.c (revision 241757c4)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)tty_pty.c	7.3.1.1 (Berkeley) 01/13/88
7  */
8 
9 /*
10  * Pseudo-teletype Driver
11  * (Actually two drivers, requiring two entries in 'cdevsw')
12  */
13 #include "pty.h"
14 
15 #if NPTY > 0
16 #include "param.h"
17 #include "systm.h"
18 #include "ioctl.h"
19 #include "tty.h"
20 #include "dir.h"
21 #include "user.h"
22 #include "conf.h"
23 #include "file.h"
24 #include "proc.h"
25 #include "uio.h"
26 #include "kernel.h"
27 #include "tsleep.h"
28 
29 #if NPTY == 1
30 #undef NPTY
31 #define	NPTY	32		/* crude XXX */
32 #endif
33 
34 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
35 
36 /*
37  * pts == /dev/tty[pqrs]?
38  * ptc == /dev/pty[pqrs]?
39  */
40 struct	tty pt_tty[NPTY];
41 struct	pt_ioctl {
42 	int	pt_flags;
43 	struct	proc *pt_selr, *pt_selw;
44 	u_char	pt_send;
45 	u_char	pt_ucntl;
46 	struct	clist pt_ioc;
47 } pt_ioctl[NPTY];
48 int	npty = NPTY;		/* for pstat -t */
49 
50 #define	PF_RCOLL	0x0001
51 #define	PF_WCOLL	0x0002
52 #define	PF_NBIO		0x0004
53 #define	PF_PKT		0x0008		/* packet mode */
54 #define	PF_STOPPED	0x0010		/* user told stopped */
55 #define	PF_REMOTE	0x0020		/* remote and flow controlled input */
56 #define	PF_NOSTOP	0x0040
57 #define	PF_UCNTL	0x0080		/* user control mode */
58 #define	PF_TIOC		0x0100		/* transparent control mode */
59 #define	PF_LIOC		0x0200		/* transparent control locked */
60 #define	PF_WIOC		0x0400		/* waiting for PF_LIOC to clear */
61 #define	PF_BLOCK	0x0800		/* block writes to slave */
62 #define	PF_OWAIT	0x1000		/* waiting for PF_BLOCK to clear */
63 
64 /*ARGSUSED*/
65 ptsopen(dev, flag)
66 	dev_t dev;
67 {
68 	register struct tty *tp;
69 	int error;
70 
71 #ifdef lint
72 	npty = npty;
73 #endif
74 	if (minor(dev) >= NPTY)
75 		return (ENXIO);
76 	tp = &pt_tty[minor(dev)];
77 	if ((tp->t_state & TS_ISOPEN) == 0) {
78 		ttychars(tp);		/* Set up default chars */
79 		tp->t_ispeed = tp->t_ospeed = EXTB;
80 		tp->t_flags = 0;	/* No features (nor raw mode) */
81 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
82 		return (EBUSY);
83 	if (tp->t_oproc)			/* Ctrlr still around. */
84 		tp->t_state |= TS_CARR_ON;
85 	while ((tp->t_state & TS_CARR_ON) == 0) {
86 		tp->t_state |= TS_WOPEN;
87 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
88 	}
89 	error = (*linesw[tp->t_line].l_open)(dev, tp);
90 	ptcwakeup(tp, FREAD|FWRITE);
91 	return (error);
92 }
93 
94 ptsclose(dev)
95 	dev_t dev;
96 {
97 	register struct tty *tp;
98 
99 	tp = &pt_tty[minor(dev)];
100 	(*linesw[tp->t_line].l_close)(tp);
101 	ttyclose(tp);
102 	ptcwakeup(tp, FREAD|FWRITE);
103 	return (0);
104 }
105 
106 ptsread(dev, uio)
107 	dev_t dev;
108 	struct uio *uio;
109 {
110 	register struct tty *tp = &pt_tty[minor(dev)];
111 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
112 	int error = 0;
113 
114 again:
115 	if (pti->pt_flags & PF_REMOTE) {
116 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
117 			if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
118 			    (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
119 			    u.u_procp->p_flag&SVFORK)
120 				return (EIO);
121 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
122 			sleep((caddr_t)&lbolt, TTIPRI);
123 		}
124 		if (tp->t_canq.c_cc == 0) {
125 			if (tp->t_state & TS_NBIO)
126 				return (EWOULDBLOCK);
127 			sleep((caddr_t)&tp->t_canq, TTIPRI);
128 			goto again;
129 		}
130 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
131 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
132 				error = EFAULT;
133 				break;
134 			}
135 		if (tp->t_canq.c_cc == 1)
136 			(void) getc(&tp->t_canq);
137 		if (tp->t_canq.c_cc)
138 			return (error);
139 	} else
140 		if (tp->t_oproc)
141 			error = (*linesw[tp->t_line].l_read)(tp, uio);
142 	ptcwakeup(tp, FWRITE);
143 	return (error);
144 }
145 
146 /*
147  * Write to pseudo-tty.
148  * Wakeups of controlling tty will happen
149  * indirectly, when tty driver calls ptsstart.
150  */
151 ptswrite(dev, uio)
152 	dev_t dev;
153 	struct uio *uio;
154 {
155 	register struct tty *tp = &pt_tty[minor(dev)];
156 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
157 
158 	if (tp->t_oproc == 0)
159 		return (EIO);
160 
161 	while (pti->pt_flags & PF_BLOCK) {
162 		pti->pt_flags |= PF_OWAIT;
163 		sleep((caddr_t)pti + 1, TTOPRI);
164 	}
165 
166 	return ((*linesw[tp->t_line].l_write)(tp, uio));
167 }
168 
169 /*
170  * Start output on pseudo-tty.
171  * Wake up process selecting or sleeping for input from controlling tty.
172  */
173 ptsstart(tp)
174 	struct tty *tp;
175 {
176 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
177 
178 	if (tp->t_state & TS_TTSTOP)
179 		return;
180 	if (pti->pt_flags & PF_STOPPED) {
181 		pti->pt_flags &= ~PF_STOPPED;
182 		pti->pt_send = TIOCPKT_START;
183 	}
184 	ptcwakeup(tp, FREAD);
185 }
186 
187 ptcwakeup(tp, flag)
188 	struct tty *tp;
189 {
190 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
191 
192 	if (flag & FREAD) {
193 		if (pti->pt_selr) {
194 			selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
195 			pti->pt_selr = 0;
196 			pti->pt_flags &= ~PF_RCOLL;
197 		}
198 		wakeup((caddr_t)&tp->t_outq.c_cf);
199 	}
200 	if (flag & FWRITE) {
201 		if (pti->pt_selw) {
202 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
203 			pti->pt_selw = 0;
204 			pti->pt_flags &= ~PF_WCOLL;
205 		}
206 		wakeup((caddr_t)&tp->t_rawq.c_cf);
207 	}
208 }
209 
210 /*ARGSUSED*/
211 ptcopen(dev, flag)
212 	dev_t dev;
213 	int flag;
214 {
215 	register struct tty *tp;
216 	struct pt_ioctl *pti;
217 
218 	if (minor(dev) >= NPTY)
219 		return (ENXIO);
220 	tp = &pt_tty[minor(dev)];
221 	if (tp->t_oproc)
222 		return (EIO);
223 	tp->t_oproc = ptsstart;
224 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
225 	pti = &pt_ioctl[minor(dev)];
226 	pti->pt_flags = 0;
227 	pti->pt_send = 0;
228 	pti->pt_ucntl = 0;
229 	return (0);
230 }
231 
232 ptcclose(dev)
233 	dev_t dev;
234 {
235 	register struct tty *tp;
236 
237 	tp = &pt_tty[minor(dev)];
238 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
239 	tp->t_state &= ~TS_CARR_ON;
240 	tp->t_oproc = 0;		/* mark closed */
241 	return (0);
242 }
243 
244 ptcread(dev, uio)
245 	dev_t dev;
246 	struct uio *uio;
247 {
248 	register struct tty *tp = &pt_tty[minor(dev)];
249 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
250 	char buf[BUFSIZ];
251 	int error = 0, cc;
252 
253 	/*
254 	 * We want to block until the slave
255 	 * is open, and there's something to read;
256 	 * but if we lost the slave or we're NBIO,
257 	 * then return the appropriate error instead.
258 	 */
259 	for (;;) {
260 		if (tp->t_state&TS_ISOPEN) {
261 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
262 				error = ureadc((int)pti->pt_send, uio);
263 				if (error)
264 					return (error);
265 				pti->pt_send = 0;
266 				return (0);
267 			}
268 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
269 				error = ureadc((int)pti->pt_ucntl, uio);
270 				if (error)
271 					return (error);
272 				pti->pt_ucntl = 0;
273 				return (0);
274 			}
275 			if (pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc) {
276 				if (uio->uio_resid < pti->pt_ioc.c_cc + 1)
277 					return (E2BIG);
278 				error = ureadc(TIOCPKT_TIOC, uio);
279 				while (error == 0 && pti->pt_ioc.c_cc > 0) {
280 					cc = q_to_b(&pti->pt_ioc, buf,
281 					    MIN(pti->pt_ioc.c_cc, BUFSIZ));
282 					if (cc <= 0)	/* impossible? */
283 						break;
284 					error = uiomove(buf, cc, UIO_READ, uio);
285 				}
286 				return (error);
287 			}
288 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
289 				break;
290 		}
291 		if ((tp->t_state&TS_CARR_ON) == 0)
292 			return (EIO);
293 		if (pti->pt_flags&PF_NBIO)
294 			return (EWOULDBLOCK);
295 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
296 	}
297 	if (pti->pt_flags & (PF_PKT|PF_UCNTL|PF_TIOC))
298 		error = ureadc(0, uio);
299 	while (uio->uio_resid > 0 && error == 0) {
300 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
301 		if (cc <= 0)
302 			break;
303 		error = uiomove(buf, cc, UIO_READ, uio);
304 	}
305 	if (tp->t_outq.c_cc <= TTLOWAT(tp) && !(pti->pt_flags & PF_BLOCK))
306 		ptswake(tp);
307 	return (error);
308 }
309 
310 ptswake(tp)
311 	register struct tty *tp;
312 {
313 	if (tp->t_state&TS_ASLEEP) {
314 		tp->t_state &= ~TS_ASLEEP;
315 		wakeup((caddr_t)&tp->t_outq);
316 	}
317 	if (tp->t_wsel) {
318 		selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
319 		tp->t_wsel = 0;
320 		tp->t_state &= ~TS_WCOLL;
321 	}
322 }
323 
324 ptsstop(tp, flush)
325 	register struct tty *tp;
326 	int flush;
327 {
328 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
329 	int flag;
330 
331 	/* note: FLUSHREAD and FLUSHWRITE already ok */
332 	if (flush == 0) {
333 		flush = TIOCPKT_STOP;
334 		pti->pt_flags |= PF_STOPPED;
335 	} else
336 		pti->pt_flags &= ~PF_STOPPED;
337 	pti->pt_send |= flush;
338 	/* change of perspective */
339 	flag = 0;
340 	if (flush & FREAD)
341 		flag |= FWRITE;
342 	if (flush & FWRITE)
343 		flag |= FREAD;
344 	ptcwakeup(tp, flag);
345 }
346 
347 ptcselect(dev, rw)
348 	dev_t dev;
349 	int rw;
350 {
351 	register struct tty *tp = &pt_tty[minor(dev)];
352 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
353 	struct proc *p;
354 	int s;
355 
356 	if ((tp->t_state&TS_CARR_ON) == 0)
357 		return (1);
358 	switch (rw) {
359 
360 	case FREAD:
361 		/*
362 		 * Need to block timeouts (ttrstart).
363 		 */
364 		s = spltty();
365 		if ((tp->t_state&TS_ISOPEN) &&
366 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
367 			splx(s);
368 			return (1);
369 		}
370 		splx(s);
371 		/* FALLTHROUGH */
372 
373 	case 0:					/* exceptional */
374 		if ((tp->t_state&TS_ISOPEN) &&
375 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
376 		     pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc ||
377 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
378 			return (1);
379 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
380 			pti->pt_flags |= PF_RCOLL;
381 		else
382 			pti->pt_selr = u.u_procp;
383 		break;
384 
385 
386 	case FWRITE:
387 		if (tp->t_state&TS_ISOPEN) {
388 			if (pti->pt_flags & PF_REMOTE) {
389 			    if (tp->t_canq.c_cc == 0)
390 				return (1);
391 			} else {
392 			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
393 				    return (1);
394 			    if (tp->t_canq.c_cc == 0 &&
395 			        (tp->t_flags & (RAW|CBREAK)) == 0)
396 				    return (1);
397 			}
398 		}
399 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
400 			pti->pt_flags |= PF_WCOLL;
401 		else
402 			pti->pt_selw = u.u_procp;
403 		break;
404 
405 	}
406 	return (0);
407 }
408 
409 ptcwrite(dev, uio)
410 	dev_t dev;
411 	register struct uio *uio;
412 {
413 	register struct tty *tp = &pt_tty[minor(dev)];
414 	register struct iovec *iov;
415 	register char *cp;
416 	register int cc = 0;
417 	char locbuf[BUFSIZ];
418 	int cnt = 0;
419 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
420 	int error = 0;
421 
422 again:
423 	if ((tp->t_state&TS_ISOPEN) == 0)
424 		goto block;
425 	if (pti->pt_flags & PF_REMOTE) {
426 		if (tp->t_canq.c_cc)
427 			goto block;
428 		while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
429 			iov = uio->uio_iov;
430 			if (iov->iov_len == 0) {
431 				uio->uio_iovcnt--;
432 				uio->uio_iov++;
433 				continue;
434 			}
435 			if (cc == 0) {
436 				cc = MIN(iov->iov_len, BUFSIZ);
437 				cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
438 				cp = locbuf;
439 				error = uiomove(cp, cc, UIO_WRITE, uio);
440 				if (error)
441 					return (error);
442 				/* check again for safety */
443 				if ((tp->t_state&TS_ISOPEN) == 0)
444 					return (EIO);
445 			}
446 			if (cc)
447 				(void) b_to_q(cp, cc, &tp->t_canq);
448 			cc = 0;
449 		}
450 		(void) putc(0, &tp->t_canq);
451 		ttwakeup(tp);
452 		wakeup((caddr_t)&tp->t_canq);
453 		return (0);
454 	}
455 	while (uio->uio_iovcnt > 0) {
456 		iov = uio->uio_iov;
457 		if (cc == 0) {
458 			if (iov->iov_len == 0) {
459 				uio->uio_iovcnt--;
460 				uio->uio_iov++;
461 				continue;
462 			}
463 			cc = MIN(iov->iov_len, BUFSIZ);
464 			cp = locbuf;
465 			error = uiomove(cp, cc, UIO_WRITE, uio);
466 			if (error)
467 				return (error);
468 			/* check again for safety */
469 			if ((tp->t_state&TS_ISOPEN) == 0)
470 				return (EIO);
471 		}
472 		while (cc > 0) {
473 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
474 			   (tp->t_canq.c_cc > 0 ||
475 			      tp->t_flags & (RAW|CBREAK))) {
476 				wakeup((caddr_t)&tp->t_rawq);
477 				goto block;
478 			}
479 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
480 			cnt++;
481 			cc--;
482 		}
483 		cc = 0;
484 	}
485 	return (0);
486 block:
487 	/*
488 	 * Come here to wait for slave to open, for space
489 	 * in outq, or space in rawq.
490 	 */
491 	if ((tp->t_state&TS_CARR_ON) == 0)
492 		return (EIO);
493 	if (pti->pt_flags & PF_NBIO) {
494 		iov->iov_base -= cc;
495 		iov->iov_len += cc;
496 		uio->uio_resid += cc;
497 		uio->uio_offset -= cc;
498 		if (cnt == 0)
499 			return (EWOULDBLOCK);
500 		return (0);
501 	}
502 	sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
503 	goto again;
504 }
505 
506 /*ARGSUSED*/
507 ptyioctl(dev, cmd, data, flag)
508 	caddr_t data;
509 	dev_t dev;
510 {
511 	register struct tty *tp = &pt_tty[minor(dev)];
512 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
513 	int stop, error;
514 	extern ttyinput();
515 
516 	/*
517 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
518 	 * ttywflush(tp) will hang if there are characters in the outq.
519 	 */
520 	if (cdevsw[major(dev)].d_open == ptcopen) {
521 		if ((cmd & 0xffff) == (TIOCIOANS(0) & 0xffff)) {
522 			if (!(pti->pt_flags & PF_LIOC) || pti->pt_ioc.c_cc)
523 				return (EINVAL);
524 			(void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
525 			wakeup((caddr_t)&pti->pt_ioc);
526 			return (0);
527 		}
528 		switch (cmd) {
529 
530 		case TIOCPKT:
531 			if (*(int *)data) {
532 				if (pti->pt_flags & PF_UCNTL)
533 					return (EINVAL);
534 				pti->pt_flags |= PF_PKT;
535 			} else
536 				pti->pt_flags &= ~PF_PKT;
537 			return (0);
538 
539 		case TIOCUCNTL:
540 			if (*(int *)data) {
541 				if (pti->pt_flags & PF_PKT)
542 					return (EINVAL);
543 				pti->pt_flags |= PF_UCNTL;
544 			} else
545 				pti->pt_flags &= ~PF_UCNTL;
546 			return (0);
547 
548 		case TIOCTIOC:
549 			if (*(int *)data) {
550 				if (pti->pt_flags & PF_UCNTL)
551 					return (EINVAL);
552 				pti->pt_flags |= PF_TIOC;
553 			} else {
554 				pti->pt_flags &= ~(PF_TIOC|PF_LIOC|PF_WIOC);
555 				while (pti->pt_ioc.c_cc)
556 					(void) getc(&pti->pt_ioc);
557 				wakeup((caddr_t)&pti->pt_ioc);
558 			}
559 			return (0);
560 
561 		case TIOCBLK:
562 			if (*(int *)data)
563 				pti->pt_flags |= PF_BLOCK;
564 			else {
565 				if (pti->pt_flags & PF_OWAIT)
566 					wakeup((caddr_t)pti + 1);
567 				pti->pt_flags &= ~(PF_BLOCK|PF_OWAIT);
568 				ptswake(tp);
569 			}
570 			return (0);
571 
572 		case TIOCREMOTE:
573 			if (*(int *)data)
574 				pti->pt_flags |= PF_REMOTE;
575 			else
576 				pti->pt_flags &= ~PF_REMOTE;
577 			ttyflush(tp, FREAD|FWRITE);
578 			return (0);
579 
580 		case FIONBIO:
581 			if (*(int *)data)
582 				pti->pt_flags |= PF_NBIO;
583 			else
584 				pti->pt_flags &= ~PF_NBIO;
585 			return (0);
586 
587 		case FIONREAD:
588 			*(int *)data = tp->t_outq.c_cc;
589 			return (0);
590 
591 		case TIOCSETP:
592 		case TIOCSETN:
593 		case TIOCSETD:
594 			while (getc(&tp->t_outq) >= 0)
595 				;
596 			break;
597 		}
598 	} else if (pti->pt_flags & PF_TIOC) {
599 		while (pti->pt_flags & PF_LIOC) {
600 			pti->pt_flags |= PF_WIOC;
601 			switch (tsleep((caddr_t)&pti->pt_flags,TTIPRI-1,5*hz)) {
602 			case TS_OK:
603 				continue;
604 			case TS_SIG:
605 			case TS_TIME:
606 				return (EBUSY);
607 			}
608 		}
609 		pti->pt_flags |= PF_LIOC | PF_BLOCK;
610 		while (pti->pt_ioc.c_cc)
611 			(void) getc(&pti->pt_ioc);
612 		(void) b_to_q(&cmd, sizeof cmd, &pti->pt_ioc);
613 		if (cmd & IOC_IN)
614 			(void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
615 		ptcwakeup(tp, FREAD);
616 		switch (tsleep((caddr_t)&pti->pt_ioc, TTIPRI-1, 5*hz)) {
617 		case TS_SIG:
618 		case TS_TIME:
619 			while (pti->pt_ioc.c_cc)
620 				(void) getc(&pti->pt_ioc);
621 			if (pti->pt_flags & PF_WIOC)
622 				wakeup((caddr_t)&pti->pt_flags);
623 			if (pti->pt_flags & PF_OWAIT)
624 				wakeup((caddr_t)pti + 1);
625 			pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
626 			ptswake(tp);
627 			return (EBUSY);
628 		case TS_OK:
629 			break;
630 		}
631 		if (pti->pt_ioc.c_cc == 0) {
632 			if (pti->pt_flags & PF_WIOC)
633 				wakeup((caddr_t)&pti->pt_flags);
634 			if (pti->pt_flags & PF_OWAIT)
635 				wakeup((caddr_t)pti + 1);
636 			pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
637 			ptswake(tp);
638 			goto doioctl;
639 		}
640 		if (q_to_b(&pti->pt_ioc, &error, sizeof error) != sizeof error)
641 			error = EINVAL;
642 		if (error == 0 && cmd & IOC_OUT) {
643 			if (IOCPARM_LEN(cmd) != pti->pt_ioc.c_cc)
644 				error = EINVAL;
645 			else
646 				(void) q_to_b(&pti->pt_ioc, data,
647 				    pti->pt_ioc.c_cc);
648 		}
649 		while (pti->pt_ioc.c_cc)
650 			(void) getc(&pti->pt_ioc);
651 		if (pti->pt_flags & PF_WIOC)
652 			wakeup((caddr_t)&pti->pt_flags);
653 		if (pti->pt_flags & PF_OWAIT)
654 			wakeup((caddr_t)pti + 1);
655 		pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
656 		ptswake(tp);
657 		return (error);
658 	}
659 
660  doioctl:
661 	error = ttioctl(tp, cmd, data, flag);
662 	/*
663 	 * Since we use the tty queues internally,
664 	 * pty's can't be switched to disciplines which overwrite
665 	 * the queues.  We can't tell anything about the discipline
666 	 * from here...
667 	 *
668 	 * Nb: this is not really good enough, the line disc open routine
669 	 * may have done anything at all, no guarantees that close
670 	 * will fix it.  This also has the effect of losing the
671 	 * previous discipline, which an error on a TIOCSETD shouldn't
672 	 * do...  Sometime it should be done via an explicit check
673 	 * for TIOCSETD, then check to see what linesw[new_number].l_rint
674 	 * really is.
675 	 */
676 	if (linesw[tp->t_line].l_rint != ttyinput) {
677 		(*linesw[tp->t_line].l_close)(tp);
678 		tp->t_line = 0;
679 		(void)(*linesw[tp->t_line].l_open)(dev, tp);
680 		error = ENOTTY;
681 	}
682 
683 	if (error < 0) {
684 		if (pti->pt_flags & PF_UCNTL &&
685 		    (cmd & ~0xff) == UIOCCMD(0)) {
686 			if (cmd & 0xff) {
687 				pti->pt_ucntl = (u_char)cmd;
688 				ptcwakeup(tp, FREAD);
689 			}
690 			return (0);
691 		}
692 		error = ENOTTY;
693 	}
694 	stop = (tp->t_flags & RAW) == 0 &&
695 	    tp->t_stopc == CTRL('s') && tp->t_startc == CTRL('q');
696 	if (pti->pt_flags & PF_NOSTOP) {
697 		if (stop) {
698 			pti->pt_send &= ~TIOCPKT_NOSTOP;
699 			pti->pt_send |= TIOCPKT_DOSTOP;
700 			pti->pt_flags &= ~PF_NOSTOP;
701 			ptcwakeup(tp, FREAD);
702 		}
703 	} else {
704 		if (!stop) {
705 			pti->pt_send &= ~TIOCPKT_DOSTOP;
706 			pti->pt_send |= TIOCPKT_NOSTOP;
707 			pti->pt_flags |= PF_NOSTOP;
708 			ptcwakeup(tp, FREAD);
709 		}
710 	}
711 	return (error);
712 }
713 #endif
714