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