tty_pty.c revision 1.7 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 (at) 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