|
|
1.1 ! root 1: #include "../chunix/chsys.h" ! 2: #include "../chunix/chconf.h" ! 3: #include "../chaos/chaos.h" ! 4: #include "../chaos/dev.h" ! 5: #include "../h/inode.h" ! 6: #include "../h/file.h" ! 7: #include "../h/tty.h" ! 8: #include "../h/dir.h" ! 9: #include "../h/user.h" ! 10: #include "../h/conf.h" ! 11: /* ! 12: * This file contains functions for treating a chaos channel as a UNIX tty ! 13: */ ! 14: #include "cht.h" ! 15: struct tty cht_tty[NCHT * 16]; ! 16: int cht_cnt = NCHT * 16; ! 17: ! 18: /* ! 19: * Do the additional work necessary to open a channel as a UNIX tty. ! 20: * Basically the existence of an associated connection is much like ! 21: * the existence of a carrier. ! 22: */ ! 23: /* ARGSUSED */ ! 24: chtopen(dev, flag) ! 25: dev_t dev; ! 26: { ! 27: register struct tty *tp; ! 28: register int unit; ! 29: int chtstart(), chtinput(); ! 30: ! 31: unit = minor(dev); ! 32: if (unit >= cht_cnt) { ! 33: u.u_error = ENXIO; ! 34: return; ! 35: } ! 36: tp = &cht_tty[unit]; ! 37: if (tp->t_state & XCLUDE && u.u_uid != 0) { ! 38: u.u_error = EBUSY; ! 39: return; ! 40: } ! 41: tp->t_state |= WOPEN; ! 42: tp->t_oproc = chtstart; ! 43: tp->t_iproc = chtinput; ! 44: if ((tp->t_state&ISOPEN) == 0) { ! 45: ttychars(tp); ! 46: tp->t_ispeed = B9600; ! 47: tp->t_ospeed = B9600; ! 48: tp->t_flags = ODDP|EVENP|ECHO; ! 49: tp->t_state |= HUPCLS; ! 50: } ! 51: tp->t_lstate |= LSCHAOS; ! 52: LOCK; ! 53: /* ! 54: * Since ttyclose forces CARR_ON off, we turn it on again if ! 55: * the connection is still around. ! 56: */ ! 57: if (tp->t_addr) ! 58: tp->t_state |= CARR_ON; ! 59: else while ((tp->t_state & CARR_ON) == 0) ! 60: sleep((caddr_t)&tp->t_rawq, TTIPRI); ! 61: UNLOCK; ! 62: tp->t_line = NTTYDISC; ! 63: (*linesw[tp->t_line].l_open)(dev, tp); ! 64: } ! 65: /* ! 66: * Close the tty associated with the given connection. ! 67: */ ! 68: chtclose(dev, flag) ! 69: dev_t dev; ! 70: int flag; ! 71: { ! 72: register struct connection *conn; ! 73: register struct tty *tp; ! 74: ! 75: tp = &cht_tty[minor(dev)]; ! 76: (*linesw[tp->t_line].l_close)(tp); ! 77: conn = (struct connection *)tp->t_addr; ! 78: if (tp->t_state & HUPCLS || conn->cn_state != CSOPEN) { ! 79: /* ! 80: * We call the main close routine in RECORD mode, which ! 81: * closes the connection directly. ! 82: */ ! 83: conn->cn_mode = CHRECORD; ! 84: chclose(conn, flag); ! 85: tp->t_addr = 0; ! 86: tp->t_state &= ~CARR_ON; ! 87: tp->t_lstate &= ~LSCHAOS; ! 88: } ! 89: ttyclose(tp); ! 90: } ! 91: ! 92: /* ! 93: * Read from a chaos channel that is a tty. ! 94: */ ! 95: chtread(dev) ! 96: dev_t dev; ! 97: { ! 98: register struct tty *tp = &cht_tty[minor(dev)]; ! 99: register struct connection *conn = (struct connection *)tp->t_addr; ! 100: /* ! 101: * Since ttys are quite possibly interactive, be sure ! 102: * to flush any output when input is desired. It would ! 103: * be soon anyway due to timeouts. ! 104: */ ! 105: spl6(); ! 106: if (conn->cn_toutput != NOPKT && !chtfull(conn)) ! 107: ch_sflush(conn); ! 108: spl0(); ! 109: (*linesw[tp->t_line].l_read)(tp); ! 110: } ! 111: int chttyraw; ! 112: /* ! 113: * Write to a chaos channel that is a tty. ! 114: */ ! 115: chtwrite(dev) ! 116: dev_t dev; ! 117: { ! 118: register struct tty *tp = &cht_tty[minor(dev)]; ! 119: ! 120: if (tp->t_flags & RAW) { ! 121: chttyraw++; ! 122: chwrite((struct connection *)tp->t_addr); ! 123: } else ! 124: (*linesw[tp->t_line].l_write)(tp); ! 125: } ! 126: /* ! 127: * We only allow tty ioctl's for a chaos tty. ! 128: * We could also allow chaos ioctl's if needed. ! 129: */ ! 130: chtioctl(dev, cmd, addr, flag) ! 131: dev_t dev; ! 132: caddr_t addr; ! 133: { ! 134: register struct tty *tp = &cht_tty[minor(dev)]; ! 135: ! 136: cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); ! 137: if (cmd == 0) ! 138: return; ! 139: if (ttioctl(tp, cmd, addr, flag)) { ! 140: if (cmd==TIOCSETP || cmd==TIOCSETN) { ! 141: /* ! 142: * Send virtual terminal codes here? ! 143: */ ! 144: /* chparam(conn); */ ! 145: } ! 146: } else switch(cmd) { ! 147: /* ! 148: * We need a remote terminal protocol here. - Yick. ! 149: */ ! 150: case TIOCSBRK: ! 151: /* maybe someday a code for break on output ? */ ! 152: break; ! 153: case TIOCCBRK: ! 154: break; ! 155: case TIOCSDTR: ! 156: break; ! 157: case TIOCCDTR: ! 158: break; ! 159: default: ! 160: u.u_error = ENOTTY; ! 161: } ! 162: } ! 163: /* ! 164: * Interrupt routine called when a new packet is available for a tty channel ! 165: * Basically empty the packet into the tty system. ! 166: * Called both from interrupt level when the read packet queue becomes ! 167: * non-empty and also (at high priority) from top level. THe top level ! 168: * call is needed to retrieve data not queued at interrupt time due to ! 169: * input queue high water mark reached. ! 170: */ ! 171: chtrint(conn) ! 172: struct connection *conn; ! 173: { ! 174: register struct packet *pkt; ! 175: register struct tty *tp = conn->cn_ttyp; ! 176: register char *cp; ! 177: ! 178: while ((pkt = conn->cn_rhead) != NOPKT) { ! 179: if (ISDATOP(pkt) && conn->cn_state == CSOPEN) ! 180: for (cp = &pkt->pk_cdata[conn->cn_roffset]; ! 181: pkt->pk_len != 0; pkt->pk_len--) ! 182: if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= ! 183: TTYHOG) { ! 184: conn->cn_roffset = cp - pkt->pk_cdata; ! 185: return; ! 186: } else ! 187: (*linesw[tp->t_line].l_rint) ! 188: (*cp++ & 0377, tp); ! 189: ch_read(conn); ! 190: } ! 191: /* ! 192: * Flush any output since we might have echoed something at ! 193: * interrupt level. ! 194: */ ! 195: if (conn->cn_toutput != NOPKT) ! 196: ch_sflush(conn); ! 197: } ! 198: /* ! 199: * Get more data if possible. This is called from ttread (ntread) to ! 200: * see if more data can be read from the connection. ! 201: * It is only needed to account for the case where packets are not ! 202: * completely emptied at interrupt level due to input clist buffer ! 203: * overflow (>TTYHOG). In this respect, chaos connections win better ! 204: * than ttys, which just throw the data away. ! 205: */ ! 206: chtinput(tp) ! 207: register struct tty *tp; ! 208: { ! 209: register int opl = spl6(); ! 210: ! 211: chtrint((struct connection *)tp->t_addr); ! 212: splx(opl); ! 213: } ! 214: /* ! 215: * Interrupt routine called when more packets can again be sent after things ! 216: * block due to window full. ! 217: */ ! 218: chtxint(conn) ! 219: register struct connection *conn; ! 220: { ! 221: register struct tty *tp = conn->cn_ttyp; ! 222: register int s = spl6(); ! 223: ! 224: if (tp->t_state & ASLEEP) { ! 225: tp->t_state &= ~ASLEEP; ! 226: wakeup((caddr_t)&tp->t_outq); ! 227: } ! 228: if (tp->t_line) ! 229: (*linesw[tp->t_line].l_start)(tp); ! 230: else ! 231: chtstart(tp); ! 232: splx(s); ! 233: } ! 234: /* ! 235: * Are we output flow controlled? ! 236: */ ! 237: chtblocked(tp) ! 238: struct tty *tp; ! 239: { ! 240: register struct connection *conn = (struct connection *)tp->t_addr; ! 241: ! 242: return chtfull(conn); ! 243: } ! 244: /* ! 245: * Are we empty on output? ! 246: */ ! 247: chtnobuf(tp) ! 248: struct tty *tp; ! 249: { ! 250: register struct connection *conn = (struct connection *)tp->t_addr; ! 251: ! 252: return !conn->cn_toutput; ! 253: } ! 254: /* ! 255: * Flush any buffered output that we can. ! 256: * Called from high priority. ! 257: */ ! 258: chtflush(tp) ! 259: struct tty *tp; ! 260: { ! 261: register struct connection *conn = (struct connection *)tp->t_addr; ! 262: ! 263: ! 264: if (conn->cn_toutput) { ! 265: ch_free((caddr_t)conn->cn_toutput); ! 266: conn->cn_toutput = NOPKT; ! 267: } ! 268: } ! 269: ! 270: /* ! 271: * Start sending any buffered output. ! 272: * We just start sending any packet that is partially full. ! 273: */ ! 274: chtstart(tp) ! 275: struct tty *tp; ! 276: { ! 277: ch_sflush((struct connection *)tp->t_addr); ! 278: } ! 279: /* ! 280: * Put out one character and return non-zero if we couldn't ! 281: */ ! 282: chtputc(c, tp) ! 283: char c; ! 284: struct tty *tp; ! 285: { ! 286: return chtout(&c, 1, tp); ! 287: } ! 288: /* ! 289: * Send a contiguous array of bytes. ! 290: * Return the number we can't accept now. ! 291: * Packet allocation strategy: ! 292: * We allocate a packet that is at least large enough to hold all bytes ! 293: * remaining to be sent in this system call. We rely on the fact that ! 294: * packets are really powers of two in size and at least 16 bytes of data, ! 295: * since we don't round up our request at all. ! 296: * If our "clever" request fails, we try for a small packet. ! 297: */ ! 298: chtout(cp, cc, tp) ! 299: register char *cp; ! 300: struct tty *tp; ! 301: { ! 302: register struct connection *conn = (struct connection *)tp->t_addr; ! 303: register struct packet *pkt; ! 304: register int n; ! 305: int sps = spl6(); ! 306: extern int ttrstrt(); ! 307: ! 308: if (conn->cn_state == CSOPEN && ! 309: (tp->t_state & (TIMEOUT|BUSY|TTSTOP)) == 0) { ! 310: while (cc != 0) { ! 311: if ((pkt = conn->cn_toutput) == NOPKT) { ! 312: n = chtfull(conn) ? CHMAXDATA : ! 313: chroundup(u.u_count + cc); ! 314: if ((pkt = pkalloc(n, 1)) == NOPKT) { ! 315: n = CHMINDATA; ! 316: if ((pkt = pkalloc(n, 1)) == NOPKT) ! 317: break; ! 318: } ! 319: pkt->pk_op = DATOP; ! 320: pkt->pk_type = 0; ! 321: pkt->pk_lenword = 0; ! 322: conn->cn_troom = n; ! 323: conn->cn_toutput = pkt; ! 324: } ! 325: if ((n = cc) > conn->cn_troom) ! 326: n = conn->cn_troom; ! 327: if (n != 0) { ! 328: chmove(cp, &pkt->pk_cdata[pkt->pk_lenword], n); ! 329: pkt->pk_time = Chclock; ! 330: pkt->pk_lenword += n; ! 331: cp += n; ! 332: } ! 333: cc -= n; ! 334: if ((conn->cn_troom -= n) == 0) ! 335: if (chtfull(conn)) ! 336: break; ! 337: else ! 338: ch_sflush(conn); ! 339: } ! 340: } ! 341: splx(sps); ! 342: return (cc); ! 343: } ! 344: /* ! 345: * Process a connection state change for a tty. ! 346: */ ! 347: chtnstate(conn) ! 348: register struct connection *conn; ! 349: { ! 350: register struct tty *tp; ! 351: ! 352: tp = conn->cn_ttyp; ! 353: switch (conn->cn_state) { ! 354: /* ! 355: * This shouldn't really happen since the connection shouldn't ! 356: * become a tty until it is open. ! 357: */ ! 358: case CSOPEN: ! 359: if ((tp->t_state & CARR_ON) == 0) { ! 360: wakeup((caddr_t)&tp->t_rawq); ! 361: tp->t_state |= CARR_ON; ! 362: } ! 363: break; ! 364: case CSCLOSED: ! 365: case CSINCT: ! 366: case CSLOST: ! 367: if (tp->t_state & CARR_ON) { ! 368: if ((tp->t_local & LNOHANG) == 0 && ! 369: tp->t_state & ISOPEN) { ! 370: gsignal(tp->t_pgrp, SIGHUP); ! 371: #ifdef SIGCONT ! 372: gsignal(tp->t_pgrp, SIGCONT); ! 373: #endif ! 374: flushtty(tp, FREAD|FWRITE); ! 375: } ! 376: tp->t_state &= ~CARR_ON; ! 377: } else if (!(tp->t_state & ISOPEN)) { ! 378: tp->t_addr = 0; ! 379: ch_close(conn, NOPKT, 1); ! 380: ch_buffree(); ! 381: } ! 382: break; ! 383: default: ! 384: panic("chtnstate"); ! 385: } ! 386: } ! 387: ! 388:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.