xref: /original-bsd/sys/kern/tty_pty.c (revision 9fa17c5f)
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 are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)tty_pty.c	7.12 (Berkeley) 06/05/90
18  */
19 
20 /*
21  * Pseudo-teletype Driver
22  * (Actually two drivers, requiring two entries in 'cdevsw')
23  */
24 #include "pty.h"
25 
26 #if NPTY > 0
27 #include "param.h"
28 #include "systm.h"
29 #include "ioctl.h"
30 #include "tty.h"
31 #include "user.h"
32 #include "conf.h"
33 #include "file.h"
34 #include "proc.h"
35 #include "uio.h"
36 #include "kernel.h"
37 #include "vnode.h"
38 
39 #if NPTY == 1
40 #undef NPTY
41 #define	NPTY	32		/* crude XXX */
42 #endif
43 
44 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
45 
46 /*
47  * pts == /dev/tty[pqrs]?
48  * ptc == /dev/pty[pqrs]?
49  */
50 struct	tty pt_tty[NPTY];
51 struct	pt_ioctl {
52 	int	pt_flags;
53 	struct	proc *pt_selr, *pt_selw;
54 	u_char	pt_send;
55 	u_char	pt_ucntl;
56 } pt_ioctl[NPTY];
57 int	npty = NPTY;		/* for pstat -t */
58 
59 int ptydebug = 0;
60 
61 #define	PF_RCOLL	0x01
62 #define	PF_WCOLL	0x02
63 #define	PF_NBIO		0x04
64 #define	PF_PKT		0x08		/* packet mode */
65 #define	PF_STOPPED	0x10		/* user told stopped */
66 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
67 #define	PF_NOSTOP	0x40
68 #define PF_UCNTL	0x80		/* user control mode */
69 
70 /*ARGSUSED*/
71 ptsopen(dev, flag)
72 	dev_t dev;
73 {
74 	register struct tty *tp;
75 	int error;
76 
77 #ifdef lint
78 	npty = npty;
79 #endif
80 	if (minor(dev) >= NPTY)
81 		return (ENXIO);
82 	tp = &pt_tty[minor(dev)];
83 	if ((tp->t_state & TS_ISOPEN) == 0) {
84 		ttychars(tp);		/* Set up default chars */
85 		tp->t_iflag = TTYDEF_IFLAG;
86 		tp->t_oflag = TTYDEF_OFLAG;
87 		tp->t_lflag = TTYDEF_LFLAG;
88 		tp->t_cflag = TTYDEF_CFLAG;
89 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
90 		ttsetwater(tp);		/* would be done in xxparam() */
91 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
92 		return (EBUSY);
93 	if (tp->t_oproc)			/* Ctrlr still around. */
94 		tp->t_state |= TS_CARR_ON;
95 	while ((tp->t_state & TS_CARR_ON) == 0) {
96 		tp->t_state |= TS_WOPEN;
97 		if (flag&FNDELAY)
98 			break;
99 		if (error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
100 		    ttopen, 0))
101 			return (error);
102 	}
103 	error = (*linesw[tp->t_line].l_open)(dev, tp, flag);
104 	ptcwakeup(tp, FREAD|FWRITE);
105 	return (error);
106 }
107 
108 ptsclose(dev)
109 	dev_t dev;
110 {
111 	register struct tty *tp;
112 
113 	tp = &pt_tty[minor(dev)];
114 	(*linesw[tp->t_line].l_close)(tp);
115 	ttyclose(tp);
116 	ptcwakeup(tp, FREAD|FWRITE);
117 }
118 
119 ptsread(dev, uio, flag)
120 	dev_t dev;
121 	struct uio *uio;
122 {
123 	register struct tty *tp = &pt_tty[minor(dev)];
124 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
125 	int error = 0;
126 
127 again:
128 	if (pti->pt_flags & PF_REMOTE) {
129 		while (isbackground(u.u_procp, tp)) {
130 			if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
131 			    (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
132 			    u.u_procp->p_pgrp->pg_jobc == 0 ||
133 			    u.u_procp->p_flag&SVFORK)
134 				return (EIO);
135 			pgsignal(u.u_procp->p_pgrp, SIGTTIN, 1);
136 			if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH,
137 			    ttybg, 0))
138 				return (error);
139 		}
140 		if (tp->t_canq.c_cc == 0) {
141 			if (flag & IO_NDELAY)
142 				return (EWOULDBLOCK);
143 			if (error = tsleep((caddr_t)&tp->t_canq,
144 			    TTIPRI | PCATCH, ttyin, 0))
145 				return (error);
146 			goto again;
147 		}
148 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
149 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
150 				error = EFAULT;
151 				break;
152 			}
153 		if (tp->t_canq.c_cc == 1)
154 			(void) getc(&tp->t_canq);
155 		if (tp->t_canq.c_cc)
156 			return (error);
157 	} else
158 		if (tp->t_oproc)
159 			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
160 	ptcwakeup(tp, FWRITE);
161 	return (error);
162 }
163 
164 /*
165  * Write to pseudo-tty.
166  * Wakeups of controlling tty will happen
167  * indirectly, when tty driver calls ptsstart.
168  */
169 ptswrite(dev, uio, flag)
170 	dev_t dev;
171 	struct uio *uio;
172 {
173 	register struct tty *tp;
174 
175 	tp = &pt_tty[minor(dev)];
176 	if (tp->t_oproc == 0)
177 		return (EIO);
178 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
179 }
180 
181 /*
182  * Start output on pseudo-tty.
183  * Wake up process selecting or sleeping for input from controlling tty.
184  */
185 ptsstart(tp)
186 	struct tty *tp;
187 {
188 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
189 
190 	if (tp->t_state & TS_TTSTOP)
191 		return;
192 	if (pti->pt_flags & PF_STOPPED) {
193 		pti->pt_flags &= ~PF_STOPPED;
194 		pti->pt_send = TIOCPKT_START;
195 	}
196 	ptcwakeup(tp, FREAD);
197 }
198 
199 ptcwakeup(tp, flag)
200 	struct tty *tp;
201 {
202 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
203 
204 	if (flag & FREAD) {
205 		if (pti->pt_selr) {
206 			selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
207 			pti->pt_selr = 0;
208 			pti->pt_flags &= ~PF_RCOLL;
209 		}
210 		wakeup((caddr_t)&tp->t_outq.c_cf);
211 	}
212 	if (flag & FWRITE) {
213 		if (pti->pt_selw) {
214 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
215 			pti->pt_selw = 0;
216 			pti->pt_flags &= ~PF_WCOLL;
217 		}
218 if (ptydebug) printf("WAKEUP c_cf %d\n", u.u_procp->p_pid);
219 		wakeup((caddr_t)&tp->t_rawq.c_cf);
220 	}
221 }
222 
223 /*ARGSUSED*/
224 ptcopen(dev, flag)
225 	dev_t dev;
226 	int flag;
227 {
228 	register struct tty *tp;
229 	struct pt_ioctl *pti;
230 
231 	if (minor(dev) >= NPTY)
232 		return (ENXIO);
233 	tp = &pt_tty[minor(dev)];
234 	if (tp->t_oproc)
235 		return (EIO);
236 	tp->t_oproc = ptsstart;
237 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
238 	tp->t_lflag &= ~EXTPROC;
239 	pti = &pt_ioctl[minor(dev)];
240 	pti->pt_flags = 0;
241 	pti->pt_send = 0;
242 	pti->pt_ucntl = 0;
243 	return (0);
244 }
245 
246 ptcclose(dev)
247 	dev_t dev;
248 {
249 	register struct tty *tp;
250 
251 	tp = &pt_tty[minor(dev)];
252 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
253 	tp->t_state &= ~TS_CARR_ON;
254 	tp->t_oproc = 0;		/* mark closed */
255 	tp->t_session = 0;
256 }
257 
258 ptcread(dev, uio, flag)
259 	dev_t dev;
260 	struct uio *uio;
261 {
262 	register struct tty *tp = &pt_tty[minor(dev)];
263 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
264 	char buf[BUFSIZ];
265 	int error = 0, cc;
266 
267 	/*
268 	 * We want to block until the slave
269 	 * is open, and there's something to read;
270 	 * but if we lost the slave or we're NBIO,
271 	 * then return the appropriate error instead.
272 	 */
273 	for (;;) {
274 		if (tp->t_state&TS_ISOPEN) {
275 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
276 				error = ureadc((int)pti->pt_send, uio);
277 				if (error)
278 					return (error);
279 				if (pti->pt_send & TIOCPKT_IOCTL) {
280 					cc = MIN(uio->uio_resid,
281 						sizeof(tp->t_termios));
282 					uiomove(&tp->t_termios, cc, uio);
283 				}
284 				pti->pt_send = 0;
285 				return (0);
286 			}
287 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
288 				error = ureadc((int)pti->pt_ucntl, uio);
289 				if (error)
290 					return (error);
291 				pti->pt_ucntl = 0;
292 				return (0);
293 			}
294 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
295 				break;
296 		}
297 		if ((tp->t_state&TS_CARR_ON) == 0)
298 			return (0);	/* EOF */
299 		if (flag & IO_NDELAY)
300 			return (EWOULDBLOCK);
301 if (ptydebug) printf("SLEEP(1) c_cf %d\n", u.u_procp->p_pid);	/* XXX */
302 		if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
303 		    ttyin, 0))
304 			return (error);
305 	}
306 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
307 		error = ureadc(0, uio);
308 	while (uio->uio_resid > 0 && error == 0) {
309 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
310 		if (cc <= 0)
311 			break;
312 		error = uiomove(buf, cc, uio);
313 	}
314 	if (tp->t_outq.c_cc <= tp->t_lowat) {
315 		if (tp->t_state&TS_ASLEEP) {
316 			tp->t_state &= ~TS_ASLEEP;
317 			wakeup((caddr_t)&tp->t_outq);
318 		}
319 		if (tp->t_wsel) {
320 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
321 			tp->t_wsel = 0;
322 			tp->t_state &= ~TS_WCOLL;
323 		}
324 	}
325 	return (error);
326 }
327 
328 ptsstop(tp, flush)
329 	register struct tty *tp;
330 	int flush;
331 {
332 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
333 	int flag;
334 
335 	/* note: FLUSHREAD and FLUSHWRITE already ok */
336 	if (flush == 0) {
337 		flush = TIOCPKT_STOP;
338 		pti->pt_flags |= PF_STOPPED;
339 	} else
340 		pti->pt_flags &= ~PF_STOPPED;
341 	pti->pt_send |= flush;
342 	/* change of perspective */
343 	flag = 0;
344 	if (flush & FREAD)
345 		flag |= FWRITE;
346 	if (flush & FWRITE)
347 		flag |= FREAD;
348 	ptcwakeup(tp, flag);
349 }
350 
351 ptcselect(dev, rw)
352 	dev_t dev;
353 	int rw;
354 {
355 	register struct tty *tp = &pt_tty[minor(dev)];
356 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
357 	struct proc *p;
358 	int s;
359 
360 	if ((tp->t_state&TS_CARR_ON) == 0)
361 		return (1);
362 	switch (rw) {
363 
364 	case FREAD:
365 		/*
366 		 * Need to block timeouts (ttrstart).
367 		 */
368 		s = spltty();
369 		if ((tp->t_state&TS_ISOPEN) &&
370 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
371 			splx(s);
372 			return (1);
373 		}
374 		splx(s);
375 		/* FALLTHROUGH */
376 
377 	case 0:					/* exceptional */
378 		if ((tp->t_state&TS_ISOPEN) &&
379 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
380 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
381 			return (1);
382 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
383 			pti->pt_flags |= PF_RCOLL;
384 		else
385 			pti->pt_selr = u.u_procp;
386 		break;
387 
388 
389 	case FWRITE:
390 		if (tp->t_state&TS_ISOPEN) {
391 			if (pti->pt_flags & PF_REMOTE) {
392 			    if (tp->t_canq.c_cc == 0)
393 				return (1);
394 			} else {
395 			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
396 				    return (1);
397 			    if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
398 				    return (1);
399 			}
400 		}
401 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
402 			pti->pt_flags |= PF_WCOLL;
403 		else
404 			pti->pt_selw = u.u_procp;
405 		break;
406 
407 	}
408 	return (0);
409 }
410 
411 ptcwrite(dev, uio, flag)
412 	dev_t dev;
413 	register struct uio *uio;
414 {
415 	register struct tty *tp = &pt_tty[minor(dev)];
416 	register struct iovec *iov;
417 	register char *cp;
418 	register int cc = 0;
419 	char locbuf[BUFSIZ];
420 	int cnt = 0;
421 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
422 	int error = 0;
423 
424 again:
425 	if ((tp->t_state&TS_ISOPEN) == 0)
426 		goto block;
427 	if (pti->pt_flags & PF_REMOTE) {
428 		if (tp->t_canq.c_cc)
429 			goto block;
430 		while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
431 			iov = uio->uio_iov;
432 			if (iov->iov_len == 0) {
433 				uio->uio_iovcnt--;
434 				uio->uio_iov++;
435 				continue;
436 			}
437 			if (cc == 0) {
438 				cc = MIN(iov->iov_len, BUFSIZ);
439 				cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
440 				cp = locbuf;
441 				error = uiomove(cp, cc, uio);
442 				if (error)
443 					return (error);
444 				/* check again for safety */
445 				if ((tp->t_state&TS_ISOPEN) == 0)
446 					return (EIO);
447 			}
448 			if (cc)
449 				(void) b_to_q(cp, cc, &tp->t_canq);
450 			cc = 0;
451 		}
452 		(void) putc(0, &tp->t_canq);
453 		ttwakeup(tp);
454 		wakeup((caddr_t)&tp->t_canq);
455 		return (0);
456 	}
457 	while (uio->uio_iovcnt > 0) {
458 		iov = uio->uio_iov;
459 		if (cc == 0) {
460 			if (iov->iov_len == 0) {
461 				uio->uio_iovcnt--;
462 				uio->uio_iov++;
463 				continue;
464 			}
465 			cc = MIN(iov->iov_len, BUFSIZ);
466 			cp = locbuf;
467 			error = uiomove(cp, cc, uio);
468 			if (error)
469 				return (error);
470 			/* check again for safety */
471 			if ((tp->t_state&TS_ISOPEN) == 0)
472 				return (EIO);
473 		}
474 		while (cc > 0) {
475 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
476 			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
477 				wakeup((caddr_t)&tp->t_rawq);
478 				goto block;
479 			}
480 			(*linesw[tp->t_line].l_rint)(*cp++&0377, tp);
481 			cnt++;
482 			cc--;
483 		}
484 		cc = 0;
485 	}
486 	return (0);
487 block:
488 	/*
489 	 * Come here to wait for slave to open, for space
490 	 * in outq, or space in rawq.
491 	 */
492 	if ((tp->t_state&TS_CARR_ON) == 0)
493 		return (EIO);
494 	if ((pti->pt_flags & PF_NBIO) || (flag & IO_NDELAY)) {
495 		iov->iov_base -= cc;
496 		iov->iov_len += cc;
497 		uio->uio_resid += cc;
498 		uio->uio_offset -= cc;
499 		if (cnt == 0)
500 			return (EWOULDBLOCK);
501 		return (0);
502 	}
503 if (ptydebug) printf("SLEEP(2) c_cf %d\n", u.u_procp->p_pid);
504 	if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
505 	    ttyout, 0))
506 		return (error);
507 	goto again;
508 }
509 
510 /*ARGSUSED*/
511 ptyioctl(dev, cmd, data, flag)
512 	caddr_t data;
513 	dev_t dev;
514 {
515 	register struct tty *tp = &pt_tty[minor(dev)];
516 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
517 	register u_char *cc = tp->t_cc;
518 	int stop, error;
519 	extern ttyinput();
520 
521 	/*
522 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
523 	 * ttywflush(tp) will hang if there are characters in the outq.
524 	 */
525 	if (cmd == TIOCEXT) {
526 		/*
527 		 * When the EXTPROC bit is being toggled, we need
528 		 * to send an TIOCPKT_IOCTL if the packet driver
529 		 * is turned on.
530 		 */
531 		if (*(int *)data) {
532 			if (pti->pt_flags & PF_PKT) {
533 				pti->pt_send |= TIOCPKT_IOCTL;
534 				ptcwakeup(tp);
535 			}
536 			tp->t_lflag |= EXTPROC;
537 		} else {
538 			if ((tp->t_state & EXTPROC) &&
539 			    (pti->pt_flags & PF_PKT)) {
540 				pti->pt_send |= TIOCPKT_IOCTL;
541 				ptcwakeup(tp);
542 			}
543 			tp->t_lflag &= ~EXTPROC;
544 		}
545 		return(0);
546 	} else
547 	if (cdevsw[major(dev)].d_open == ptcopen)
548 		switch (cmd) {
549 
550 		case TIOCPKT:
551 			if (*(int *)data) {
552 				if (pti->pt_flags & PF_UCNTL)
553 					return (EINVAL);
554 				pti->pt_flags |= PF_PKT;
555 			} else
556 				pti->pt_flags &= ~PF_PKT;
557 			return (0);
558 
559 		case TIOCUCNTL:
560 			if (*(int *)data) {
561 				if (pti->pt_flags & PF_PKT)
562 					return (EINVAL);
563 				pti->pt_flags |= PF_UCNTL;
564 			} else
565 				pti->pt_flags &= ~PF_UCNTL;
566 			return (0);
567 
568 		case TIOCREMOTE:
569 			if (*(int *)data)
570 				pti->pt_flags |= PF_REMOTE;
571 			else
572 				pti->pt_flags &= ~PF_REMOTE;
573 			ttyflush(tp, FREAD|FWRITE);
574 			return (0);
575 
576 		case FIONBIO:
577 			if (*(int *)data)
578 				pti->pt_flags |= PF_NBIO;
579 			else
580 				pti->pt_flags &= ~PF_NBIO;
581 			return (0);
582 
583 		case TIOCSETP:
584 		case TIOCSETN:
585 		case TIOCSETD:
586 		case TIOCSETA:
587 		case TIOCSETAW:
588 		case TIOCSETAF:
589 		case JUNK_TIOCSETAS:
590 		case JUNK_TIOCSETAWS:
591 		case JUNK_TIOCSETAFS:
592 			while (getc(&tp->t_outq) >= 0)
593 				;
594 			break;
595 
596 		case TIOCSIG:
597 			if (*(unsigned int *)data >= NSIG)
598 				return(EINVAL);
599 			if ((tp->t_lflag&NOFLSH) == 0)
600 				ttyflush(tp, FREAD|FWRITE);
601 			pgsignal(tp->t_pgrp, *(unsigned int *)data);
602 			return(0);
603 		}
604 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
605 	if (error < 0)
606 		 error = ttioctl(tp, cmd, data, flag);
607 	/*
608 	 * Since we use the tty queues internally,
609 	 * pty's can't be switched to disciplines which overwrite
610 	 * the queues.  We can't tell anything about the discipline
611 	 * from here...
612 	 */
613 	if (linesw[tp->t_line].l_rint != ttyinput) {
614 		(*linesw[tp->t_line].l_close)(tp);
615 		tp->t_line = 0;
616 		(void)(*linesw[tp->t_line].l_open)(dev, tp, flag);
617 		error = ENOTTY;
618 	}
619 	if (error < 0) {
620 		if (pti->pt_flags & PF_UCNTL &&
621 		    (cmd & ~0xff) == UIOCCMD(0)) {
622 			if (cmd & 0xff) {
623 				pti->pt_ucntl = (u_char)cmd;
624 				ptcwakeup(tp, FREAD);
625 			}
626 			return (0);
627 		}
628 		error = ENOTTY;
629 	}
630 	/*
631 	 * If external processing and packet mode send ioctl packet.
632 	 */
633 	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
634 		switch(cmd) {
635 		case TIOCSETA:
636 		case TIOCSETAW:
637 		case TIOCSETAF:
638 		case JUNK_TIOCSETAS:
639 		case JUNK_TIOCSETAWS:
640 		case JUNK_TIOCSETAFS:
641 		case TIOCSETP:
642 		case TIOCSETN:
643 #ifdef	COMPAT_43
644 		case TIOCSETC:
645 		case TIOCSLTC:
646 		case TIOCLBIS:
647 		case TIOCLBIC:
648 		case TIOCLSET:
649 #endif
650 			pti->pt_send |= TIOCPKT_IOCTL;
651 		default:
652 			break;
653 		}
654 	}
655 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
656 		&& CCEQ(cc[VSTART], CTRL('q'));
657 	if (pti->pt_flags & PF_NOSTOP) {
658 		if (stop) {
659 			pti->pt_send &= ~TIOCPKT_NOSTOP;
660 			pti->pt_send |= TIOCPKT_DOSTOP;
661 			pti->pt_flags &= ~PF_NOSTOP;
662 			ptcwakeup(tp, FREAD);
663 		}
664 	} else {
665 		if (!stop) {
666 			pti->pt_send &= ~TIOCPKT_DOSTOP;
667 			pti->pt_send |= TIOCPKT_NOSTOP;
668 			pti->pt_flags |= PF_NOSTOP;
669 			ptcwakeup(tp, FREAD);
670 		}
671 	}
672 	return (error);
673 }
674 #endif
675