1 /* $OpenBSD: tty_pty.c,v 1.8 2001/07/19 18:52:05 mickey Exp $ */ 2 /* $NetBSD: tty_pty.c,v 1.33.4.1 1996/06/02 09:08:11 mrg Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95 37 */ 38 39 /* 40 * Pseudo-teletype Driver 41 * (Actually two drivers, requiring two entries in 'cdevsw') 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/ioctl.h> 47 #include <sys/proc.h> 48 #include <sys/tty.h> 49 #include <sys/file.h> 50 #include <sys/uio.h> 51 #include <sys/kernel.h> 52 #include <sys/malloc.h> 53 #include <sys/vnode.h> 54 #include <sys/signalvar.h> 55 #include <sys/uio.h> 56 #include <sys/conf.h> 57 58 #define BUFSIZ 100 /* Chunk size iomoved to/from user */ 59 60 /* 61 * pts == /dev/tty[pqrs]? 62 * ptc == /dev/pty[pqrs]? 63 */ 64 struct pt_softc { 65 struct tty *pt_tty; 66 int pt_flags; 67 struct selinfo pt_selr, pt_selw; 68 u_char pt_send; 69 u_char pt_ucntl; 70 } *pt_softc; 71 int npty; 72 73 #define PF_PKT 0x08 /* packet mode */ 74 #define PF_STOPPED 0x10 /* user told stopped */ 75 #define PF_REMOTE 0x20 /* remote and flow controlled input */ 76 #define PF_NOSTOP 0x40 77 #define PF_UCNTL 0x80 /* user control mode */ 78 79 void ptyattach __P((int)); 80 void ptcwakeup __P((struct tty *, int)); 81 struct tty *ptytty __P((dev_t)); 82 void ptsstart __P((struct tty *)); 83 84 /* 85 * Establish n (or default if n is 1) ptys in the system. 86 */ 87 void 88 ptyattach(n) 89 int n; 90 { 91 #define DEFAULT_NPTY 32 92 93 /* maybe should allow 0 => none? */ 94 if (n <= 1) 95 n = DEFAULT_NPTY; 96 pt_softc = malloc(n * sizeof(struct pt_softc), M_DEVBUF, M_WAITOK); 97 bzero(pt_softc, n * sizeof(struct pt_softc)); 98 npty = n; 99 } 100 101 /*ARGSUSED*/ 102 int 103 ptsopen(dev, flag, devtype, p) 104 dev_t dev; 105 int flag, devtype; 106 struct proc *p; 107 { 108 struct pt_softc *pti; 109 register struct tty *tp; 110 int error; 111 112 if (minor(dev) >= npty) 113 return (ENXIO); 114 pti = &pt_softc[minor(dev)]; 115 if (!pti->pt_tty) { 116 tp = pti->pt_tty = ttymalloc(); 117 tty_attach(tp); 118 } 119 else 120 tp = pti->pt_tty; 121 if ((tp->t_state & TS_ISOPEN) == 0) { 122 tp->t_state |= TS_WOPEN; 123 ttychars(tp); /* Set up default chars */ 124 tp->t_iflag = TTYDEF_IFLAG; 125 tp->t_oflag = TTYDEF_OFLAG; 126 tp->t_lflag = TTYDEF_LFLAG; 127 tp->t_cflag = TTYDEF_CFLAG; 128 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 129 ttsetwater(tp); /* would be done in xxparam() */ 130 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 131 return (EBUSY); 132 if (tp->t_oproc) /* Ctrlr still around. */ 133 tp->t_state |= TS_CARR_ON; 134 while ((tp->t_state & TS_CARR_ON) == 0) { 135 tp->t_state |= TS_WOPEN; 136 if (flag&FNONBLOCK) 137 break; 138 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 139 ttopen, 0); 140 if (error) 141 return (error); 142 } 143 error = (*linesw[tp->t_line].l_open)(dev, tp); 144 ptcwakeup(tp, FREAD|FWRITE); 145 return (error); 146 } 147 148 int 149 ptsclose(dev, flag, mode, p) 150 dev_t dev; 151 int flag, mode; 152 struct proc *p; 153 { 154 register struct pt_softc *pti = &pt_softc[minor(dev)]; 155 register struct tty *tp = pti->pt_tty; 156 int error; 157 158 error = (*linesw[tp->t_line].l_close)(tp, flag); 159 error |= ttyclose(tp); 160 ptcwakeup(tp, FREAD|FWRITE); 161 return (error); 162 } 163 164 int 165 ptsread(dev, uio, flag) 166 dev_t dev; 167 struct uio *uio; 168 int flag; 169 { 170 struct proc *p = curproc; 171 register struct pt_softc *pti = &pt_softc[minor(dev)]; 172 register struct tty *tp = pti->pt_tty; 173 int error = 0; 174 175 again: 176 if (pti->pt_flags & PF_REMOTE) { 177 while (isbackground(p, tp)) { 178 if ((p->p_sigignore & sigmask(SIGTTIN)) || 179 (p->p_sigmask & sigmask(SIGTTIN)) || 180 p->p_pgrp->pg_jobc == 0 || 181 p->p_flag & P_PPWAIT) 182 return (EIO); 183 pgsignal(p->p_pgrp, SIGTTIN, 1); 184 error = ttysleep(tp, (caddr_t)&lbolt, 185 TTIPRI | PCATCH, ttybg, 0); 186 if (error) 187 return (error); 188 } 189 if (tp->t_canq.c_cc == 0) { 190 if (flag & IO_NDELAY) 191 return (EWOULDBLOCK); 192 error = ttysleep(tp, (caddr_t)&tp->t_canq, 193 TTIPRI | PCATCH, ttyin, 0); 194 if (error) 195 return (error); 196 goto again; 197 } 198 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 199 if (ureadc(getc(&tp->t_canq), uio) < 0) { 200 error = EFAULT; 201 break; 202 } 203 if (tp->t_canq.c_cc == 1) 204 (void) getc(&tp->t_canq); 205 if (tp->t_canq.c_cc) 206 return (error); 207 } else 208 if (tp->t_oproc) 209 error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 210 ptcwakeup(tp, FWRITE); 211 return (error); 212 } 213 214 /* 215 * Write to pseudo-tty. 216 * Wakeups of controlling tty will happen 217 * indirectly, when tty driver calls ptsstart. 218 */ 219 int 220 ptswrite(dev, uio, flag) 221 dev_t dev; 222 struct uio *uio; 223 int flag; 224 { 225 register struct pt_softc *pti = &pt_softc[minor(dev)]; 226 register struct tty *tp = pti->pt_tty; 227 228 if (tp->t_oproc == 0) 229 return (EIO); 230 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 231 } 232 233 /* 234 * Start output on pseudo-tty. 235 * Wake up process selecting or sleeping for input from controlling tty. 236 */ 237 void 238 ptsstart(tp) 239 struct tty *tp; 240 { 241 register struct pt_softc *pti = &pt_softc[minor(tp->t_dev)]; 242 243 if (tp->t_state & TS_TTSTOP) 244 return; 245 if (pti->pt_flags & PF_STOPPED) { 246 pti->pt_flags &= ~PF_STOPPED; 247 pti->pt_send = TIOCPKT_START; 248 } 249 ptcwakeup(tp, FREAD); 250 } 251 252 int 253 ptsstop(tp, flush) 254 register struct tty *tp; 255 int flush; 256 { 257 struct pt_softc *pti = &pt_softc[minor(tp->t_dev)]; 258 int flag; 259 260 /* note: FLUSHREAD and FLUSHWRITE already ok */ 261 if (flush == 0) { 262 flush = TIOCPKT_STOP; 263 pti->pt_flags |= PF_STOPPED; 264 } else 265 pti->pt_flags &= ~PF_STOPPED; 266 pti->pt_send |= flush; 267 /* change of perspective */ 268 flag = 0; 269 if (flush & FREAD) 270 flag |= FWRITE; 271 if (flush & FWRITE) 272 flag |= FREAD; 273 ptcwakeup(tp, flag); 274 return 0; 275 } 276 277 void 278 ptcwakeup(tp, flag) 279 struct tty *tp; 280 int flag; 281 { 282 struct pt_softc *pti = &pt_softc[minor(tp->t_dev)]; 283 284 if (flag & FREAD) { 285 selwakeup(&pti->pt_selr); 286 wakeup((caddr_t)&tp->t_outq.c_cf); 287 } 288 if (flag & FWRITE) { 289 selwakeup(&pti->pt_selw); 290 wakeup((caddr_t)&tp->t_rawq.c_cf); 291 } 292 } 293 294 int ptcopen __P((dev_t, int, int, struct proc *)); 295 296 /*ARGSUSED*/ 297 int 298 ptcopen(dev, flag, devtype, p) 299 dev_t dev; 300 int flag, devtype; 301 struct proc *p; 302 { 303 struct pt_softc *pti; 304 register struct tty *tp; 305 306 if (minor(dev) >= npty) 307 return (ENXIO); 308 pti = &pt_softc[minor(dev)]; 309 if (!pti->pt_tty) { 310 tp = pti->pt_tty = ttymalloc(); 311 tty_attach(tp); 312 } 313 else 314 tp = pti->pt_tty; 315 if (tp->t_oproc) 316 return (EIO); 317 tp->t_oproc = ptsstart; 318 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 319 tp->t_lflag &= ~EXTPROC; 320 pti->pt_flags = 0; 321 pti->pt_send = 0; 322 pti->pt_ucntl = 0; 323 return (0); 324 } 325 326 /*ARGSUSED*/ 327 int 328 ptcclose(dev, flag, devtype, p) 329 dev_t dev; 330 int flag, devtype; 331 struct proc *p; 332 { 333 register struct pt_softc *pti = &pt_softc[minor(dev)]; 334 register struct tty *tp = pti->pt_tty; 335 336 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 337 tp->t_state &= ~TS_CARR_ON; 338 tp->t_oproc = 0; /* mark closed */ 339 return (0); 340 } 341 342 int 343 ptcread(dev, uio, flag) 344 dev_t dev; 345 struct uio *uio; 346 int flag; 347 { 348 register struct pt_softc *pti = &pt_softc[minor(dev)]; 349 register struct tty *tp = pti->pt_tty; 350 char buf[BUFSIZ]; 351 int error = 0, cc; 352 353 /* 354 * We want to block until the slave 355 * is open, and there's something to read; 356 * but if we lost the slave or we're NBIO, 357 * then return the appropriate error instead. 358 */ 359 for (;;) { 360 if (tp->t_state&TS_ISOPEN) { 361 if (pti->pt_flags&PF_PKT && pti->pt_send) { 362 error = ureadc((int)pti->pt_send, uio); 363 if (error) 364 return (error); 365 if (pti->pt_send & TIOCPKT_IOCTL) { 366 cc = min(uio->uio_resid, 367 sizeof(tp->t_termios)); 368 uiomove((caddr_t) &tp->t_termios, 369 cc, uio); 370 } 371 pti->pt_send = 0; 372 return (0); 373 } 374 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 375 error = ureadc((int)pti->pt_ucntl, uio); 376 if (error) 377 return (error); 378 pti->pt_ucntl = 0; 379 return (0); 380 } 381 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 382 break; 383 } 384 if ((tp->t_state&TS_CARR_ON) == 0) 385 return (0); /* EOF */ 386 if (flag & IO_NDELAY) 387 return (EWOULDBLOCK); 388 error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH, 389 ttyin, 0); 390 if (error) 391 return (error); 392 } 393 if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 394 error = ureadc(0, uio); 395 while (uio->uio_resid > 0 && error == 0) { 396 cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 397 if (cc <= 0) 398 break; 399 error = uiomove(buf, cc, uio); 400 } 401 if (tp->t_outq.c_cc <= tp->t_lowat) { 402 if (tp->t_state&TS_ASLEEP) { 403 tp->t_state &= ~TS_ASLEEP; 404 wakeup((caddr_t)&tp->t_outq); 405 } 406 selwakeup(&tp->t_wsel); 407 } 408 return (error); 409 } 410 411 412 int 413 ptcwrite(dev, uio, flag) 414 dev_t dev; 415 register struct uio *uio; 416 int flag; 417 { 418 register struct pt_softc *pti = &pt_softc[minor(dev)]; 419 register struct tty *tp = pti->pt_tty; 420 register u_char *cp = NULL; 421 register int cc = 0; 422 u_char locbuf[BUFSIZ]; 423 int cnt = 0; 424 int error = 0; 425 426 again: 427 if ((tp->t_state&TS_ISOPEN) == 0) 428 goto block; 429 if (pti->pt_flags & PF_REMOTE) { 430 if (tp->t_canq.c_cc) 431 goto block; 432 while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 433 if (cc == 0) { 434 cc = min(uio->uio_resid, BUFSIZ); 435 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc); 436 cp = locbuf; 437 error = uiomove((caddr_t)cp, cc, uio); 438 if (error) 439 return (error); 440 /* check again for safety */ 441 if ((tp->t_state&TS_ISOPEN) == 0) 442 return (EIO); 443 } 444 if (cc) 445 (void) b_to_q((char *)cp, cc, &tp->t_canq); 446 cc = 0; 447 } 448 (void) putc(0, &tp->t_canq); 449 ttwakeup(tp); 450 wakeup((caddr_t)&tp->t_canq); 451 return (0); 452 } 453 while (uio->uio_resid > 0) { 454 if (cc == 0) { 455 cc = min(uio->uio_resid, BUFSIZ); 456 cp = locbuf; 457 error = uiomove((caddr_t)cp, cc, uio); 458 if (error) 459 return (error); 460 /* check again for safety */ 461 if ((tp->t_state&TS_ISOPEN) == 0) 462 return (EIO); 463 } 464 while (cc > 0) { 465 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 466 (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { 467 wakeup((caddr_t)&tp->t_rawq); 468 goto block; 469 } 470 (*linesw[tp->t_line].l_rint)(*cp++, tp); 471 cnt++; 472 cc--; 473 } 474 cc = 0; 475 } 476 return (0); 477 block: 478 /* 479 * Come here to wait for slave to open, for space 480 * in outq, or space in rawq. 481 */ 482 if ((tp->t_state&TS_CARR_ON) == 0) 483 return (EIO); 484 if (flag & IO_NDELAY) { 485 /* adjust for data copied in but not written */ 486 uio->uio_resid += cc; 487 if (cnt == 0) 488 return (EWOULDBLOCK); 489 return (0); 490 } 491 error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH, 492 ttyout, 0); 493 if (error) { 494 /* adjust for data copied in but not written */ 495 uio->uio_resid += cc; 496 return (error); 497 } 498 goto again; 499 } 500 501 int 502 ptcselect(dev, rw, p) 503 dev_t dev; 504 int rw; 505 struct proc *p; 506 { 507 register struct pt_softc *pti = &pt_softc[minor(dev)]; 508 register struct tty *tp = pti->pt_tty; 509 int s; 510 511 if ((tp->t_state&TS_CARR_ON) == 0) 512 return (1); 513 switch (rw) { 514 515 case FREAD: 516 /* 517 * Need to block timeouts (ttrstart). 518 */ 519 s = spltty(); 520 if ((tp->t_state&TS_ISOPEN) && 521 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 522 splx(s); 523 return (1); 524 } 525 splx(s); 526 /* FALLTHROUGH */ 527 528 case 0: /* exceptional */ 529 if ((tp->t_state&TS_ISOPEN) && 530 (((pti->pt_flags & PF_PKT) && pti->pt_send) || 531 ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))) 532 return (1); 533 selrecord(p, &pti->pt_selr); 534 break; 535 536 537 case FWRITE: 538 if (tp->t_state&TS_ISOPEN) { 539 if (pti->pt_flags & PF_REMOTE) { 540 if (tp->t_canq.c_cc == 0) 541 return (1); 542 } else { 543 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) 544 return (1); 545 if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) 546 return (1); 547 } 548 } 549 selrecord(p, &pti->pt_selw); 550 break; 551 552 } 553 return (0); 554 } 555 556 557 struct tty * 558 ptytty(dev) 559 dev_t dev; 560 { 561 register struct pt_softc *pti = &pt_softc[minor(dev)]; 562 register struct tty *tp = pti->pt_tty; 563 564 return (tp); 565 } 566 567 /*ARGSUSED*/ 568 int 569 ptyioctl(dev, cmd, data, flag, p) 570 dev_t dev; 571 u_long cmd; 572 caddr_t data; 573 int flag; 574 struct proc *p; 575 { 576 register struct pt_softc *pti = &pt_softc[minor(dev)]; 577 register struct tty *tp = pti->pt_tty; 578 register u_char *cc = tp->t_cc; 579 int stop, error; 580 581 /* 582 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 583 * ttywflush(tp) will hang if there are characters in the outq. 584 */ 585 if (cmd == TIOCEXT) { 586 /* 587 * When the EXTPROC bit is being toggled, we need 588 * to send an TIOCPKT_IOCTL if the packet driver 589 * is turned on. 590 */ 591 if (*(int *)data) { 592 if (pti->pt_flags & PF_PKT) { 593 pti->pt_send |= TIOCPKT_IOCTL; 594 ptcwakeup(tp, FREAD); 595 } 596 tp->t_lflag |= EXTPROC; 597 } else { 598 if ((tp->t_lflag & EXTPROC) && 599 (pti->pt_flags & PF_PKT)) { 600 pti->pt_send |= TIOCPKT_IOCTL; 601 ptcwakeup(tp, FREAD); 602 } 603 tp->t_lflag &= ~EXTPROC; 604 } 605 return(0); 606 } else 607 if (cdevsw[major(dev)].d_open == ptcopen) 608 switch (cmd) { 609 610 case TIOCGPGRP: 611 #ifdef COMPAT_SUNOS 612 { 613 /* 614 * I'm not sure about SunOS TIOCGPGRP semantics 615 * on PTYs, but it's something like this: 616 */ 617 extern struct emul emul_sunos; 618 if (p->p_emul == &emul_sunos && tp->t_pgrp == 0) 619 return (EIO); 620 *(int *)data = tp->t_pgrp->pg_id; 621 return (0); 622 } 623 #endif 624 /* 625 * We aviod calling ttioctl on the controller since, 626 * in that case, tp must be the controlling terminal. 627 */ 628 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 629 return (0); 630 631 case TIOCPKT: 632 if (*(int *)data) { 633 if (pti->pt_flags & PF_UCNTL) 634 return (EINVAL); 635 pti->pt_flags |= PF_PKT; 636 } else 637 pti->pt_flags &= ~PF_PKT; 638 return (0); 639 640 case TIOCUCNTL: 641 if (*(int *)data) { 642 if (pti->pt_flags & PF_PKT) 643 return (EINVAL); 644 pti->pt_flags |= PF_UCNTL; 645 } else 646 pti->pt_flags &= ~PF_UCNTL; 647 return (0); 648 649 case TIOCREMOTE: 650 if (*(int *)data) 651 pti->pt_flags |= PF_REMOTE; 652 else 653 pti->pt_flags &= ~PF_REMOTE; 654 ttyflush(tp, FREAD|FWRITE); 655 return (0); 656 657 #ifdef COMPAT_OLDTTY 658 case TIOCSETP: 659 case TIOCSETN: 660 #endif 661 case TIOCSETD: 662 case TIOCSETA: 663 case TIOCSETAW: 664 case TIOCSETAF: 665 ndflush(&tp->t_outq, tp->t_outq.c_cc); 666 break; 667 668 case TIOCSIG: 669 if (*(unsigned int *)data >= NSIG) 670 return(EINVAL); 671 if ((tp->t_lflag&NOFLSH) == 0) 672 ttyflush(tp, FREAD|FWRITE); 673 pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 674 if ((*(unsigned int *)data == SIGINFO) && 675 ((tp->t_lflag&NOKERNINFO) == 0)) 676 ttyinfo(tp); 677 return(0); 678 } 679 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 680 if (error < 0) 681 error = ttioctl(tp, cmd, data, flag, p); 682 if (error < 0) { 683 if (pti->pt_flags & PF_UCNTL && 684 (cmd & ~0xff) == UIOCCMD(0)) { 685 if (cmd & 0xff) { 686 pti->pt_ucntl = (u_char)cmd; 687 ptcwakeup(tp, FREAD); 688 } 689 return (0); 690 } 691 error = ENOTTY; 692 } 693 /* 694 * If external processing and packet mode send ioctl packet. 695 */ 696 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { 697 switch(cmd) { 698 case TIOCSETA: 699 case TIOCSETAW: 700 case TIOCSETAF: 701 #ifdef COMPAT_OLDTTY 702 case TIOCSETP: 703 case TIOCSETN: 704 case TIOCSETC: 705 case TIOCSLTC: 706 case TIOCLBIS: 707 case TIOCLBIC: 708 case TIOCLSET: 709 #endif 710 pti->pt_send |= TIOCPKT_IOCTL; 711 ptcwakeup(tp, FREAD); 712 default: 713 break; 714 } 715 } 716 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 717 && CCEQ(cc[VSTART], CTRL('q')); 718 if (pti->pt_flags & PF_NOSTOP) { 719 if (stop) { 720 pti->pt_send &= ~TIOCPKT_NOSTOP; 721 pti->pt_send |= TIOCPKT_DOSTOP; 722 pti->pt_flags &= ~PF_NOSTOP; 723 ptcwakeup(tp, FREAD); 724 } 725 } else { 726 if (!stop) { 727 pti->pt_send &= ~TIOCPKT_DOSTOP; 728 pti->pt_send |= TIOCPKT_NOSTOP; 729 pti->pt_flags |= PF_NOSTOP; 730 ptcwakeup(tp, FREAD); 731 } 732 } 733 return (error); 734 } 735