|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1989, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95 ! 59: */ ! 60: ! 61: /* ! 62: * Pseudo-teletype Driver ! 63: * (Actually two drivers, requiring two entries in 'cdevsw') ! 64: */ ! 65: #include "pty.h" /* XXX */ ! 66: ! 67: #include <sys/param.h> ! 68: #include <sys/systm.h> ! 69: #include <sys/ioctl.h> ! 70: #include <sys/proc.h> ! 71: #include <sys/tty.h> ! 72: #include <sys/conf.h> ! 73: #include <sys/file.h> ! 74: #include <sys/uio.h> ! 75: #include <sys/kernel.h> ! 76: #include <sys/vnode.h> ! 77: #include <sys/signalvar.h> ! 78: ! 79: #ifndef NeXT ! 80: #ifdef DEVFS ! 81: #include <sys/devfsext.h> ! 82: #endif /*DEVFS*/ ! 83: ! 84: #define FREE_BSDSTATIC static ! 85: #else ! 86: #include <machine/spl.h> ! 87: ! 88: #define FREE_BSDSTATIC __private_extern__ ! 89: #define d_open_t open_close_fcn_t ! 90: #define d_close_t open_close_fcn_t ! 91: #define d_devtotty_t struct tty ** ! 92: #define d_ioctl_t ioctl_fcn_t ! 93: #define d_read_t read_write_fcn_t ! 94: #define d_write_t read_write_fcn_t ! 95: #define d_select_t select_fcn_t ! 96: typedef void d_stop_t __P((struct tty *tp, int rw)); ! 97: #endif /* NeXT */ ! 98: ! 99: #ifdef notyet ! 100: static void ptyattach __P((int n)); ! 101: #endif ! 102: static void ptsstart __P((struct tty *tp)); ! 103: static void ptcwakeup __P((struct tty *tp, int flag)); ! 104: ! 105: FREE_BSDSTATIC d_open_t ptsopen; ! 106: FREE_BSDSTATIC d_close_t ptsclose; ! 107: FREE_BSDSTATIC d_read_t ptsread; ! 108: FREE_BSDSTATIC d_write_t ptswrite; ! 109: FREE_BSDSTATIC d_ioctl_t ptyioctl; ! 110: FREE_BSDSTATIC d_stop_t ptsstop; ! 111: FREE_BSDSTATIC d_devtotty_t ptydevtotty; ! 112: FREE_BSDSTATIC d_open_t ptcopen; ! 113: FREE_BSDSTATIC d_close_t ptcclose; ! 114: FREE_BSDSTATIC d_read_t ptcread; ! 115: FREE_BSDSTATIC d_write_t ptcwrite; ! 116: FREE_BSDSTATIC d_select_t ptcselect; ! 117: ! 118: #ifndef NeXT ! 119: #define CDEV_MAJOR_S 5 ! 120: #define CDEV_MAJOR_C 6 ! 121: static struct cdevsw pts_cdevsw = ! 122: { ptsopen, ptsclose, ptsread, ptswrite, /*5*/ ! 123: ptyioctl, ptsstop, nullreset, ptydevtotty,/* ttyp */ ! 124: ttselect, nommap, NULL, "pts", NULL, -1 }; ! 125: ! 126: static struct cdevsw ptc_cdevsw = ! 127: { ptcopen, ptcclose, ptcread, ptcwrite, /*6*/ ! 128: ptyioctl, nullstop, nullreset, ptydevtotty,/* ptyp */ ! 129: ptcselect, nommap, NULL, "ptc", NULL, -1 }; ! 130: #endif /* !NeXT */ ! 131: ! 132: ! 133: #if NPTY == 1 ! 134: #undef NPTY ! 135: #define NPTY 32 /* crude XXX */ ! 136: #warning You have only one pty defined, redefining to 32. ! 137: #endif ! 138: ! 139: #ifndef NeXT ! 140: #ifdef DEVFS ! 141: #define MAXUNITS (8 * 32) ! 142: static void *devfs_token_pts[MAXUNITS]; ! 143: static void *devfs_token_ptc[MAXUNITS]; ! 144: static const char jnames[] = "pqrsPQRS"; ! 145: #if NPTY > MAXUNITS ! 146: #undef NPTY ! 147: #define NPTY MAXUNITS ! 148: #warning Can't have more than 256 pty's with DEVFS defined. ! 149: #endif /* NPTY > MAXUNITS */ ! 150: #endif /* DEVFS */ ! 151: #endif /* !NeXT */ ! 152: ! 153: #define BUFSIZ 100 /* Chunk size iomoved to/from user */ ! 154: ! 155: /* ! 156: * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] ! 157: * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] ! 158: */ ! 159: #ifndef NeXT ! 160: FREE_BSDSTATIC struct tty pt_tty[NPTY]; /* XXX */ ! 161: #else /* NeXT */ ! 162: /* NeXT All references to have been changed to indirections in the file */ ! 163: FREE_BSDSTATIC struct tty *pt_tty[NPTY] = { NULL }; ! 164: #endif /* ! NeXT */ ! 165: ! 166: static struct pt_ioctl { ! 167: int pt_flags; ! 168: struct selinfo pt_selr, pt_selw; ! 169: u_char pt_send; ! 170: u_char pt_ucntl; ! 171: } pt_ioctl[NPTY]; /* XXX */ ! 172: static int npty = NPTY; /* for pstat -t */ ! 173: ! 174: #define PF_PKT 0x08 /* packet mode */ ! 175: #define PF_STOPPED 0x10 /* user told stopped */ ! 176: #define PF_REMOTE 0x20 /* remote and flow controlled input */ ! 177: #define PF_NOSTOP 0x40 ! 178: #define PF_UCNTL 0x80 /* user control mode */ ! 179: ! 180: #ifdef notyet ! 181: /* ! 182: * Establish n (or default if n is 1) ptys in the system. ! 183: * ! 184: * XXX cdevsw & pstat require the array `pty[]' to be an array ! 185: */ ! 186: FREEBSD_STATIC void ! 187: ptyattach(n) ! 188: int n; ! 189: { ! 190: char *mem; ! 191: register u_long ntb; ! 192: #define DEFAULT_NPTY 32 ! 193: ! 194: /* maybe should allow 0 => none? */ ! 195: if (n <= 1) ! 196: n = DEFAULT_NPTY; ! 197: ntb = n * sizeof(struct tty); ! 198: #ifndef NeXT ! 199: mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl), ! 200: M_DEVBUF, M_WAITOK); ! 201: #else ! 202: MALLOC(mem, char *, ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl), ! 203: M_DEVBUF, M_WAITOK); ! 204: #endif /* !NeXT */ ! 205: pt_tty = (struct tty *)mem; ! 206: mem = (char *)ALIGN(mem + ntb); ! 207: pt_ioctl = (struct pt_ioctl *)mem; ! 208: npty = n; ! 209: } ! 210: #endif ! 211: ! 212: #ifdef NeXT ! 213: int pty_init() ! 214: { ! 215: return 0; ! 216: } ! 217: #endif ! 218: ! 219: /*ARGSUSED*/ ! 220: FREE_BSDSTATIC int ! 221: ptsopen(dev, flag, devtype, p) ! 222: dev_t dev; ! 223: int flag, devtype; ! 224: struct proc *p; ! 225: { ! 226: register struct tty *tp; ! 227: int error; ! 228: ! 229: #ifndef NeXT ! 230: tp = &pt_tty[minor(dev)]; ! 231: #else ! 232: /* ! 233: * You will see this sourt of code coming up in diffs later both ! 234: * the ttymalloc and the tp indirection. ! 235: */ ! 236: if (minor(dev) >= npty) ! 237: return (ENXIO); ! 238: if (!pt_tty[minor(dev)]) { ! 239: tp = pt_tty[minor(dev)] = ttymalloc(); ! 240: } else ! 241: tp = pt_tty[minor(dev)]; ! 242: #endif ! 243: if ((tp->t_state & TS_ISOPEN) == 0) { ! 244: ttychars(tp); /* Set up default chars */ ! 245: tp->t_iflag = TTYDEF_IFLAG; ! 246: tp->t_oflag = TTYDEF_OFLAG; ! 247: tp->t_lflag = TTYDEF_LFLAG; ! 248: tp->t_cflag = TTYDEF_CFLAG; ! 249: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; ! 250: ttsetwater(tp); /* would be done in xxparam() */ ! 251: } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) ! 252: return (EBUSY); ! 253: if (tp->t_oproc) /* Ctrlr still around. */ ! 254: (void)(*linesw[tp->t_line].l_modem)(tp, 1); ! 255: while ((tp->t_state & TS_CARR_ON) == 0) { ! 256: if (flag&FNONBLOCK) ! 257: break; ! 258: error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, ! 259: "ptsopn", 0); ! 260: if (error) ! 261: return (error); ! 262: } ! 263: error = (*linesw[tp->t_line].l_open)(dev, tp); ! 264: if (error == 0) ! 265: ptcwakeup(tp, FREAD|FWRITE); ! 266: return (error); ! 267: } ! 268: ! 269: FREE_BSDSTATIC int ! 270: ptsclose(dev, flag, mode, p) ! 271: dev_t dev; ! 272: int flag, mode; ! 273: struct proc *p; ! 274: { ! 275: register struct tty *tp; ! 276: int err; ! 277: ! 278: tp = pt_tty[minor(dev)]; ! 279: err = (*linesw[tp->t_line].l_close)(tp, flag); ! 280: ptsstop(tp, FREAD|FWRITE); ! 281: (void) ttyclose(tp); ! 282: return (err); ! 283: } ! 284: ! 285: FREE_BSDSTATIC int ! 286: ptsread(dev, uio, flag) ! 287: dev_t dev; ! 288: struct uio *uio; ! 289: int flag; ! 290: { ! 291: #ifndef NeXT ! 292: struct proc *p = curproc; ! 293: #else ! 294: struct proc *p = current_proc(); ! 295: #endif /* NeXT */ ! 296: register struct tty *tp = pt_tty[minor(dev)]; ! 297: register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; ! 298: int error = 0; ! 299: ! 300: again: ! 301: if (pti->pt_flags & PF_REMOTE) { ! 302: while (isbackground(p, tp)) { ! 303: if ((p->p_sigignore & sigmask(SIGTTIN)) || ! 304: (p->p_sigmask & sigmask(SIGTTIN)) || ! 305: p->p_pgrp->pg_jobc == 0 || ! 306: p->p_flag & P_PPWAIT) ! 307: return (EIO); ! 308: pgsignal(p->p_pgrp, SIGTTIN, 1); ! 309: error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg", ! 310: 0); ! 311: if (error) ! 312: return (error); ! 313: } ! 314: if (tp->t_canq.c_cc == 0) { ! 315: if (flag & IO_NDELAY) ! 316: return (EWOULDBLOCK); ! 317: error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH, ! 318: "ptsin", 0); ! 319: if (error) ! 320: return (error); ! 321: goto again; ! 322: } ! 323: while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) ! 324: if (ureadc(getc(&tp->t_canq), uio) < 0) { ! 325: error = EFAULT; ! 326: break; ! 327: } ! 328: if (tp->t_canq.c_cc == 1) ! 329: (void) getc(&tp->t_canq); ! 330: if (tp->t_canq.c_cc) ! 331: return (error); ! 332: } else ! 333: if (tp->t_oproc) ! 334: error = (*linesw[tp->t_line].l_read)(tp, uio, flag); ! 335: ptcwakeup(tp, FWRITE); ! 336: return (error); ! 337: } ! 338: ! 339: /* ! 340: * Write to pseudo-tty. ! 341: * Wakeups of controlling tty will happen ! 342: * indirectly, when tty driver calls ptsstart. ! 343: */ ! 344: FREE_BSDSTATIC int ! 345: ptswrite(dev, uio, flag) ! 346: dev_t dev; ! 347: struct uio *uio; ! 348: int flag; ! 349: { ! 350: register struct tty *tp; ! 351: ! 352: tp = pt_tty[minor(dev)]; ! 353: if (tp->t_oproc == 0) ! 354: return (EIO); ! 355: return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); ! 356: } ! 357: ! 358: /* ! 359: * Start output on pseudo-tty. ! 360: * Wake up process selecting or sleeping for input from controlling tty. ! 361: */ ! 362: static void ! 363: ptsstart(tp) ! 364: struct tty *tp; ! 365: { ! 366: register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; ! 367: ! 368: if (tp->t_state & TS_TTSTOP) ! 369: return; ! 370: if (pti->pt_flags & PF_STOPPED) { ! 371: pti->pt_flags &= ~PF_STOPPED; ! 372: pti->pt_send = TIOCPKT_START; ! 373: } ! 374: ptcwakeup(tp, FREAD); ! 375: } ! 376: ! 377: static void ! 378: ptcwakeup(tp, flag) ! 379: struct tty *tp; ! 380: int flag; ! 381: { ! 382: struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; ! 383: ! 384: if (flag & FREAD) { ! 385: selwakeup(&pti->pt_selr); ! 386: wakeup(TSA_PTC_READ(tp)); ! 387: } ! 388: if (flag & FWRITE) { ! 389: selwakeup(&pti->pt_selw); ! 390: wakeup(TSA_PTC_WRITE(tp)); ! 391: } ! 392: } ! 393: ! 394: FREE_BSDSTATIC int ! 395: ptcopen(dev, flag, devtype, p) ! 396: dev_t dev; ! 397: int flag, devtype; ! 398: struct proc *p; ! 399: { ! 400: register struct tty *tp; ! 401: struct pt_ioctl *pti; ! 402: ! 403: if (minor(dev) >= npty) ! 404: return (ENXIO); ! 405: if(!pt_tty[minor(dev)]) { ! 406: tp = pt_tty[minor(dev)] = ttymalloc(); ! 407: } else ! 408: tp = pt_tty[minor(dev)]; ! 409: if (tp->t_oproc) ! 410: return (EIO); ! 411: tp->t_oproc = ptsstart; ! 412: #ifdef sun4c ! 413: tp->t_stop = ptsstop; ! 414: #endif ! 415: (void)(*linesw[tp->t_line].l_modem)(tp, 1); ! 416: tp->t_lflag &= ~EXTPROC; ! 417: pti = &pt_ioctl[minor(dev)]; ! 418: pti->pt_flags = 0; ! 419: pti->pt_send = 0; ! 420: pti->pt_ucntl = 0; ! 421: return (0); ! 422: } ! 423: ! 424: FREE_BSDSTATIC int ! 425: ptcclose(dev, flags, fmt, p) ! 426: dev_t dev; ! 427: int flags; ! 428: int fmt; ! 429: struct proc *p; ! 430: { ! 431: register struct tty *tp; ! 432: ! 433: tp = pt_tty[minor(dev)]; ! 434: (void)(*linesw[tp->t_line].l_modem)(tp, 0); ! 435: ! 436: /* ! 437: * XXX MDMBUF makes no sense for ptys but would inhibit the above ! 438: * l_modem(). CLOCAL makes sense but isn't supported. Special ! 439: * l_modem()s that ignore carrier drop make no sense for ptys but ! 440: * may be in use because other parts of the line discipline make ! 441: * sense for ptys. Recover by doing everything that a normal ! 442: * ttymodem() would have done except for sending a SIGHUP. ! 443: */ ! 444: if (tp->t_state & TS_ISOPEN) { ! 445: tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); ! 446: tp->t_state |= TS_ZOMBIE; ! 447: ttyflush(tp, FREAD | FWRITE); ! 448: } ! 449: ! 450: tp->t_oproc = 0; /* mark closed */ ! 451: return (0); ! 452: } ! 453: ! 454: FREE_BSDSTATIC int ! 455: ptcread(dev, uio, flag) ! 456: dev_t dev; ! 457: struct uio *uio; ! 458: int flag; ! 459: { ! 460: register struct tty *tp = pt_tty[minor(dev)]; ! 461: struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; ! 462: char buf[BUFSIZ]; ! 463: int error = 0, cc; ! 464: ! 465: /* ! 466: * We want to block until the slave ! 467: * is open, and there's something to read; ! 468: * but if we lost the slave or we're NBIO, ! 469: * then return the appropriate error instead. ! 470: */ ! 471: for (;;) { ! 472: if (tp->t_state&TS_ISOPEN) { ! 473: if (pti->pt_flags&PF_PKT && pti->pt_send) { ! 474: error = ureadc((int)pti->pt_send, uio); ! 475: if (error) ! 476: return (error); ! 477: if (pti->pt_send & TIOCPKT_IOCTL) { ! 478: cc = min(uio->uio_resid, ! 479: sizeof(tp->t_termios)); ! 480: uiomove((caddr_t)&tp->t_termios, cc, ! 481: uio); ! 482: } ! 483: pti->pt_send = 0; ! 484: return (0); ! 485: } ! 486: if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { ! 487: error = ureadc((int)pti->pt_ucntl, uio); ! 488: if (error) ! 489: return (error); ! 490: pti->pt_ucntl = 0; ! 491: return (0); ! 492: } ! 493: if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) ! 494: break; ! 495: } ! 496: if ((tp->t_state & TS_CONNECTED) == 0) ! 497: return (0); /* EOF */ ! 498: if (flag & IO_NDELAY) ! 499: return (EWOULDBLOCK); ! 500: error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); ! 501: if (error) ! 502: return (error); ! 503: } ! 504: if (pti->pt_flags & (PF_PKT|PF_UCNTL)) ! 505: error = ureadc(0, uio); ! 506: while (uio->uio_resid > 0 && error == 0) { ! 507: cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); ! 508: if (cc <= 0) ! 509: break; ! 510: error = uiomove(buf, cc, uio); ! 511: } ! 512: ttwwakeup(tp); ! 513: return (error); ! 514: } ! 515: ! 516: FREE_BSDSTATIC void ! 517: ptsstop(tp, flush) ! 518: register struct tty *tp; ! 519: int flush; ! 520: { ! 521: struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; ! 522: int flag; ! 523: ! 524: /* note: FLUSHREAD and FLUSHWRITE already ok */ ! 525: if (flush == 0) { ! 526: flush = TIOCPKT_STOP; ! 527: pti->pt_flags |= PF_STOPPED; ! 528: } else ! 529: pti->pt_flags &= ~PF_STOPPED; ! 530: pti->pt_send |= flush; ! 531: /* change of perspective */ ! 532: flag = 0; ! 533: if (flush & FREAD) ! 534: flag |= FWRITE; ! 535: if (flush & FWRITE) ! 536: flag |= FREAD; ! 537: ptcwakeup(tp, flag); ! 538: } ! 539: ! 540: FREE_BSDSTATIC int ! 541: ptcselect(dev, rw, p) ! 542: dev_t dev; ! 543: int rw; ! 544: struct proc *p; ! 545: { ! 546: register struct tty *tp = pt_tty[minor(dev)]; ! 547: struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; ! 548: int s; ! 549: ! 550: if ((tp->t_state & TS_CONNECTED) == 0) ! 551: return (1); ! 552: switch (rw) { ! 553: ! 554: case FREAD: ! 555: /* ! 556: * Need to block timeouts (ttrstart). ! 557: */ ! 558: s = spltty(); ! 559: if ((tp->t_state&TS_ISOPEN) && ! 560: tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { ! 561: splx(s); ! 562: return (1); ! 563: } ! 564: splx(s); ! 565: /* FALLTHROUGH */ ! 566: ! 567: case 0: /* exceptional */ ! 568: if ((tp->t_state&TS_ISOPEN) && ! 569: ((pti->pt_flags&PF_PKT && pti->pt_send) || ! 570: (pti->pt_flags&PF_UCNTL && pti->pt_ucntl))) ! 571: return (1); ! 572: selrecord(p, &pti->pt_selr); ! 573: break; ! 574: ! 575: ! 576: case FWRITE: ! 577: if (tp->t_state&TS_ISOPEN) { ! 578: if (pti->pt_flags & PF_REMOTE) { ! 579: if (tp->t_canq.c_cc == 0) ! 580: return (1); ! 581: } else { ! 582: if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ! 583: return (1); ! 584: if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) ! 585: return (1); ! 586: } ! 587: } ! 588: selrecord(p, &pti->pt_selw); ! 589: break; ! 590: ! 591: } ! 592: return (0); ! 593: } ! 594: ! 595: FREE_BSDSTATIC int ! 596: ptcwrite(dev, uio, flag) ! 597: dev_t dev; ! 598: register struct uio *uio; ! 599: int flag; ! 600: { ! 601: register struct tty *tp = pt_tty[minor(dev)]; ! 602: register u_char *cp = NULL; ! 603: register int cc = 0; ! 604: u_char locbuf[BUFSIZ]; ! 605: int cnt = 0; ! 606: struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; ! 607: int error = 0; ! 608: ! 609: again: ! 610: if ((tp->t_state&TS_ISOPEN) == 0) ! 611: goto block; ! 612: if (pti->pt_flags & PF_REMOTE) { ! 613: if (tp->t_canq.c_cc) ! 614: goto block; ! 615: while ((uio->uio_resid > 0 || cc > 0) && ! 616: tp->t_canq.c_cc < TTYHOG - 1) { ! 617: if (cc == 0) { ! 618: cc = min(uio->uio_resid, BUFSIZ); ! 619: cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc); ! 620: cp = locbuf; ! 621: error = uiomove((caddr_t)cp, cc, uio); ! 622: if (error) ! 623: return (error); ! 624: /* check again for safety */ ! 625: if ((tp->t_state & TS_ISOPEN) == 0) { ! 626: /* adjust as usual */ ! 627: uio->uio_resid += cc; ! 628: return (EIO); ! 629: } ! 630: } ! 631: if (cc > 0) { ! 632: cc = b_to_q((char *)cp, cc, &tp->t_canq); ! 633: /* ! 634: * XXX we don't guarantee that the canq size ! 635: * is >= TTYHOG, so the above b_to_q() may ! 636: * leave some bytes uncopied. However, space ! 637: * is guaranteed for the null terminator if ! 638: * we don't fail here since (TTYHOG - 1) is ! 639: * not a multiple of CBSIZE. ! 640: */ ! 641: if (cc > 0) ! 642: break; ! 643: } ! 644: } ! 645: /* adjust for data copied in but not written */ ! 646: uio->uio_resid += cc; ! 647: (void) putc(0, &tp->t_canq); ! 648: ttwakeup(tp); ! 649: wakeup(TSA_PTS_READ(tp)); ! 650: return (0); ! 651: } ! 652: while (uio->uio_resid > 0 || cc > 0) { ! 653: if (cc == 0) { ! 654: cc = min(uio->uio_resid, BUFSIZ); ! 655: cp = locbuf; ! 656: error = uiomove((caddr_t)cp, cc, uio); ! 657: if (error) ! 658: return (error); ! 659: /* check again for safety */ ! 660: if ((tp->t_state & TS_ISOPEN) == 0) { ! 661: /* adjust for data copied in but not written */ ! 662: uio->uio_resid += cc; ! 663: return (EIO); ! 664: } ! 665: } ! 666: while (cc > 0) { ! 667: if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && ! 668: (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { ! 669: wakeup(TSA_HUP_OR_INPUT(tp)); ! 670: goto block; ! 671: } ! 672: (*linesw[tp->t_line].l_rint)(*cp++, tp); ! 673: cnt++; ! 674: cc--; ! 675: } ! 676: cc = 0; ! 677: } ! 678: return (0); ! 679: block: ! 680: /* ! 681: * Come here to wait for slave to open, for space ! 682: * in outq, or space in rawq, or an empty canq. ! 683: */ ! 684: if ((tp->t_state & TS_CONNECTED) == 0) { ! 685: /* adjust for data copied in but not written */ ! 686: uio->uio_resid += cc; ! 687: return (EIO); ! 688: } ! 689: if (flag & IO_NDELAY) { ! 690: /* adjust for data copied in but not written */ ! 691: uio->uio_resid += cc; ! 692: if (cnt == 0) ! 693: return (EWOULDBLOCK); ! 694: return (0); ! 695: } ! 696: error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); ! 697: if (error) { ! 698: /* adjust for data copied in but not written */ ! 699: uio->uio_resid += cc; ! 700: return (error); ! 701: } ! 702: goto again; ! 703: } ! 704: ! 705: #ifndef NeXT ! 706: /* XXX we eventually want to go to this model, ! 707: * but premier can't change the cdevsw */ ! 708: static struct tty * ! 709: ptydevtotty(dev) ! 710: dev_t dev; ! 711: { ! 712: if (minor(dev) >= npty) ! 713: return (NULL); ! 714: ! 715: return &pt_tty[minor(dev)]; ! 716: } ! 717: #endif /* !NeXT */ ! 718: ! 719: /*ARGSUSED*/ ! 720: FREE_BSDSTATIC int ! 721: #ifndef NeXT ! 722: ptyioctl(dev, cmd, data, flag) ! 723: dev_t dev; ! 724: int cmd; ! 725: caddr_t data; ! 726: int flag; ! 727: #else ! 728: ptyioctl(dev, cmd, data, flag, p) ! 729: dev_t dev; ! 730: u_long cmd; ! 731: caddr_t data; ! 732: int flag; ! 733: struct proc *p; ! 734: #endif ! 735: { ! 736: register struct tty *tp = pt_tty[minor(dev)]; ! 737: register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; ! 738: register u_char *cc = tp->t_cc; ! 739: int stop, error; ! 740: ! 741: /* ! 742: * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. ! 743: * ttywflush(tp) will hang if there are characters in the outq. ! 744: */ ! 745: if (cmd == TIOCEXT) { ! 746: /* ! 747: * When the EXTPROC bit is being toggled, we need ! 748: * to send an TIOCPKT_IOCTL if the packet driver ! 749: * is turned on. ! 750: */ ! 751: if (*(int *)data) { ! 752: if (pti->pt_flags & PF_PKT) { ! 753: pti->pt_send |= TIOCPKT_IOCTL; ! 754: ptcwakeup(tp, FREAD); ! 755: } ! 756: tp->t_lflag |= EXTPROC; ! 757: } else { ! 758: if ((tp->t_lflag & EXTPROC) && ! 759: (pti->pt_flags & PF_PKT)) { ! 760: pti->pt_send |= TIOCPKT_IOCTL; ! 761: ptcwakeup(tp, FREAD); ! 762: } ! 763: tp->t_lflag &= ~EXTPROC; ! 764: } ! 765: return(0); ! 766: } else ! 767: #ifndef NeXT ! 768: if (cdevsw[major(dev)]->d_open == ptcopen) ! 769: #else ! 770: if (cdevsw[major(dev)].d_open == ptcopen) ! 771: #endif ! 772: switch (cmd) { ! 773: ! 774: case TIOCGPGRP: ! 775: /* ! 776: * We aviod calling ttioctl on the controller since, ! 777: * in that case, tp must be the controlling terminal. ! 778: */ ! 779: *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; ! 780: return (0); ! 781: ! 782: case TIOCPKT: ! 783: if (*(int *)data) { ! 784: if (pti->pt_flags & PF_UCNTL) ! 785: return (EINVAL); ! 786: pti->pt_flags |= PF_PKT; ! 787: } else ! 788: pti->pt_flags &= ~PF_PKT; ! 789: return (0); ! 790: ! 791: case TIOCUCNTL: ! 792: if (*(int *)data) { ! 793: if (pti->pt_flags & PF_PKT) ! 794: return (EINVAL); ! 795: pti->pt_flags |= PF_UCNTL; ! 796: } else ! 797: pti->pt_flags &= ~PF_UCNTL; ! 798: return (0); ! 799: ! 800: case TIOCREMOTE: ! 801: if (*(int *)data) ! 802: pti->pt_flags |= PF_REMOTE; ! 803: else ! 804: pti->pt_flags &= ~PF_REMOTE; ! 805: ttyflush(tp, FREAD|FWRITE); ! 806: return (0); ! 807: ! 808: #ifdef COMPAT_43 ! 809: case TIOCSETP: ! 810: case TIOCSETN: ! 811: #endif ! 812: case TIOCSETD: ! 813: case TIOCSETA: ! 814: case TIOCSETAW: ! 815: case TIOCSETAF: ! 816: ndflush(&tp->t_outq, tp->t_outq.c_cc); ! 817: break; ! 818: ! 819: case TIOCSIG: ! 820: if (*(unsigned int *)data >= NSIG || ! 821: *(unsigned int *)data == 0) ! 822: return(EINVAL); ! 823: if ((tp->t_lflag&NOFLSH) == 0) ! 824: ttyflush(tp, FREAD|FWRITE); ! 825: pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); ! 826: if ((*(unsigned int *)data == SIGINFO) && ! 827: ((tp->t_lflag&NOKERNINFO) == 0)) ! 828: ttyinfo(tp); ! 829: return(0); ! 830: } ! 831: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); ! 832: if (error < 0) ! 833: error = ttioctl(tp, cmd, data, flag, p); ! 834: if (error < 0) { ! 835: if (pti->pt_flags & PF_UCNTL && ! 836: (cmd & ~0xff) == UIOCCMD(0)) { ! 837: if (cmd & 0xff) { ! 838: pti->pt_ucntl = (u_char)cmd; ! 839: ptcwakeup(tp, FREAD); ! 840: } ! 841: return (0); ! 842: } ! 843: error = ENOTTY; ! 844: } ! 845: /* ! 846: * If external processing and packet mode send ioctl packet. ! 847: */ ! 848: if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { ! 849: switch(cmd) { ! 850: case TIOCSETA: ! 851: case TIOCSETAW: ! 852: case TIOCSETAF: ! 853: #ifdef COMPAT_43 ! 854: case TIOCSETP: ! 855: case TIOCSETN: ! 856: #endif ! 857: #if defined(COMPAT_43) || defined(COMPAT_SUNOS) ! 858: case TIOCSETC: ! 859: case TIOCSLTC: ! 860: case TIOCLBIS: ! 861: case TIOCLBIC: ! 862: case TIOCLSET: ! 863: #endif ! 864: pti->pt_send |= TIOCPKT_IOCTL; ! 865: ptcwakeup(tp, FREAD); ! 866: default: ! 867: break; ! 868: } ! 869: } ! 870: stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) ! 871: && CCEQ(cc[VSTART], CTRL('q')); ! 872: if (pti->pt_flags & PF_NOSTOP) { ! 873: if (stop) { ! 874: pti->pt_send &= ~TIOCPKT_NOSTOP; ! 875: pti->pt_send |= TIOCPKT_DOSTOP; ! 876: pti->pt_flags &= ~PF_NOSTOP; ! 877: ptcwakeup(tp, FREAD); ! 878: } ! 879: } else { ! 880: if (!stop) { ! 881: pti->pt_send &= ~TIOCPKT_DOSTOP; ! 882: pti->pt_send |= TIOCPKT_NOSTOP; ! 883: pti->pt_flags |= PF_NOSTOP; ! 884: ptcwakeup(tp, FREAD); ! 885: } ! 886: } ! 887: return (error); ! 888: } ! 889: ! 890: #ifndef NeXT ! 891: static ptc_devsw_installed = 0; ! 892: ! 893: static void ! 894: ptc_drvinit(void *unused) ! 895: { ! 896: #ifdef DEVFS ! 897: int i,j,k; ! 898: #endif ! 899: dev_t dev; ! 900: ! 901: if( ! ptc_devsw_installed ) { ! 902: dev = makedev(CDEV_MAJOR_S, 0); ! 903: cdevsw_add(&dev, &pts_cdevsw, NULL); ! 904: dev = makedev(CDEV_MAJOR_C, 0); ! 905: cdevsw_add(&dev, &ptc_cdevsw, NULL); ! 906: ptc_devsw_installed = 1; ! 907: #ifdef DEVFS ! 908: for ( i = 0 ; i<NPTY ; i++ ) { ! 909: j = i / 32; ! 910: k = i % 32; ! 911: devfs_token_pts[i] = ! 912: devfs_add_devswf(&pts_cdevsw,i, ! 913: DV_CHR,0,0,0666, ! 914: "tty%c%n",jnames[j],k); ! 915: devfs_token_ptc[i] = ! 916: devfs_add_devswf(&ptc_cdevsw,i, ! 917: DV_CHR,0,0,0666, ! 918: "pty%c%n",jnames[j],k); ! 919: } ! 920: #endif ! 921: } ! 922: } ! 923: ! 924: SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL) ! 925: #endif /* !NeXT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.