|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * @(#)cons.c 7.1 (Berkeley) 5/21/88 ! 7: */ ! 8: ! 9: /* ! 10: * Tahoe console processor driver ! 11: * ! 12: * Minor device 0 is the CP itself. ! 13: * No real read/writes can be done to him. ! 14: * Minor 1 is the console terminal. ! 15: * Minor 2 is the remote line trminal. ! 16: */ ! 17: #include "param.h" ! 18: #include "conf.h" ! 19: #include "dir.h" ! 20: #include "ioctl.h" ! 21: #include "user.h" ! 22: #include "proc.h" ! 23: #include "tty.h" ! 24: #include "uio.h" ! 25: #include "callout.h" ! 26: #include "systm.h" ! 27: #include "kernel.h" ! 28: #include "syslog.h" ! 29: ! 30: #include "cp.h" ! 31: #include "cpu.h" ! 32: #include "mtpr.h" ! 33: ! 34: int cnrestart(); ! 35: int timeout(); ! 36: ! 37: struct tty CPtty; ! 38: struct tty cons; ! 39: struct tty RLtty; ! 40: struct tty *cntty[3] = { &CPtty, &cons, &RLtty }; ! 41: ! 42: struct tty *constty = 0; /* virtual console */ ! 43: ! 44: struct consoftc { ! 45: char cs_flags; ! 46: #define CSF_ACTIVE 0x1 /* timeout active */ ! 47: #define CSF_POLLING 0x2 /* polling for input */ ! 48: char cs_lastc; /* last char sent */ ! 49: int cs_timo; /* timeouts since interrupt */ ! 50: u_long cs_wedgecnt; /* times restarted */ ! 51: } consoftc[3]; ! 52: ! 53: /* ! 54: * We check the console periodically to make sure ! 55: * that it hasn't wedged. Unfortunately, if an XOFF ! 56: * is typed on the console, that can't be distinguished ! 57: * from more catastrophic failure. ! 58: */ ! 59: #define CN_TIMERVAL (hz) /* frequency at which to check cons */ ! 60: #define CN_TIMO (2*60) /* intervals to allow for output char */ ! 61: ! 62: struct cpdcb_o consout[3] = { ! 63: { CPTAKE|CPDONE }, { CPTAKE|CPDONE }, { CPTAKE|CPDONE } ! 64: }; ! 65: struct cpdcb_i consin[3] = { ! 66: { CPTAKE|CPDONE }, { CPTAKE|CPDONE }, { CPTAKE|CPDONE } ! 67: }; ! 68: struct cphdr *cnlast; ! 69: ! 70: int cnstart(); ! 71: int ttrstrt(); ! 72: char partab[]; ! 73: ! 74: /* ! 75: * Wait for CP to accept last CP command sent ! 76: * before setting up next command. ! 77: */ ! 78: #define waitforlast(timo) { \ ! 79: if (cnlast) { \ ! 80: (timo) = 10000; \ ! 81: do \ ! 82: uncache((char *)&cnlast->cp_unit); \ ! 83: while ((cnlast->cp_unit&CPTAKE) == 0 && --(timo)); \ ! 84: } \ ! 85: } ! 86: ! 87: /*ARGSUSED*/ ! 88: cnopen(dev, flag) ! 89: dev_t dev; ! 90: { ! 91: register struct tty *tp; ! 92: int unit = minor(dev); ! 93: ! 94: if (unit > CPREMOT) ! 95: return (ENXIO); ! 96: tp = cntty[unit]; ! 97: if (tp->t_state&TS_XCLUDE && u.u_uid != 0) ! 98: return (EBUSY); ! 99: cnpostread(unit); /* post request for input */ ! 100: tp->t_oproc = cnstart; ! 101: tp->t_dev = dev; ! 102: if ((tp->t_state&TS_ISOPEN) == 0) { ! 103: ttychars(tp); ! 104: tp->t_state = TS_ISOPEN|TS_CARR_ON; ! 105: tp->t_flags = EVENP|ECHO|XTABS|CRMOD; ! 106: } ! 107: return ((*linesw[tp->t_line].l_open)(dev, tp)); ! 108: } ! 109: ! 110: cnpostread(unit) ! 111: int unit; ! 112: { ! 113: register struct cpdcb_i *cin; ! 114: register int timo; ! 115: ! 116: waitforlast(timo); ! 117: cin = &consin[unit]; ! 118: cin->cp_hdr.cp_unit = unit; ! 119: cin->cp_hdr.cp_comm = CPREAD; ! 120: cin->cp_hdr.cp_count = 1; /* Get ready for input */ ! 121: mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)cin)); ! 122: cnlast = &cin->cp_hdr; ! 123: } ! 124: ! 125: cnclose(dev) ! 126: dev_t dev; ! 127: { ! 128: register struct tty *tp = cntty[minor(dev)]; ! 129: ! 130: (*linesw[tp->t_line].l_close)(tp); ! 131: ttyclose(tp); ! 132: } ! 133: ! 134: /*ARGSUSED*/ ! 135: cnread(dev, uio) ! 136: dev_t dev; ! 137: struct uio *uio; ! 138: { ! 139: struct tty *tp = cntty[minor(dev)]; ! 140: ! 141: return ((*linesw[tp->t_line].l_read)(tp, uio)); ! 142: } ! 143: ! 144: /*ARGSUSED*/ ! 145: cnwrite(dev, uio) ! 146: dev_t dev; ! 147: struct uio *uio; ! 148: { ! 149: register struct tty *tp = cntty[minor(dev)]; ! 150: ! 151: if (tp == &cons && constty && ! 152: (constty->t_state & (TS_CARR_ON | TS_ISOPEN)) == ! 153: (TS_CARR_ON | TS_ISOPEN)) ! 154: tp = constty; ! 155: return ((*linesw[tp->t_line].l_write)(tp, uio)); ! 156: } ! 157: ! 158: /* ! 159: * Got a console receive interrupt - ! 160: * the console processor wants to give us a character. ! 161: * Catch the character, and see who it goes to. ! 162: */ ! 163: cnrint(dev) ! 164: dev_t dev; ! 165: { ! 166: register int unit, timo; ! 167: register struct tty *tp; ! 168: int c; ! 169: ! 170: unit = minor(dev); ! 171: if (!intenable || consoftc[unit].cs_flags&CSF_POLLING) ! 172: return; ! 173: /* make sure we dont take it from cache */ ! 174: uncache(&consin[unit].cpi_buf[0]); ! 175: c = consin[unit].cpi_buf[0]; ! 176: waitforlast(timo); ! 177: /* This resets status bits */ ! 178: consin[unit].cp_hdr.cp_unit = unit; ! 179: /* Ready for new character */ ! 180: mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)&consin[unit])); ! 181: cnlast = &consin[unit].cp_hdr; ! 182: ! 183: tp = cntty[unit]; ! 184: #ifdef KADB ! 185: if (unit == CPCONS && kdbrintr(c, tp)) ! 186: return; ! 187: #endif ! 188: (*linesw[tp->t_line].l_rint)(c, tp); ! 189: } ! 190: ! 191: cnioctl(dev, cmd, addr, flag) ! 192: dev_t dev; ! 193: caddr_t addr; ! 194: { ! 195: register struct tty *tp = cntty[minor(dev)]; ! 196: register error; ! 197: ! 198: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); ! 199: if (error >= 0) ! 200: return error; ! 201: if ((error = ttioctl(tp, cmd, addr, flag)) < 0) ! 202: error = ENOTTY; ! 203: else if (cmd == TIOCSETP || cmd == TIOCSETN) ! 204: cnparams(tp); ! 205: return (error); ! 206: } ! 207: ! 208: int consintr = 1; ! 209: /* ! 210: * Got a console transmission interrupt - ! 211: * the console processor wants another character. ! 212: */ ! 213: cnxint(dev) ! 214: dev_t dev; ! 215: { ! 216: register struct tty *tp; ! 217: register int unit; ! 218: ! 219: if (!intenable || !consintr) ! 220: return; ! 221: unit = minor(dev); ! 222: #ifdef CPPERF ! 223: scope_in(unit == CPCONS ? 1 : 2); ! 224: #endif ! 225: tp = cntty[unit]; ! 226: tp->t_state &= ~TS_BUSY; ! 227: consoftc[unit].cs_timo = 0; ! 228: if (tp->t_line) ! 229: (*linesw[tp->t_line].l_start)(tp); ! 230: else ! 231: cnstart(tp); ! 232: } ! 233: ! 234: cnstart(tp) ! 235: register struct tty *tp; ! 236: { ! 237: register c, s; ! 238: ! 239: #ifdef CPPERF ! 240: scope_in(minor(tp->t_dev) == CPCONS ? 3 : 4); ! 241: #endif ! 242: s = spl8(); ! 243: if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) ! 244: goto out; ! 245: if (tp->t_outq.c_cc <= TTLOWAT(tp)) { ! 246: if (tp->t_state&TS_ASLEEP) { ! 247: tp->t_state &= ~TS_ASLEEP; ! 248: wakeup((caddr_t)&tp->t_outq); ! 249: } ! 250: if (tp->t_wsel) { ! 251: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); ! 252: tp->t_wsel = 0; ! 253: tp->t_state &= ~TS_WCOLL; ! 254: } ! 255: } ! 256: if (tp->t_outq.c_cc == 0) ! 257: goto out; ! 258: c = getc(&tp->t_outq) & 0xff; ! 259: if ((tp->t_flags & (RAW|LITOUT)) == 0) { ! 260: if (c <= 0177) ! 261: c |= partab[c] & 0200; ! 262: else { ! 263: timeout(ttrstrt, (caddr_t)tp, (c&0177)); ! 264: tp->t_state |= TS_TIMEOUT; ! 265: goto out; ! 266: } ! 267: } ! 268: cnputchar(c, tp); ! 269: tp->t_state |= TS_BUSY; ! 270: out: ! 271: splx(s); ! 272: } ! 273: ! 274: cnputc(c) ! 275: char c; ! 276: { ! 277: ! 278: if (c == '\n') ! 279: cnputchar('\r', (struct tty *)0); ! 280: cnputchar(c, (struct tty *)0); ! 281: } ! 282: ! 283: /* ! 284: * Print a character on console. ! 285: */ ! 286: cnputchar(c, tp) ! 287: char c; ! 288: register struct tty *tp; ! 289: { ! 290: register timo; ! 291: register struct cpdcb_o *current; ! 292: register struct consoftc *cs; ! 293: int unit; ! 294: ! 295: /* tp == 0 only in system error messages */ ! 296: if (tp == 0) { ! 297: tp = &cons; ! 298: tp->t_dev = CPCONS; /* may not be open */ ! 299: c |= partab[c&0177]&0200; ! 300: } ! 301: unit = minor(tp->t_dev); ! 302: current = &consout[unit]; ! 303: timo = 30000; ! 304: /* ! 305: * Try waiting for the console tty to finish previous command ! 306: * on this unit, otherwise give up after a reasonable time. ! 307: */ ! 308: do ! 309: uncache(¤t->cp_hdr.cp_unit); ! 310: while ((current->cp_hdr.cp_unit&CPDONE) == 0 && --timo); ! 311: ! 312: current->cp_hdr.cp_comm = CPWRITE; ! 313: current->cp_hdr.cp_count = 1; ! 314: current->cp_buf[0] = c; ! 315: /* ! 316: * Try waiting for the console tty ! 317: * to accept previous command. ! 318: */ ! 319: waitforlast(timo); ! 320: ! 321: /* Reset done bit */ ! 322: current->cp_hdr.cp_unit = (char)unit; ! 323: #ifdef CPPERF ! 324: if (intenable != 0) ! 325: scope_in(5); ! 326: #endif ! 327: cs = &consoftc[unit]; ! 328: cs->cs_lastc = c; ! 329: cs->cs_timo = CN_TIMO; ! 330: if ((cs->cs_flags&CSF_ACTIVE) == 0 && clk_enable) { ! 331: cs->cs_flags |= CSF_ACTIVE; ! 332: timeout(cnrestart, (caddr_t)tp, CN_TIMERVAL); ! 333: } ! 334: mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current)); ! 335: cnlast = ¤t->cp_hdr; ! 336: } ! 337: ! 338: #if defined(KADB) || defined(GENERIC) ! 339: cngetc() ! 340: { ! 341: register int c, s; ! 342: ! 343: s = spl8(); /* block cnrint while we poll */ ! 344: c = cngetchar(&cons); ! 345: if (c == '\r') ! 346: c = '\n'; ! 347: splx(s); ! 348: return (c); ! 349: } ! 350: ! 351: cngetchar(tp) ! 352: register struct tty *tp; ! 353: { ! 354: register timo, unit; ! 355: register struct cpdcb_i *current; ! 356: char c; ! 357: ! 358: unit = minor(tp->t_dev); ! 359: current = &consin[unit]; ! 360: waitforlast(timo); ! 361: current->cp_hdr.cp_unit = unit; /* Resets done bit */ ! 362: current->cp_hdr.cp_comm = CPREAD; ! 363: current->cp_hdr.cp_count = 1; ! 364: mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current)); ! 365: while ((current->cp_hdr.cp_unit&CPDONE) == 0) ! 366: uncache(¤t->cp_hdr.cp_unit); ! 367: uncache(¤t->cpi_buf[0]); ! 368: c = current->cpi_buf[0] & 0x7f; ! 369: cnlast = ¤t->cp_hdr; ! 370: return (c); ! 371: } ! 372: #endif ! 373: ! 374: /* ! 375: * Restart (if necessary) transfer to CP line. ! 376: * This way, lost transmit interrupts don't wedge output. ! 377: */ ! 378: cnrestart(tp) ! 379: struct tty *tp; ! 380: { ! 381: register struct consoftc *cs; ! 382: ! 383: cs = &consoftc[minor(tp->t_dev)]; ! 384: cs->cs_flags &= ~CSF_ACTIVE; ! 385: if (cs->cs_timo) { ! 386: if (--cs->cs_timo == 0) { ! 387: cs->cs_wedgecnt++; ! 388: cnreset(tp); ! 389: cnputchar(cs->cs_lastc, tp); ! 390: } else { ! 391: cs->cs_flags |= CSF_ACTIVE; ! 392: timeout(cnrestart, (caddr_t)tp, CN_TIMERVAL); ! 393: } ! 394: } ! 395: } ! 396: ! 397: /* ! 398: * Reset console. ! 399: */ ! 400: cnreset(tp) ! 401: register struct tty *tp; ! 402: { ! 403: register timo; ! 404: register struct cpdcb_o *current; ! 405: register unit; ! 406: static int failed; ! 407: ! 408: unit = minor(tp->t_dev); ! 409: current = &consout[unit]; ! 410: current->cp_hdr.cp_comm = CPRESET; ! 411: current->cp_hdr.cp_count = 0; ! 412: current->cp_hdr.cp_unit = unit; ! 413: mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current)); ! 414: cnlast = ¤t->cp_hdr; ! 415: timo = 10000; ! 416: do ! 417: uncache(¤t->cp_hdr.cp_unit); ! 418: while ((current->cp_hdr.cp_unit&CPTAKE) == 0 && --timo); ! 419: if (current->cp_hdr.cp_unit & CPTAKE) { ! 420: cnparams(tp); ! 421: failed = 0; ! 422: } else if (failed++ == 0) ! 423: log(LOG_ERR, "Console wedged, reset failed.\n"); ! 424: } ! 425: ! 426: /* ! 427: * Set line parameters ! 428: */ ! 429: cnparams(tp) ! 430: register struct tty *tp; ! 431: { ! 432: register timo; ! 433: register struct cpdcb_o *current; ! 434: int unit; ! 435: ! 436: unit = minor(tp->t_dev); ! 437: current = &consout[unit]; ! 438: timo = 30000; ! 439: /* ! 440: * Try waiting for the console tty to finish any output, ! 441: * otherwise give up after a reasonable time. ! 442: */ ! 443: do ! 444: uncache(¤t->cp_hdr.cp_unit); ! 445: while ((current->cp_hdr.cp_unit&CPDONE) == 0 && --timo); ! 446: current->cp_hdr.cp_comm = CPSTTY; ! 447: current->cp_hdr.cp_count = 4; ! 448: current->cp_buf[0] = tp->t_ispeed; ! 449: /* the rest are defaults */ ! 450: current->cp_buf[1] = 0; /* no parity */ ! 451: current->cp_buf[2] = 0; /* stop bits */ ! 452: current->cp_buf[3] = 8; /* data bits */ ! 453: /* Reset done bit */ ! 454: current->cp_hdr.cp_unit = unit; ! 455: ! 456: waitforlast(timo); ! 457: mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current)); ! 458: cnlast = ¤t->cp_hdr; ! 459: ! 460: cnpostread(unit); ! 461: } ! 462: ! 463: #ifdef KADB ! 464: /* ! 465: * Turn input polling on/off (used by debugger). ! 466: */ ! 467: cnpoll(onoff) ! 468: int onoff; ! 469: { ! 470: ! 471: if (!onoff) { ! 472: consoftc[CPCONS].cs_flags &= ~CSF_POLLING; ! 473: cnpostread(CPCONS); /* restart input */ ! 474: } else ! 475: consoftc[CPCONS].cs_flags |= CSF_POLLING; ! 476: } ! 477: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.