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