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