|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 University of Utah. ! 3: * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Systems Programming Group of the University of Utah Computer ! 8: * Science Department. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: * from: $Hdr: dcm.c 1.26 91/01/21$ ! 39: * ! 40: * @(#)dcm.c 7.14 (Berkeley) 6/27/91 ! 41: */ ! 42: ! 43: /* ! 44: * TODO: ! 45: * Timeouts ! 46: * Test console support. ! 47: */ ! 48: ! 49: #include "dcm.h" ! 50: #if NDCM > 0 ! 51: /* ! 52: * 98642/MUX ! 53: */ ! 54: #include "sys/param.h" ! 55: #include "sys/systm.h" ! 56: #include "sys/ioctl.h" ! 57: #include "sys/tty.h" ! 58: #include "sys/proc.h" ! 59: #include "sys/conf.h" ! 60: #include "sys/file.h" ! 61: #include "sys/uio.h" ! 62: #include "sys/kernel.h" ! 63: #include "sys/syslog.h" ! 64: #include "sys/time.h" ! 65: ! 66: #include "device.h" ! 67: #include "dcmreg.h" ! 68: #include "machine/cpu.h" ! 69: #include "../hp300/isr.h" ! 70: ! 71: #ifndef DEFAULT_BAUD_RATE ! 72: #define DEFAULT_BAUD_RATE 9600 ! 73: #endif ! 74: ! 75: int ttrstrt(); ! 76: int dcmprobe(), dcmstart(), dcmintr(), dcmparam(); ! 77: ! 78: struct driver dcmdriver = { ! 79: dcmprobe, "dcm", ! 80: }; ! 81: ! 82: #define NDCMLINE (NDCM*4) ! 83: ! 84: struct tty dcm_tty[NDCMLINE]; ! 85: struct modemreg *dcm_modem[NDCMLINE]; ! 86: char mcndlast[NDCMLINE]; /* XXX last modem status for line */ ! 87: int ndcm = NDCMLINE; ! 88: ! 89: int dcm_active; ! 90: int dcmsoftCAR[NDCM]; ! 91: struct dcmdevice *dcm_addr[NDCM]; ! 92: struct isr dcmisr[NDCM]; ! 93: ! 94: struct speedtab dcmspeedtab[] = { ! 95: 0, BR_0, ! 96: 50, BR_50, ! 97: 75, BR_75, ! 98: 110, BR_110, ! 99: 134, BR_134, ! 100: 150, BR_150, ! 101: 300, BR_300, ! 102: 600, BR_600, ! 103: 1200, BR_1200, ! 104: 1800, BR_1800, ! 105: 2400, BR_2400, ! 106: 4800, BR_4800, ! 107: 9600, BR_9600, ! 108: 19200, BR_19200, ! 109: 38400, BR_38400, ! 110: -1, -1 ! 111: }; ! 112: ! 113: /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */ ! 114: #define DCM_USPERCH(s) (10000000 / (s)) ! 115: ! 116: /* ! 117: * Per board interrupt scheme. 16.7ms is the polling interrupt rate ! 118: * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms). ! 119: */ ! 120: #define DIS_TIMER 0 ! 121: #define DIS_PERCHAR 1 ! 122: #define DIS_RESET 2 ! 123: ! 124: int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */ ! 125: int dcminterval = 5; /* interval (secs) between checks */ ! 126: struct dcmischeme { ! 127: int dis_perchar; /* non-zero if interrupting per char */ ! 128: long dis_time; /* last time examined */ ! 129: int dis_intr; /* recv interrupts during last interval */ ! 130: int dis_char; /* characters read during last interval */ ! 131: } dcmischeme[NDCM]; ! 132: ! 133: /* ! 134: * Console support ! 135: */ ! 136: #ifdef DCMCONSOLE ! 137: int dcmconsole = DCMCONSOLE; ! 138: #else ! 139: int dcmconsole = -1; ! 140: #endif ! 141: int dcmconsinit; ! 142: int dcmdefaultrate = DEFAULT_BAUD_RATE; ! 143: int dcmconbrdbusy = 0; ! 144: int dcmmajor; ! 145: extern struct tty *constty; ! 146: ! 147: #ifdef KGDB ! 148: /* ! 149: * Kernel GDB support ! 150: */ ! 151: #include "machine/remote-sl.h" ! 152: ! 153: extern dev_t kgdb_dev; ! 154: extern int kgdb_rate; ! 155: extern int kgdb_debug_init; ! 156: #endif ! 157: ! 158: /* #define IOSTATS */ ! 159: ! 160: #ifdef DEBUG ! 161: int dcmdebug = 0x0; ! 162: #define DDB_SIOERR 0x01 ! 163: #define DDB_PARAM 0x02 ! 164: #define DDB_INPUT 0x04 ! 165: #define DDB_OUTPUT 0x08 ! 166: #define DDB_INTR 0x10 ! 167: #define DDB_IOCTL 0x20 ! 168: #define DDB_INTSCHM 0x40 ! 169: #define DDB_MODEM 0x80 ! 170: #define DDB_OPENCLOSE 0x100 ! 171: #endif ! 172: ! 173: #ifdef IOSTATS ! 174: #define DCMRBSIZE 94 ! 175: #define DCMXBSIZE 24 ! 176: ! 177: struct dcmstats { ! 178: long xints; /* # of xmit ints */ ! 179: long xchars; /* # of xmit chars */ ! 180: long xempty; /* times outq is empty in dcmstart */ ! 181: long xrestarts; /* times completed while xmitting */ ! 182: long rints; /* # of recv ints */ ! 183: long rchars; /* # of recv chars */ ! 184: long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */ ! 185: long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */ ! 186: } dcmstats[NDCM]; ! 187: #endif ! 188: ! 189: #define UNIT(x) minor(x) ! 190: #define BOARD(x) (((x) >> 2) & 0x3f) ! 191: #define PORT(x) ((x) & 3) ! 192: #define MKUNIT(b,p) (((b) << 2) | (p)) ! 193: ! 194: /* ! 195: * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux, ! 196: * the distribution panel uses "HP DCE" conventions. If requested via ! 197: * the device flags, we swap the inputs to something closer to normal DCE, ! 198: * allowing a straight-through cable to a DTE or a reversed cable ! 199: * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected; ! 200: * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect ! 201: * DSR or make RTS work, though). The following gives the full ! 202: * details of a cable from this mux panel to a modem: ! 203: * ! 204: * HP modem ! 205: * name pin pin name ! 206: * HP inputs: ! 207: * "Rx" 2 3 Tx ! 208: * CTS 4 5 CTS (only needed for CCTS_OFLOW) ! 209: * DCD 20 8 DCD ! 210: * "DSR" 9 6 DSR (unneeded) ! 211: * RI 22 22 RI (unneeded) ! 212: * ! 213: * HP outputs: ! 214: * "Tx" 3 2 Rx ! 215: * "DTR" 6 not connected ! 216: * "RTS" 8 20 DTR ! 217: * "SR" 23 4 RTS (often not needed) ! 218: */ ! 219: #define FLAG_STDDCE 0x10 /* map inputs if this bit is set in flags */ ! 220: #define hp2dce_in(ibits) (iconv[(ibits) & 0xf]) ! 221: static char iconv[16] = { ! 222: 0, MI_DM, MI_CTS, MI_CTS|MI_DM, ! 223: MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM, ! 224: MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM, ! 225: MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS, ! 226: MI_RI|MI_CD|MI_CTS|MI_DM ! 227: }; ! 228: ! 229: dcmprobe(hd) ! 230: register struct hp_device *hd; ! 231: { ! 232: register struct dcmdevice *dcm; ! 233: register int i; ! 234: register int timo = 0; ! 235: int s, brd, isconsole, mbits; ! 236: ! 237: dcm = (struct dcmdevice *)hd->hp_addr; ! 238: if ((dcm->dcm_rsid & 0x1f) != DCMID) ! 239: return (0); ! 240: brd = hd->hp_unit; ! 241: isconsole = (brd == BOARD(dcmconsole)); ! 242: /* ! 243: * XXX selected console device (CONSUNIT) as determined by ! 244: * dcmcnprobe does not agree with logical numbering imposed ! 245: * by the config file (i.e. lowest address DCM is not unit ! 246: * CONSUNIT). Don't recognize this card. ! 247: */ ! 248: if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)]) ! 249: return (0); ! 250: ! 251: /* ! 252: * Empirically derived self-test magic ! 253: */ ! 254: s = spltty(); ! 255: dcm->dcm_rsid = DCMRS; ! 256: DELAY(50000); /* 5000 is not long enough */ ! 257: dcm->dcm_rsid = 0; ! 258: dcm->dcm_ic = IC_IE; ! 259: dcm->dcm_cr = CR_SELFT; ! 260: while ((dcm->dcm_ic & IC_IR) == 0) ! 261: if (++timo == 20000) ! 262: return (0); ! 263: DELAY(50000) /* XXX why is this needed ???? */ ! 264: while ((dcm->dcm_iir & IIR_SELFT) == 0) ! 265: if (++timo == 400000) ! 266: return (0); ! 267: DELAY(50000) /* XXX why is this needed ???? */ ! 268: if (dcm->dcm_stcon != ST_OK) { ! 269: if (!isconsole) ! 270: printf("dcm%d: self test failed: %x\n", ! 271: brd, dcm->dcm_stcon); ! 272: return (0); ! 273: } ! 274: dcm->dcm_ic = IC_ID; ! 275: splx(s); ! 276: ! 277: hd->hp_ipl = DCMIPL(dcm->dcm_ic); ! 278: dcm_addr[brd] = dcm; ! 279: dcm_active |= 1 << brd; ! 280: dcmsoftCAR[brd] = hd->hp_flags; ! 281: dcmisr[brd].isr_ipl = hd->hp_ipl; ! 282: dcmisr[brd].isr_arg = brd; ! 283: dcmisr[brd].isr_intr = dcmintr; ! 284: isrlink(&dcmisr[brd]); ! 285: #ifdef KGDB ! 286: if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == brd) { ! 287: if (dcmconsole == UNIT(kgdb_dev)) ! 288: kgdb_dev = NODEV; /* can't debug over console port */ ! 289: #ifndef KGDB_CHEAT ! 290: /* ! 291: * The following could potentially be replaced ! 292: * by the corresponding code in dcmcnprobe. ! 293: */ ! 294: else { ! 295: (void) dcminit(kgdb_dev, kgdb_rate); ! 296: if (kgdb_debug_init) { ! 297: printf("dcm%d: ", UNIT(kgdb_dev)); ! 298: kgdb_connect(1); ! 299: } else ! 300: printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev)); ! 301: } ! 302: /* end could be replaced */ ! 303: #endif ! 304: } ! 305: #endif ! 306: if (dcmistype == DIS_TIMER) ! 307: dcmsetischeme(brd, DIS_RESET|DIS_TIMER); ! 308: else ! 309: dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR); ! 310: ! 311: /* load pointers to modem control */ ! 312: dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0; ! 313: dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1; ! 314: dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2; ! 315: dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3; ! 316: /* set DCD (modem) and CTS (flow control) on all ports */ ! 317: if (dcmsoftCAR[brd] & FLAG_STDDCE) ! 318: mbits = hp2dce_in(MI_CD|MI_CTS); ! 319: else ! 320: mbits = MI_CD|MI_CTS; ! 321: for (i = 0; i < 4; i++) ! 322: dcm_modem[MKUNIT(brd, i)]->mdmmsk = mbits; ! 323: ! 324: dcm->dcm_ic = IC_IE; /* turn all interrupts on */ ! 325: /* ! 326: * Need to reset baud rate, etc. of next print so reset dcmconsole. ! 327: * Also make sure console is always "hardwired" ! 328: */ ! 329: if (isconsole) { ! 330: dcmconsinit = 0; ! 331: dcmsoftCAR[brd] |= (1 << PORT(dcmconsole)); ! 332: } ! 333: return (1); ! 334: } ! 335: ! 336: /* ARGSUSED */ ! 337: #ifdef __STDC__ ! 338: dcmopen(dev_t dev, int flag, int mode, struct proc *p) ! 339: #else ! 340: dcmopen(dev, flag, mode, p) ! 341: dev_t dev; ! 342: int flag, mode; ! 343: struct proc *p; ! 344: #endif ! 345: { ! 346: register struct tty *tp; ! 347: register int unit, brd; ! 348: int error = 0, mbits; ! 349: ! 350: unit = UNIT(dev); ! 351: brd = BOARD(unit); ! 352: if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0) ! 353: return (ENXIO); ! 354: tp = &dcm_tty[unit]; ! 355: tp->t_oproc = dcmstart; ! 356: tp->t_param = dcmparam; ! 357: tp->t_dev = dev; ! 358: if ((tp->t_state & TS_ISOPEN) == 0) { ! 359: tp->t_state |= TS_WOPEN; ! 360: ttychars(tp); ! 361: if (tp->t_ispeed == 0) { ! 362: tp->t_iflag = TTYDEF_IFLAG; ! 363: tp->t_oflag = TTYDEF_OFLAG; ! 364: tp->t_cflag = TTYDEF_CFLAG; ! 365: tp->t_lflag = TTYDEF_LFLAG; ! 366: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; ! 367: } ! 368: (void) dcmparam(tp, &tp->t_termios); ! 369: ttsetwater(tp); ! 370: } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) ! 371: return (EBUSY); ! 372: mbits = MO_ON; ! 373: if (dcmsoftCAR[brd] & FLAG_STDDCE) ! 374: mbits |= MO_SR; /* pin 23, could be used as RTS */ ! 375: (void) dcmmctl(dev, mbits, DMSET); /* enable port */ ! 376: if ((dcmsoftCAR[brd] & (1 << PORT(unit))) || ! 377: (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)) ! 378: tp->t_state |= TS_CARR_ON; ! 379: #ifdef DEBUG ! 380: if (dcmdebug & DDB_MODEM) ! 381: printf("dcm%d: dcmopen port %d softcarr %c\n", ! 382: brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0'); ! 383: #endif ! 384: (void) spltty(); ! 385: while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && ! 386: (tp->t_state & TS_CARR_ON) == 0) { ! 387: tp->t_state |= TS_WOPEN; ! 388: if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ! 389: ttopen, 0)) ! 390: break; ! 391: } ! 392: (void) spl0(); ! 393: ! 394: #ifdef DEBUG ! 395: if (dcmdebug & DDB_OPENCLOSE) ! 396: printf("dcmopen: u %x st %x fl %x\n", ! 397: unit, tp->t_state, tp->t_flags); ! 398: #endif ! 399: if (error == 0) ! 400: error = (*linesw[tp->t_line].l_open)(dev, tp); ! 401: return (error); ! 402: } ! 403: ! 404: /*ARGSUSED*/ ! 405: dcmclose(dev, flag, mode, p) ! 406: dev_t dev; ! 407: int flag, mode; ! 408: struct proc *p; ! 409: { ! 410: register struct tty *tp; ! 411: int unit; ! 412: ! 413: unit = UNIT(dev); ! 414: tp = &dcm_tty[unit]; ! 415: (*linesw[tp->t_line].l_close)(tp, flag); ! 416: if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || ! 417: (tp->t_state&TS_ISOPEN) == 0) ! 418: (void) dcmmctl(dev, MO_OFF, DMSET); ! 419: #ifdef DEBUG ! 420: if (dcmdebug & DDB_OPENCLOSE) ! 421: printf("dcmclose: u %x st %x fl %x\n", ! 422: unit, tp->t_state, tp->t_flags); ! 423: #endif ! 424: ttyclose(tp); ! 425: return (0); ! 426: } ! 427: ! 428: dcmread(dev, uio, flag) ! 429: dev_t dev; ! 430: struct uio *uio; ! 431: { ! 432: register struct tty *tp; ! 433: ! 434: tp = &dcm_tty[UNIT(dev)]; ! 435: return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); ! 436: } ! 437: ! 438: dcmwrite(dev, uio, flag) ! 439: dev_t dev; ! 440: struct uio *uio; ! 441: { ! 442: int unit = UNIT(dev); ! 443: register struct tty *tp; ! 444: ! 445: tp = &dcm_tty[unit]; ! 446: /* ! 447: * XXX we disallow virtual consoles if the physical console is ! 448: * a serial port. This is in case there is a display attached that ! 449: * is not the console. In that situation we don't need/want the X ! 450: * server taking over the console. ! 451: */ ! 452: if (constty && unit == dcmconsole) ! 453: constty = NULL; ! 454: return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); ! 455: } ! 456: ! 457: dcmintr(brd) ! 458: register int brd; ! 459: { ! 460: register struct dcmdevice *dcm = dcm_addr[brd]; ! 461: register struct dcmischeme *dis; ! 462: register int unit = MKUNIT(brd, 0); ! 463: register int code, i; ! 464: int pcnd[4], mcode, mcnd[4]; ! 465: ! 466: /* ! 467: * Do all guarded register accesses right off to minimize ! 468: * block out of hardware. ! 469: */ ! 470: SEM_LOCK(dcm); ! 471: if ((dcm->dcm_ic & IC_IR) == 0) { ! 472: SEM_UNLOCK(dcm); ! 473: return (0); ! 474: } ! 475: for (i = 0; i < 4; i++) { ! 476: pcnd[i] = dcm->dcm_icrtab[i].dcm_data; ! 477: dcm->dcm_icrtab[i].dcm_data = 0; ! 478: code = dcm_modem[unit+i]->mdmin; ! 479: if (dcmsoftCAR[brd] & FLAG_STDDCE) ! 480: code = hp2dce_in(code); ! 481: mcnd[i] = code; ! 482: } ! 483: code = dcm->dcm_iir & IIR_MASK; ! 484: dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */ ! 485: mcode = dcm->dcm_modemintr; ! 486: dcm->dcm_modemintr = 0; ! 487: SEM_UNLOCK(dcm); ! 488: ! 489: #ifdef DEBUG ! 490: if (dcmdebug & DDB_INTR) { ! 491: printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ", ! 492: brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]); ! 493: printf("miir %x mc %x/%x/%x/%x\n", ! 494: mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]); ! 495: } ! 496: #endif ! 497: if (code & IIR_TIMEO) ! 498: dcmrint(brd, dcm); ! 499: if (code & IIR_PORT0) ! 500: dcmpint(unit+0, pcnd[0], dcm); ! 501: if (code & IIR_PORT1) ! 502: dcmpint(unit+1, pcnd[1], dcm); ! 503: if (code & IIR_PORT2) ! 504: dcmpint(unit+2, pcnd[2], dcm); ! 505: if (code & IIR_PORT3) ! 506: dcmpint(unit+3, pcnd[3], dcm); ! 507: if (code & IIR_MODM) { ! 508: if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */ ! 509: dcmmint(unit+0, mcnd[0], dcm); ! 510: if (mcode & 0x2) ! 511: dcmmint(unit+1, mcnd[1], dcm); ! 512: if (mcode & 0x4) ! 513: dcmmint(unit+2, mcnd[2], dcm); ! 514: if (mcode & 0x8) ! 515: dcmmint(unit+3, mcnd[3], dcm); ! 516: } ! 517: ! 518: dis = &dcmischeme[brd]; ! 519: /* ! 520: * Chalk up a receiver interrupt if the timer running or one of ! 521: * the ports reports a special character interrupt. ! 522: */ ! 523: if ((code & IIR_TIMEO) || ! 524: ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC)) ! 525: dis->dis_intr++; ! 526: /* ! 527: * See if it is time to check/change the interrupt rate. ! 528: */ ! 529: if (dcmistype < 0 && ! 530: (i = time.tv_sec - dis->dis_time) >= dcminterval) { ! 531: /* ! 532: * If currently per-character and averaged over 70 interrupts ! 533: * per-second (66 is threshold of 600 baud) in last interval, ! 534: * switch to timer mode. ! 535: * ! 536: * XXX decay counts ala load average to avoid spikes? ! 537: */ ! 538: if (dis->dis_perchar && dis->dis_intr > 70 * i) ! 539: dcmsetischeme(brd, DIS_TIMER); ! 540: /* ! 541: * If currently using timer and had more interrupts than ! 542: * received characters in the last interval, switch back ! 543: * to per-character. Note that after changing to per-char ! 544: * we must process any characters already in the queue ! 545: * since they may have arrived before the bitmap was setup. ! 546: * ! 547: * XXX decay counts? ! 548: */ ! 549: else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) { ! 550: dcmsetischeme(brd, DIS_PERCHAR); ! 551: dcmrint(brd, dcm); ! 552: } ! 553: dis->dis_intr = dis->dis_char = 0; ! 554: dis->dis_time = time.tv_sec; ! 555: } ! 556: return (1); ! 557: } ! 558: ! 559: /* ! 560: * Port interrupt. Can be two things: ! 561: * First, it might be a special character (exception interrupt); ! 562: * Second, it may be a buffer empty (transmit interrupt); ! 563: */ ! 564: dcmpint(unit, code, dcm) ! 565: int unit, code; ! 566: struct dcmdevice *dcm; ! 567: { ! 568: struct tty *tp = &dcm_tty[unit]; ! 569: ! 570: if (code & IT_SPEC) ! 571: dcmreadbuf(unit, dcm, tp); ! 572: if (code & IT_TX) ! 573: dcmxint(unit, dcm, tp); ! 574: } ! 575: ! 576: dcmrint(brd, dcm) ! 577: int brd; ! 578: register struct dcmdevice *dcm; ! 579: { ! 580: register int i, unit; ! 581: register struct tty *tp; ! 582: ! 583: unit = MKUNIT(brd, 0); ! 584: tp = &dcm_tty[unit]; ! 585: for (i = 0; i < 4; i++, tp++, unit++) ! 586: dcmreadbuf(unit, dcm, tp); ! 587: } ! 588: ! 589: dcmreadbuf(unit, dcm, tp) ! 590: int unit; ! 591: register struct dcmdevice *dcm; ! 592: register struct tty *tp; ! 593: { ! 594: int port = PORT(unit); ! 595: register struct dcmpreg *pp = dcm_preg(dcm, port); ! 596: register struct dcmrfifo *fifo; ! 597: register int c, stat; ! 598: register unsigned head; ! 599: int nch = 0; ! 600: #ifdef IOSTATS ! 601: struct dcmstats *dsp = &dcmstats[BOARD(unit)]; ! 602: ! 603: dsp->rints++; ! 604: #endif ! 605: if ((tp->t_state & TS_ISOPEN) == 0) { ! 606: #ifdef KGDB ! 607: if ((makedev(dcmmajor, unit) == kgdb_dev) && ! 608: (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) && ! 609: dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_END) { ! 610: pp->r_head = (head + 2) & RX_MASK; ! 611: kgdb_connect(0); /* trap into kgdb */ ! 612: return; ! 613: } ! 614: #endif /* KGDB */ ! 615: pp->r_head = pp->r_tail & RX_MASK; ! 616: return; ! 617: } ! 618: ! 619: head = pp->r_head & RX_MASK; ! 620: fifo = &dcm->dcm_rfifos[3-port][head>>1]; ! 621: /* ! 622: * XXX upper bound on how many chars we will take in one swallow? ! 623: */ ! 624: while (head != (pp->r_tail & RX_MASK)) { ! 625: /* ! 626: * Get character/status and update head pointer as fast ! 627: * as possible to make room for more characters. ! 628: */ ! 629: c = fifo->data_char; ! 630: stat = fifo->data_stat; ! 631: head = (head + 2) & RX_MASK; ! 632: pp->r_head = head; ! 633: fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0]; ! 634: nch++; ! 635: ! 636: #ifdef DEBUG ! 637: if (dcmdebug & DDB_INPUT) ! 638: printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n", ! 639: unit, c&0xFF, c, stat&0xFF, ! 640: tp->t_flags, head, pp->r_tail); ! 641: #endif ! 642: /* ! 643: * Check for and handle errors ! 644: */ ! 645: if (stat & RD_MASK) { ! 646: #ifdef DEBUG ! 647: if (dcmdebug & (DDB_INPUT|DDB_SIOERR)) ! 648: printf("dcmreadbuf(%d): err: c%x('%c') s%x\n", ! 649: unit, stat, c&0xFF, c); ! 650: #endif ! 651: if (stat & (RD_BD | RD_FE)) ! 652: c |= TTY_FE; ! 653: else if (stat & RD_PE) ! 654: c |= TTY_PE; ! 655: else if (stat & RD_OVF) ! 656: log(LOG_WARNING, ! 657: "dcm%d: silo overflow\n", unit); ! 658: else if (stat & RD_OE) ! 659: log(LOG_WARNING, ! 660: "dcm%d: uart overflow\n", unit); ! 661: } ! 662: (*linesw[tp->t_line].l_rint)(c, tp); ! 663: } ! 664: dcmischeme[BOARD(unit)].dis_char += nch; ! 665: #ifdef IOSTATS ! 666: dsp->rchars += nch; ! 667: if (nch <= DCMRBSIZE) ! 668: dsp->rsilo[nch]++; ! 669: else ! 670: dsp->rsilo[DCMRBSIZE+1]++; ! 671: #endif ! 672: } ! 673: ! 674: dcmxint(unit, dcm, tp) ! 675: int unit; ! 676: struct dcmdevice *dcm; ! 677: register struct tty *tp; ! 678: { ! 679: tp->t_state &= ~TS_BUSY; ! 680: if (tp->t_state & TS_FLUSH) ! 681: tp->t_state &= ~TS_FLUSH; ! 682: (*linesw[tp->t_line].l_start)(tp); ! 683: } ! 684: ! 685: dcmmint(unit, mcnd, dcm) ! 686: register int unit; ! 687: register struct dcmdevice *dcm; ! 688: int mcnd; ! 689: { ! 690: register struct tty *tp; ! 691: int delta; ! 692: ! 693: #ifdef DEBUG ! 694: if (dcmdebug & DDB_MODEM) ! 695: printf("dcmmint: port %d mcnd %x mcndlast %x\n", ! 696: unit, mcnd, mcndlast[unit]); ! 697: #endif ! 698: tp = &dcm_tty[unit]; ! 699: delta = mcnd ^ mcndlast[unit]; ! 700: mcndlast[unit] = mcnd; ! 701: if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) && ! 702: (tp->t_flags & CCTS_OFLOW)) { ! 703: if (mcnd & MI_CTS) { ! 704: tp->t_state &= ~TS_TTSTOP; ! 705: ttstart(tp); ! 706: } else ! 707: tp->t_state |= TS_TTSTOP; /* inline dcmstop */ ! 708: } ! 709: if (delta & MI_CD) { ! 710: if (mcnd & MI_CD) ! 711: (void)(*linesw[tp->t_line].l_modem)(tp, 1); ! 712: else if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0 && ! 713: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { ! 714: dcm_modem[unit]->mdmout = MO_OFF; ! 715: SEM_LOCK(dcm); ! 716: dcm->dcm_modemchng |= 1<<(unit & 3); ! 717: dcm->dcm_cr |= CR_MODM; ! 718: SEM_UNLOCK(dcm); ! 719: DELAY(10); /* time to change lines */ ! 720: } ! 721: } ! 722: } ! 723: ! 724: dcmioctl(dev, cmd, data, flag) ! 725: dev_t dev; ! 726: caddr_t data; ! 727: { ! 728: register struct tty *tp; ! 729: register int unit = UNIT(dev); ! 730: register struct dcmdevice *dcm; ! 731: register int port; ! 732: int error, s; ! 733: ! 734: #ifdef DEBUG ! 735: if (dcmdebug & DDB_IOCTL) ! 736: printf("dcmioctl: unit %d cmd %x data %x flag %x\n", ! 737: unit, cmd, *data, flag); ! 738: #endif ! 739: tp = &dcm_tty[unit]; ! 740: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); ! 741: if (error >= 0) ! 742: return (error); ! 743: error = ttioctl(tp, cmd, data, flag); ! 744: if (error >= 0) ! 745: return (error); ! 746: ! 747: port = PORT(unit); ! 748: dcm = dcm_addr[BOARD(unit)]; ! 749: switch (cmd) { ! 750: case TIOCSBRK: ! 751: /* ! 752: * Wait for transmitter buffer to empty ! 753: */ ! 754: s = spltty(); ! 755: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) ! 756: DELAY(DCM_USPERCH(tp->t_ospeed)); ! 757: SEM_LOCK(dcm); ! 758: dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; ! 759: dcm->dcm_cr |= (1 << port); /* start break */ ! 760: SEM_UNLOCK(dcm); ! 761: splx(s); ! 762: break; ! 763: ! 764: case TIOCCBRK: ! 765: SEM_LOCK(dcm); ! 766: dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; ! 767: dcm->dcm_cr |= (1 << port); /* end break */ ! 768: SEM_UNLOCK(dcm); ! 769: break; ! 770: ! 771: case TIOCSDTR: ! 772: (void) dcmmctl(dev, MO_ON, DMBIS); ! 773: break; ! 774: ! 775: case TIOCCDTR: ! 776: (void) dcmmctl(dev, MO_ON, DMBIC); ! 777: break; ! 778: ! 779: case TIOCMSET: ! 780: (void) dcmmctl(dev, *(int *)data, DMSET); ! 781: break; ! 782: ! 783: case TIOCMBIS: ! 784: (void) dcmmctl(dev, *(int *)data, DMBIS); ! 785: break; ! 786: ! 787: case TIOCMBIC: ! 788: (void) dcmmctl(dev, *(int *)data, DMBIC); ! 789: break; ! 790: ! 791: case TIOCMGET: ! 792: *(int *)data = dcmmctl(dev, 0, DMGET); ! 793: break; ! 794: ! 795: default: ! 796: return (ENOTTY); ! 797: } ! 798: return (0); ! 799: } ! 800: ! 801: dcmparam(tp, t) ! 802: register struct tty *tp; ! 803: register struct termios *t; ! 804: { ! 805: register struct dcmdevice *dcm; ! 806: register int port, mode, cflag = t->c_cflag; ! 807: int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); ! 808: ! 809: /* check requested parameters */ ! 810: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) ! 811: return (EINVAL); ! 812: /* and copy to tty */ ! 813: tp->t_ispeed = t->c_ispeed; ! 814: tp->t_ospeed = t->c_ospeed; ! 815: tp->t_cflag = cflag; ! 816: if (ospeed == 0) { ! 817: (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET); ! 818: return (0); ! 819: } ! 820: ! 821: mode = 0; ! 822: switch (cflag&CSIZE) { ! 823: case CS5: ! 824: mode = LC_5BITS; break; ! 825: case CS6: ! 826: mode = LC_6BITS; break; ! 827: case CS7: ! 828: mode = LC_7BITS; break; ! 829: case CS8: ! 830: mode = LC_8BITS; break; ! 831: } ! 832: if (cflag&PARENB) { ! 833: if (cflag&PARODD) ! 834: mode |= LC_PODD; ! 835: else ! 836: mode |= LC_PEVEN; ! 837: } ! 838: if (cflag&CSTOPB) ! 839: mode |= LC_2STOP; ! 840: else ! 841: mode |= LC_1STOP; ! 842: #ifdef DEBUG ! 843: if (dcmdebug & DDB_PARAM) ! 844: printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n", ! 845: UNIT(tp->t_dev), cflag, mode, tp->t_ospeed, ! 846: DCM_USPERCH(tp->t_ospeed)); ! 847: #endif ! 848: ! 849: port = PORT(tp->t_dev); ! 850: dcm = dcm_addr[BOARD(tp->t_dev)]; ! 851: /* ! 852: * Wait for transmitter buffer to empty. ! 853: */ ! 854: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) ! 855: DELAY(DCM_USPERCH(tp->t_ospeed)); ! 856: /* ! 857: * Make changes known to hardware. ! 858: */ ! 859: dcm->dcm_data[port].dcm_baud = ospeed; ! 860: dcm->dcm_data[port].dcm_conf = mode; ! 861: SEM_LOCK(dcm); ! 862: dcm->dcm_cmdtab[port].dcm_data |= CT_CON; ! 863: dcm->dcm_cr |= (1 << port); ! 864: SEM_UNLOCK(dcm); ! 865: /* ! 866: * Delay for config change to take place. Weighted by baud. ! 867: * XXX why do we do this? ! 868: */ ! 869: DELAY(16 * DCM_USPERCH(tp->t_ospeed)); ! 870: return (0); ! 871: } ! 872: ! 873: dcmstart(tp) ! 874: register struct tty *tp; ! 875: { ! 876: register struct dcmdevice *dcm; ! 877: register struct dcmpreg *pp; ! 878: register struct dcmtfifo *fifo; ! 879: register char *bp; ! 880: register unsigned tail, next; ! 881: register int port, nch; ! 882: unsigned head; ! 883: char buf[16]; ! 884: int s; ! 885: #ifdef IOSTATS ! 886: struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)]; ! 887: int tch = 0; ! 888: #endif ! 889: ! 890: s = spltty(); ! 891: #ifdef IOSTATS ! 892: dsp->xints++; ! 893: #endif ! 894: #ifdef DEBUG ! 895: if (dcmdebug & DDB_OUTPUT) ! 896: printf("dcmstart(%d): state %x flags %x outcc %d\n", ! 897: UNIT(tp->t_dev), tp->t_state, tp->t_flags, ! 898: tp->t_outq.c_cc); ! 899: #endif ! 900: if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) ! 901: goto out; ! 902: if (tp->t_outq.c_cc <= tp->t_lowat) { ! 903: if (tp->t_state&TS_ASLEEP) { ! 904: tp->t_state &= ~TS_ASLEEP; ! 905: wakeup((caddr_t)&tp->t_outq); ! 906: } ! 907: if (tp->t_wsel) { ! 908: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); ! 909: tp->t_wsel = 0; ! 910: tp->t_state &= ~TS_WCOLL; ! 911: } ! 912: } ! 913: if (tp->t_outq.c_cc == 0) { ! 914: #ifdef IOSTATS ! 915: dsp->xempty++; ! 916: #endif ! 917: goto out; ! 918: } ! 919: ! 920: dcm = dcm_addr[BOARD(tp->t_dev)]; ! 921: port = PORT(tp->t_dev); ! 922: pp = dcm_preg(dcm, port); ! 923: tail = pp->t_tail & TX_MASK; ! 924: next = (tail + 1) & TX_MASK; ! 925: head = pp->t_head & TX_MASK; ! 926: if (head == next) ! 927: goto out; ! 928: fifo = &dcm->dcm_tfifos[3-port][tail]; ! 929: again: ! 930: nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK); ! 931: #ifdef IOSTATS ! 932: tch += nch; ! 933: #endif ! 934: #ifdef DEBUG ! 935: if (dcmdebug & DDB_OUTPUT) ! 936: printf("\thead %x tail %x nch %d\n", head, tail, nch); ! 937: #endif ! 938: /* ! 939: * Loop transmitting all the characters we can. ! 940: */ ! 941: for (bp = buf; --nch >= 0; bp++) { ! 942: fifo->data_char = *bp; ! 943: pp->t_tail = next; ! 944: /* ! 945: * If this is the first character, ! 946: * get the hardware moving right now. ! 947: */ ! 948: if (bp == buf) { ! 949: tp->t_state |= TS_BUSY; ! 950: SEM_LOCK(dcm); ! 951: dcm->dcm_cmdtab[port].dcm_data |= CT_TX; ! 952: dcm->dcm_cr |= (1 << port); ! 953: SEM_UNLOCK(dcm); ! 954: } ! 955: tail = next; ! 956: fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0]; ! 957: next = (next + 1) & TX_MASK; ! 958: } ! 959: /* ! 960: * Head changed while we were loading the buffer, ! 961: * go back and load some more if we can. ! 962: */ ! 963: if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) { ! 964: #ifdef IOSTATS ! 965: dsp->xrestarts++; ! 966: #endif ! 967: head = pp->t_head & TX_MASK; ! 968: goto again; ! 969: } ! 970: ! 971: /* ! 972: * Kick it one last time in case it finished while we were ! 973: * loading the last bunch. ! 974: */ ! 975: if (bp > &buf[1]) { ! 976: tp->t_state |= TS_BUSY; ! 977: SEM_LOCK(dcm); ! 978: dcm->dcm_cmdtab[port].dcm_data |= CT_TX; ! 979: dcm->dcm_cr |= (1 << port); ! 980: SEM_UNLOCK(dcm); ! 981: } ! 982: #ifdef DEBUG ! 983: if (dcmdebug & DDB_INTR) ! 984: printf("dcmstart(%d): head %x tail %x outqcc %d\n", ! 985: UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc); ! 986: #endif ! 987: out: ! 988: #ifdef IOSTATS ! 989: dsp->xchars += tch; ! 990: if (tch <= DCMXBSIZE) ! 991: dsp->xsilo[tch]++; ! 992: else ! 993: dsp->xsilo[DCMXBSIZE+1]++; ! 994: #endif ! 995: splx(s); ! 996: } ! 997: ! 998: /* ! 999: * Stop output on a line. ! 1000: */ ! 1001: dcmstop(tp, flag) ! 1002: register struct tty *tp; ! 1003: { ! 1004: int s; ! 1005: ! 1006: s = spltty(); ! 1007: if (tp->t_state & TS_BUSY) { ! 1008: /* XXX is there some way to safely stop transmission? */ ! 1009: if ((tp->t_state&TS_TTSTOP) == 0) ! 1010: tp->t_state |= TS_FLUSH; ! 1011: } ! 1012: splx(s); ! 1013: } ! 1014: ! 1015: /* ! 1016: * Modem control ! 1017: */ ! 1018: dcmmctl(dev, bits, how) ! 1019: dev_t dev; ! 1020: int bits, how; ! 1021: { ! 1022: register struct dcmdevice *dcm; ! 1023: int s, unit, brd, hit = 0; ! 1024: ! 1025: unit = UNIT(dev); ! 1026: #ifdef DEBUG ! 1027: if (dcmdebug & DDB_MODEM) ! 1028: printf("dcmmctl(%d) unit %d bits 0x%x how %x\n", ! 1029: BOARD(unit), unit, bits, how); ! 1030: #endif ! 1031: ! 1032: brd = BOARD(unit); ! 1033: dcm = dcm_addr[brd]; ! 1034: s = spltty(); ! 1035: switch (how) { ! 1036: ! 1037: case DMSET: ! 1038: dcm_modem[unit]->mdmout = bits; ! 1039: hit++; ! 1040: break; ! 1041: ! 1042: case DMBIS: ! 1043: dcm_modem[unit]->mdmout |= bits; ! 1044: hit++; ! 1045: break; ! 1046: ! 1047: case DMBIC: ! 1048: dcm_modem[unit]->mdmout &= ~bits; ! 1049: hit++; ! 1050: break; ! 1051: ! 1052: case DMGET: ! 1053: bits = dcm_modem[unit]->mdmin; ! 1054: if (dcmsoftCAR[brd] & FLAG_STDDCE) ! 1055: bits = hp2dce_in(bits); ! 1056: break; ! 1057: } ! 1058: if (hit) { ! 1059: SEM_LOCK(dcm); ! 1060: dcm->dcm_modemchng |= 1<<(unit & 3); ! 1061: dcm->dcm_cr |= CR_MODM; ! 1062: SEM_UNLOCK(dcm); ! 1063: DELAY(10); /* delay until done */ ! 1064: (void) splx(s); ! 1065: } ! 1066: return (bits); ! 1067: } ! 1068: ! 1069: /* ! 1070: * Set board to either interrupt per-character or at a fixed interval. ! 1071: */ ! 1072: dcmsetischeme(brd, flags) ! 1073: int brd, flags; ! 1074: { ! 1075: register struct dcmdevice *dcm = dcm_addr[brd]; ! 1076: register struct dcmischeme *dis = &dcmischeme[brd]; ! 1077: register int i; ! 1078: u_char mask; ! 1079: int perchar = flags & DIS_PERCHAR; ! 1080: ! 1081: #ifdef DEBUG ! 1082: if (dcmdebug & DDB_INTSCHM) ! 1083: printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n", ! 1084: brd, perchar, dis->dis_perchar, ! 1085: dis->dis_intr, dis->dis_char); ! 1086: if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { ! 1087: printf("dcmsetischeme(%d): redundent request %d\n", ! 1088: brd, perchar); ! 1089: return; ! 1090: } ! 1091: #endif ! 1092: /* ! 1093: * If perchar is non-zero, we enable interrupts on all characters ! 1094: * otherwise we disable perchar interrupts and use periodic ! 1095: * polling interrupts. ! 1096: */ ! 1097: dis->dis_perchar = perchar; ! 1098: mask = perchar ? 0xf : 0x0; ! 1099: for (i = 0; i < 256; i++) ! 1100: dcm->dcm_bmap[i].data_data = mask; ! 1101: /* ! 1102: * Don't slow down tandem mode, interrupt on flow control ! 1103: * chars for any port on the board. ! 1104: */ ! 1105: if (!perchar) { ! 1106: register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)]; ! 1107: int c; ! 1108: ! 1109: for (i = 0; i < 4; i++, tp++) { ! 1110: if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) ! 1111: dcm->dcm_bmap[c].data_data |= (1 << i); ! 1112: if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) ! 1113: dcm->dcm_bmap[c].data_data |= (1 << i); ! 1114: } ! 1115: } ! 1116: /* ! 1117: * Board starts with timer disabled so if first call is to ! 1118: * set perchar mode then we don't want to toggle the timer. ! 1119: */ ! 1120: if (flags == (DIS_RESET|DIS_PERCHAR)) ! 1121: return; ! 1122: /* ! 1123: * Toggle card 16.7ms interrupts (we first make sure that card ! 1124: * has cleared the bit so it will see the toggle). ! 1125: */ ! 1126: while (dcm->dcm_cr & CR_TIMER) ! 1127: ; ! 1128: SEM_LOCK(dcm); ! 1129: dcm->dcm_cr |= CR_TIMER; ! 1130: SEM_UNLOCK(dcm); ! 1131: } ! 1132: ! 1133: /* ! 1134: * Following are all routines needed for DCM to act as console ! 1135: */ ! 1136: #include "../hp300/cons.h" ! 1137: ! 1138: dcmcnprobe(cp) ! 1139: struct consdev *cp; ! 1140: { ! 1141: register struct hp_hw *hw; ! 1142: int unit; ! 1143: ! 1144: /* locate the major number */ ! 1145: for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) ! 1146: if (cdevsw[dcmmajor].d_open == dcmopen) ! 1147: break; ! 1148: ! 1149: /* ! 1150: * Implicitly assigns the lowest select code DCM card found to be ! 1151: * logical unit 0 (actually CONUNIT). If your config file does ! 1152: * anything different, you're screwed. ! 1153: */ ! 1154: for (hw = sc_table; hw->hw_type; hw++) ! 1155: if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva)) ! 1156: break; ! 1157: if (!HW_ISDEV(hw, D_COMMDCM)) { ! 1158: cp->cn_pri = CN_DEAD; ! 1159: return; ! 1160: } ! 1161: unit = CONUNIT; ! 1162: dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva; ! 1163: ! 1164: /* initialize required fields */ ! 1165: cp->cn_dev = makedev(dcmmajor, unit); ! 1166: cp->cn_tp = &dcm_tty[unit]; ! 1167: switch (dcm_addr[BOARD(unit)]->dcm_rsid) { ! 1168: case DCMID: ! 1169: cp->cn_pri = CN_NORMAL; ! 1170: break; ! 1171: case DCMID|DCMCON: ! 1172: cp->cn_pri = CN_REMOTE; ! 1173: break; ! 1174: default: ! 1175: cp->cn_pri = CN_DEAD; ! 1176: return; ! 1177: } ! 1178: /* ! 1179: * If dcmconsole is initialized, raise our priority. ! 1180: */ ! 1181: if (dcmconsole == UNIT(unit)) ! 1182: cp->cn_pri = CN_REMOTE; ! 1183: #ifdef KGDB_CHEAT ! 1184: /* ! 1185: * This doesn't currently work, at least not with ite consoles; ! 1186: * the console hasn't been initialized yet. ! 1187: */ ! 1188: if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) { ! 1189: (void) dcminit(kgdb_dev, kgdb_rate); ! 1190: if (kgdb_debug_init) { ! 1191: /* ! 1192: * We assume that console is ready for us... ! 1193: * this assumes that a dca or ite console ! 1194: * has been selected already and will init ! 1195: * on the first putc. ! 1196: */ ! 1197: printf("dcm%d: ", UNIT(kgdb_dev)); ! 1198: kgdb_connect(1); ! 1199: } ! 1200: } ! 1201: #endif ! 1202: } ! 1203: ! 1204: dcmcninit(cp) ! 1205: struct consdev *cp; ! 1206: { ! 1207: dcminit(cp->cn_dev, dcmdefaultrate); ! 1208: dcmconsinit = 1; ! 1209: dcmconsole = UNIT(cp->cn_dev); ! 1210: } ! 1211: ! 1212: dcminit(dev, rate) ! 1213: dev_t dev; ! 1214: int rate; ! 1215: { ! 1216: register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; ! 1217: int s, mode, port; ! 1218: ! 1219: port = PORT(dev); ! 1220: mode = LC_8BITS | LC_1STOP; ! 1221: s = splhigh(); ! 1222: /* ! 1223: * Wait for transmitter buffer to empty. ! 1224: */ ! 1225: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) ! 1226: DELAY(DCM_USPERCH(rate)); ! 1227: /* ! 1228: * Make changes known to hardware. ! 1229: */ ! 1230: dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); ! 1231: dcm->dcm_data[port].dcm_conf = mode; ! 1232: SEM_LOCK(dcm); ! 1233: dcm->dcm_cmdtab[port].dcm_data |= CT_CON; ! 1234: dcm->dcm_cr |= (1 << port); ! 1235: SEM_UNLOCK(dcm); ! 1236: /* ! 1237: * Delay for config change to take place. Weighted by baud. ! 1238: * XXX why do we do this? ! 1239: */ ! 1240: DELAY(16 * DCM_USPERCH(rate)); ! 1241: splx(s); ! 1242: } ! 1243: ! 1244: dcmcngetc(dev) ! 1245: dev_t dev; ! 1246: { ! 1247: register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; ! 1248: register struct dcmrfifo *fifo; ! 1249: register struct dcmpreg *pp; ! 1250: register unsigned head; ! 1251: int s, c, stat, port; ! 1252: ! 1253: port = PORT(dev); ! 1254: pp = dcm_preg(dcm, port); ! 1255: s = splhigh(); ! 1256: head = pp->r_head & RX_MASK; ! 1257: fifo = &dcm->dcm_rfifos[3-port][head>>1]; ! 1258: while (head == (pp->r_tail & RX_MASK)) ! 1259: ; ! 1260: /* ! 1261: * If board interrupts are enabled, just let our received char ! 1262: * interrupt through in case some other port on the board was ! 1263: * busy. Otherwise we must clear the interrupt. ! 1264: */ ! 1265: SEM_LOCK(dcm); ! 1266: if ((dcm->dcm_ic & IC_IE) == 0) ! 1267: stat = dcm->dcm_iir; ! 1268: SEM_UNLOCK(dcm); ! 1269: c = fifo->data_char; ! 1270: stat = fifo->data_stat; ! 1271: pp->r_head = (head + 2) & RX_MASK; ! 1272: splx(s); ! 1273: return (c); ! 1274: } ! 1275: ! 1276: /* ! 1277: * Console kernel output character routine. ! 1278: */ ! 1279: dcmcnputc(dev, c) ! 1280: dev_t dev; ! 1281: int c; ! 1282: { ! 1283: register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; ! 1284: register struct dcmpreg *pp; ! 1285: unsigned tail; ! 1286: int s, port, stat; ! 1287: ! 1288: port = PORT(dev); ! 1289: pp = dcm_preg(dcm, port); ! 1290: s = splhigh(); ! 1291: #ifdef KGDB ! 1292: if (dev != kgdb_dev) ! 1293: #endif ! 1294: if (dcmconsinit == 0) { ! 1295: (void) dcminit(dev, dcmdefaultrate); ! 1296: dcmconsinit = 1; ! 1297: } ! 1298: tail = pp->t_tail & TX_MASK; ! 1299: while (tail != (pp->t_head & TX_MASK)) ! 1300: ; ! 1301: dcm->dcm_tfifos[3-port][tail].data_char = c; ! 1302: pp->t_tail = tail = (tail + 1) & TX_MASK; ! 1303: SEM_LOCK(dcm); ! 1304: dcm->dcm_cmdtab[port].dcm_data |= CT_TX; ! 1305: dcm->dcm_cr |= (1 << port); ! 1306: SEM_UNLOCK(dcm); ! 1307: while (tail != (pp->t_head & TX_MASK)) ! 1308: ; ! 1309: /* ! 1310: * If board interrupts are enabled, just let our completion ! 1311: * interrupt through in case some other port on the board ! 1312: * was busy. Otherwise we must clear the interrupt. ! 1313: */ ! 1314: if ((dcm->dcm_ic & IC_IE) == 0) { ! 1315: SEM_LOCK(dcm); ! 1316: stat = dcm->dcm_iir; ! 1317: SEM_UNLOCK(dcm); ! 1318: } ! 1319: splx(s); ! 1320: } ! 1321: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.