|
|
1.1 ! root 1: /* ! 2: * File: pty.c ! 3: * ! 4: * Purpose: pseudoterminal device driver ! 5: * ! 6: * Master devices are named /dev/pty[pqrs][0-f]. ! 7: * Corresponding slaves are /dev/tty[pqrs][0-f]. ! 8: * ! 9: * Minor numbers are 0..127 assigned in increasing order, ! 10: * plus 128 for master device. ! 11: * ! 12: * Output written to master appears as input to slave and ! 13: * vice versa. Data path is: ! 14: * ! 15: * app master slave line app ! 16: * using device shunt device disc. using ! 17: * master driver driver module slave ! 18: * ! 19: * slave read does ttread() which is fed by ttin() ! 20: * master write does ttin() ! 21: * ! 22: * slave write does ttwrite() which is fed by ttout() ! 23: * master read does ttout() ! 24: * ! 25: * $Log: pty.c,v $ ! 26: * Revision 1.3 92/07/16 16:35:29 hal ! 27: * Kernel #58 ! 28: * ! 29: * Revision 1.2 92/03/18 07:45:33 hal ! 30: * master device polling added ! 31: * ! 32: * Revision 1.1 92/03/16 12:57:31 hal ! 33: * Initial revision ! 34: * ! 35: */ ! 36: ! 37: /* ! 38: * ----------------------------------------------------------------- ! 39: * Includes. ! 40: */ ! 41: #include <sys/coherent.h> ! 42: #include <sys/stat.h> ! 43: #include <sys/proc.h> ! 44: #include <sys/tty.h> /* indirectly includes sgtty.h */ ! 45: #include <sys/con.h> ! 46: #include <sys/devices.h> ! 47: #include <errno.h> ! 48: #include <poll.h> ! 49: #include <sys/sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */ ! 50: ! 51: /* ! 52: * ----------------------------------------------------------------- ! 53: * Definitions. ! 54: * Constants. ! 55: * Macros with argument lists. ! 56: * Typedefs. ! 57: * Enums. ! 58: */ ! 59: ! 60: #define channel(dev) (dev & 0x7F) ! 61: #define master(dev) (dev & 0x80) ! 62: #ifdef _I386 ! 63: #define EEBUSY EBUSY ! 64: #else ! 65: #define EEBUSY EDBUSY ! 66: #endif ! 67: ! 68: /* ! 69: * Explanation of p_mopen values: ! 70: * 0 - master is closed ! 71: * 1 - master open, waiting for slave to open ! 72: * 2 - master and slave both open ! 73: * 3 - master open, slave has closed ! 74: */ ! 75: ! 76: typedef struct pty { ! 77: TTY p_tp; ! 78: event_t p_iev; ! 79: event_t p_oev; ! 80: char p_mopen; ! 81: char p_asleep; /* master is asleep in read or write awaiting slave */ ! 82: char p_ttwr; /* slave is suspended in mid ttwrite() */ ! 83: } PTY; ! 84: ! 85: /* ! 86: * ----------------------------------------------------------------- ! 87: * Functions. ! 88: * Import Functions. ! 89: * Export Functions. ! 90: * Local Functions. ! 91: */ ! 92: int nulldev(); ! 93: ! 94: /* ! 95: * Configuration functions (local functions). ! 96: */ ! 97: static void ptyclose(); ! 98: static void ptyioctl(); ! 99: static void ptyioctl0(); ! 100: static void ptyload(); ! 101: static void ptyopen(); ! 102: static void ptyread(); ! 103: static void ptyunload(); ! 104: static void ptywrite(); ! 105: static void ptystart(); ! 106: static int ptypoll(); ! 107: ! 108: /* ! 109: * Support functions (local functions). ! 110: */ ! 111: static void ptycycle(); ! 112: ! 113: /* ! 114: * ----------------------------------------------------------------- ! 115: * Global Data. ! 116: * Import Variables. ! 117: * Export Variables. ! 118: * Local Variables. ! 119: */ ! 120: int NUPTY = 8; ! 121: ! 122: /* ! 123: * Configuration table (export data). ! 124: */ ! 125: CON ptycon ={ ! 126: DFCHR|DFPOL, /* Flags */ ! 127: PTY_MAJOR, /* Major index */ ! 128: ptyopen, /* Open */ ! 129: ptyclose, /* Close */ ! 130: nulldev, /* Block */ ! 131: ptyread, /* Read */ ! 132: ptywrite, /* Write */ ! 133: #ifdef _I386 ! 134: ptyioctl0, /* Ioctl */ ! 135: #else ! 136: ptyioctl, /* Ioctl */ ! 137: #endif ! 138: nulldev, /* Powerfail */ ! 139: nulldev, /* Timeout */ ! 140: ptyload, /* Load */ ! 141: ptyunload, /* Unload */ ! 142: ptypoll /* Poll */ ! 143: }; ! 144: ! 145: static PTY * p; ! 146: ! 147: /* ! 148: * ----------------------------------------------------------------- ! 149: * Code. ! 150: */ ! 151: ! 152: /* ! 153: * ptyload() ! 154: */ ! 155: static void ! 156: ptyload() ! 157: { ! 158: int i; ! 159: TTY * tp; ! 160: ! 161: if ((p = (PTY *)kalloc(NUPTY*sizeof(PTY))) == 0) { ! 162: printf("ptyload: can't allocate %s pty's\n", NUPTY); ! 163: return; ! 164: } ! 165: kclear(p, NUPTY*sizeof(PTY)); ! 166: for (i = 0; i < NUPTY; i++) { ! 167: tp = &p[i].p_tp; ! 168: tp->t_cs_sel = cs_sel(); ! 169: tp->t_start = ptystart; ! 170: tp->t_param = nulldev; ! 171: tp->t_ddp = (char *)i; ! 172: } ! 173: } ! 174: ! 175: /* ! 176: * ptyunload() ! 177: */ ! 178: static void ! 179: ptyunload() ! 180: { ! 181: if (p) ! 182: kfree(p); ! 183: printf("pty driver unloaded\n"); ! 184: } ! 185: ! 186: /* ! 187: * ptyopen() ! 188: */ ! 189: static void ! 190: ptyopen(dev, mode) ! 191: dev_t dev; ! 192: int mode; ! 193: { ! 194: int chan = channel(dev); ! 195: PTY * pp = p + chan; ! 196: TTY * tp = &pp->p_tp; ! 197: ! 198: if (chan >= NUPTY) { ! 199: u.u_error = ENXIO; ! 200: goto open_done; ! 201: } ! 202: ! 203: if (master(dev)){ ! 204: if (pp->p_mopen) { ! 205: u.u_error = EEBUSY; ! 206: goto open_done; ! 207: } ! 208: if (tp->t_open) ! 209: pp->p_mopen = 2; ! 210: else ! 211: pp->p_mopen = 1; ! 212: wakeup((char *)(&tp->t_open)); ! 213: ptycycle(chan); ! 214: } else { ! 215: tp->t_flags |= T_HOPEN | T_STOP; ! 216: for (;;) { /* wait for carrier */ ! 217: if (pp->p_mopen) ! 218: break; ! 219: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, ! 220: SVTTOUT, "ptycd"); ! 221: /* PTY driver is waiting for carrier. */ ! 222: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 223: u.u_error = EINTR; ! 224: tp->t_flags &= ~(T_HOPEN | T_STOP); ! 225: goto open_done; ! 226: } ! 227: } ! 228: tp->t_flags |= T_CARR; ! 229: tp->t_flags &= ~(T_HOPEN | T_STOP); ! 230: ttopen(tp); ! 231: tp->t_open++; ! 232: ttsetgrp(tp, dev, mode); ! 233: if (pp->p_mopen == 1 || pp->p_mopen == 3) ! 234: pp->p_mopen = 2; ! 235: } ! 236: open_done:; ! 237: } ! 238: ! 239: /* ! 240: * ptyclose() ! 241: */ ! 242: static void ! 243: ptyclose(dev, mode) ! 244: dev_t dev; ! 245: int mode; ! 246: { ! 247: int chan = channel(dev); ! 248: PTY * pp = p + chan; ! 249: TTY * tp = &pp->p_tp; ! 250: ! 251: if (chan >= NUPTY) { ! 252: u.u_error = ENXIO; ! 253: return; ! 254: } ! 255: ! 256: if (master(dev)){ ! 257: if (pp->p_mopen) { ! 258: tp->t_flags &= ~T_CARR; ! 259: tthup(tp); ! 260: pp->p_mopen = 0; ! 261: } ! 262: } else { ! 263: if (--tp->t_open == 0) { ! 264: ttclose(tp); ! 265: if (pp->p_mopen == 2) ! 266: pp->p_mopen = 3; ! 267: wakeup(&pp->p_mopen); ! 268: } ! 269: } ! 270: } ! 271: ! 272: /* ! 273: * ptyread() ! 274: */ ! 275: static void ! 276: ptyread(dev, iop) ! 277: dev_t dev; ! 278: register IO * iop; ! 279: { ! 280: int chan = channel(dev); ! 281: PTY * pp = p + chan; ! 282: TTY * tp = &pp->p_tp; ! 283: int c; ! 284: ! 285: if (master(dev)){ ! 286: int char_read = 0; ! 287: ! 288: while (iop->io_ioc) { ! 289: c = ttout(tp); ! 290: if (c == -1) { /* nothing to fetch */ ! 291: if (char_read) { ! 292: ttstart(tp); ! 293: goto read_done; ! 294: } ! 295: if (iop->io_flag & IONDLY) { ! 296: u.u_error = EAGAIN; ! 297: goto read_done; ! 298: } ! 299: if (pp->p_mopen == 3) { ! 300: u.u_error = EIO; ! 301: goto read_done; ! 302: } ! 303: ttstart(tp); ! 304: pp->p_asleep = 1; ! 305: v_sleep(&pp->p_mopen, CVTTOUT, IVTTOUT, ! 306: SVTTOUT, "ptyread"); ! 307: /* The PTY driver is waiting for a read. */ ! 308: if (SELF->p_ssig && nondsig()) { ! 309: u.u_error = EINTR; ! 310: goto read_done; ! 311: } ! 312: } else { ! 313: ioputc(c, iop); ! 314: char_read = 1; ! 315: } ! 316: } ! 317: read_done:; ! 318: } else { ! 319: if (pp->p_asleep) { ! 320: pp->p_asleep = 0; ! 321: wakeup(&pp->p_mopen); ! 322: } ! 323: pollwake(&pp->p_oev); ! 324: ttread(tp, iop); ! 325: } ! 326: } ! 327: ! 328: /* ! 329: * ptywrite() ! 330: */ ! 331: static void ! 332: ptywrite(dev, iop) ! 333: dev_t dev; ! 334: register IO * iop; ! 335: { ! 336: int chan = channel(dev); ! 337: PTY * pp = p + chan; ! 338: TTY * tp = &pp->p_tp; ! 339: int c; ! 340: ! 341: if (master(dev)){ ! 342: while (iop->io_ioc) { ! 343: if (!ttinp(tp)) { ! 344: if (iop->io_flag & IONDLY) { ! 345: u.u_error = EAGAIN; ! 346: goto write_done; ! 347: } ! 348: if (pp->p_mopen == 3) { ! 349: u.u_error = EIO; ! 350: goto write_done; ! 351: } ! 352: pp->p_asleep = 1; ! 353: v_sleep(&pp->p_mopen, CVTTOUT, IVTTOUT, ! 354: SVTTOUT, "ptywrite"); ! 355: /* The PTY driver is waiting for a write. */ ! 356: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 357: u.u_error = EINTR; ! 358: goto write_done; ! 359: } ! 360: } ! 361: c = iogetc(iop); ! 362: ttin(tp, c); ! 363: } ! 364: wakeup(&pp->p_mopen); ! 365: } else { ! 366: pp->p_ttwr = 1; ! 367: ttwrite0(tp,iop,wakeup,&pp->p_mopen,pollwake,&pp->p_iev); ! 368: pp->p_ttwr = 0; ! 369: } ! 370: write_done:; ! 371: } ! 372: ! 373: /* ! 374: * ptyioctl() ! 375: */ ! 376: #ifdef _I386 ! 377: static void ! 378: ptyioctl0(dev, com, vec) ! 379: dev_t dev; ! 380: int com; ! 381: struct sgttyb *vec; ! 382: { ! 383: tioc286(dev, com, vec, ptyioctl); ! 384: } ! 385: #endif ! 386: ! 387: static void ! 388: ptyioctl(dev, com, vec) ! 389: dev_t dev; ! 390: int com; ! 391: struct sgttyb *vec; ! 392: { ! 393: int chan = channel(dev); ! 394: PTY * pp = p + chan; ! 395: TTY * tp = &pp->p_tp; ! 396: ! 397: if (master(dev)){ ! 398: u.u_error = EINVAL; ! 399: } else { ! 400: ttioctl(tp, com, vec); ! 401: } ! 402: } ! 403: ! 404: /* ! 405: * ptystart() ! 406: */ ! 407: static void ! 408: ptystart(tp) ! 409: TTY * tp; ! 410: { ! 411: int chan = (int)tp->t_ddp; ! 412: PTY * pp = p + chan; ! 413: ! 414: if (chan >= 0 && chan < NUPTY) { ! 415: if (pp->p_ttwr) ! 416: wakeup(&pp->p_mopen); ! 417: } ! 418: } ! 419: ! 420: /* ! 421: * ptypoll() ! 422: */ ! 423: static int ! 424: ptypoll(dev, ev, msec) ! 425: dev_t dev; ! 426: int ev; ! 427: int msec; ! 428: { ! 429: int chan = channel(dev); ! 430: PTY * pp = p + chan; ! 431: TTY * tp = &pp->p_tp; ! 432: int ret; ! 433: ! 434: if (master(dev)) { ! 435: /* ! 436: * Priority polls not supported. ! 437: */ ! 438: ev &= (POLLIN | POLLOUT); ! 439: ! 440: /* ! 441: * Input poll with no data present. ! 442: */ ! 443: if ((ev & POLLIN) && (ttoutp(tp) == 0)) { ! 444: ! 445: /* ! 446: * Blocking input poll. ! 447: */ ! 448: if (msec != 0) { ! 449: pollopen(&pp->p_iev); ! 450: } ! 451: ! 452: /* ! 453: * Second look to avoid interrupt race. ! 454: */ ! 455: if (ttoutp(tp) == 0) ! 456: ev &= ~POLLIN; ! 457: } ! 458: ! 459: /* ! 460: * Output poll with no space. ! 461: */ ! 462: if ((ev & POLLOUT) && (ttinp(tp) == 0)) { ! 463: ! 464: /* ! 465: * Blocking output poll. ! 466: */ ! 467: if (msec != 0) { ! 468: pollopen(&pp->p_oev); ! 469: } ! 470: ! 471: /* ! 472: * Second look to avoid interrupt race. ! 473: */ ! 474: if (ttinp(tp) == 0) ! 475: ev &= ~POLLIN; ! 476: } ! 477: ! 478: ret = ev; ! 479: } else ! 480: ret = ttpoll(tp, ev, msec); ! 481: return ret; ! 482: } ! 483: ! 484: /* ! 485: * ptycycle() ! 486: * ! 487: * Do a wakeup of any sleeping pty's at regular intervals. ! 488: */ ! 489: static void ! 490: ptycycle(chan) ! 491: int chan; ! 492: { ! 493: PTY * pp = p + chan; ! 494: TTY * tp = &pp->p_tp; ! 495: ! 496: /* ! 497: * Do wakeups. ! 498: */ ! 499: if (pp->p_asleep || pp->p_ttwr) { ! 500: wakeup(&pp->p_mopen); ! 501: pollwake(&pp->p_oev); ! 502: } ! 503: ! 504: /* ! 505: * Schedule next cycle. ! 506: */ ! 507: if (pp->p_mopen) ! 508: timeout(&tp->t_rawtim, HZ/10, ptycycle, chan); ! 509: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.