Annotation of sys/arch/hp300/dev/dcm.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: dcm.c,v 1.28 2006/01/01 11:59:37 miod Exp $ */
! 2: /* $NetBSD: dcm.c,v 1.41 1997/05/05 20:59:16 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1995, 1996, 1997 Jason R. Thorpe. All rights reserved.
! 6: * Copyright (c) 1988 University of Utah.
! 7: * Copyright (c) 1982, 1986, 1990, 1993
! 8: * The Regents of the University of California. All rights reserved.
! 9: *
! 10: * This code is derived from software contributed to Berkeley by
! 11: * the Systems Programming Group of the University of Utah Computer
! 12: * Science Department.
! 13: *
! 14: * Redistribution and use in source and binary forms, with or without
! 15: * modification, are permitted provided that the following conditions
! 16: * are met:
! 17: * 1. Redistributions of source code must retain the above copyright
! 18: * notice, this list of conditions and the following disclaimer.
! 19: * 2. Redistributions in binary form must reproduce the above copyright
! 20: * notice, this list of conditions and the following disclaimer in the
! 21: * documentation and/or other materials provided with the distribution.
! 22: * 3. 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 Utah: $Hdr: dcm.c 1.29 92/01/21$
! 39: *
! 40: * @(#)dcm.c 8.4 (Berkeley) 1/12/94
! 41: */
! 42:
! 43: /*
! 44: * TODO:
! 45: * Timeouts
! 46: * Test console support.
! 47: */
! 48:
! 49: /*
! 50: * 98642/MUX
! 51: */
! 52: #include <sys/param.h>
! 53: #include <sys/systm.h>
! 54: #include <sys/ioctl.h>
! 55: #include <sys/proc.h>
! 56: #include <sys/tty.h>
! 57: #include <sys/conf.h>
! 58: #include <sys/file.h>
! 59: #include <sys/uio.h>
! 60: #include <sys/kernel.h>
! 61: #include <sys/syslog.h>
! 62: #include <sys/time.h>
! 63: #include <sys/device.h>
! 64:
! 65: #include <machine/autoconf.h>
! 66: #include <machine/bus.h>
! 67: #include <machine/cpu.h>
! 68: #include <machine/intr.h>
! 69:
! 70: #include <dev/cons.h>
! 71:
! 72: #include <hp300/dev/dioreg.h>
! 73: #include <hp300/dev/diovar.h>
! 74: #include <hp300/dev/diodevs.h>
! 75: #include <hp300/dev/dcmreg.h>
! 76:
! 77: #ifndef DEFAULT_BAUD_RATE
! 78: #define DEFAULT_BAUD_RATE 9600
! 79: #endif
! 80:
! 81: const struct speedtab dcmspeedtab[] = {
! 82: { 0, BR_0 },
! 83: { 50, BR_50 },
! 84: { 75, BR_75 },
! 85: { 110, BR_110 },
! 86: { 134, BR_134 },
! 87: { 150, BR_150 },
! 88: { 300, BR_300 },
! 89: { 600, BR_600 },
! 90: { 1200, BR_1200 },
! 91: { 1800, BR_1800 },
! 92: { 2400, BR_2400 },
! 93: { 4800, BR_4800 },
! 94: { 9600, BR_9600 },
! 95: { 19200, BR_19200 },
! 96: { 38400, BR_38400 },
! 97: { -1, -1 },
! 98: };
! 99:
! 100: /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
! 101: #define DCM_USPERCH(s) (10000000 / (s))
! 102:
! 103: /*
! 104: * Per board interrupt scheme. 16.7ms is the polling interrupt rate
! 105: * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
! 106: */
! 107: #define DIS_TIMER 0
! 108: #define DIS_PERCHAR 1
! 109: #define DIS_RESET 2
! 110:
! 111: int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */
! 112: int dcminterval = 5; /* interval (secs) between checks */
! 113: struct dcmischeme {
! 114: int dis_perchar; /* non-zero if interrupting per char */
! 115: long dis_time; /* last time examined */
! 116: int dis_intr; /* recv interrupts during last interval */
! 117: int dis_char; /* characters read during last interval */
! 118: };
! 119:
! 120: /*
! 121: * Stuff for DCM console support. This could probably be done a little
! 122: * better.
! 123: */
! 124: static struct dcmdevice *dcm_cn = NULL; /* pointer to hardware */
! 125: static int dcmconsinit; /* has been initialized */
! 126:
! 127: int dcmdefaultrate = DEFAULT_BAUD_RATE;
! 128: int dcmconbrdbusy = 0;
! 129: int dcmmajor;
! 130:
! 131: #ifdef KGDB
! 132: /*
! 133: * Kernel GDB support
! 134: */
! 135: #include <machine/remote-sl.h>
! 136:
! 137: extern dev_t kgdb_dev;
! 138: extern int kgdb_rate;
! 139: extern int kgdb_debug_init;
! 140: #endif
! 141:
! 142: /* #define DCMSTATS */
! 143:
! 144: #ifdef DEBUG
! 145: int dcmdebug = 0x0;
! 146: #define DDB_SIOERR 0x01
! 147: #define DDB_PARAM 0x02
! 148: #define DDB_INPUT 0x04
! 149: #define DDB_OUTPUT 0x08
! 150: #define DDB_INTR 0x10
! 151: #define DDB_IOCTL 0x20
! 152: #define DDB_INTSCHM 0x40
! 153: #define DDB_MODEM 0x80
! 154: #define DDB_OPENCLOSE 0x100
! 155: #endif
! 156:
! 157: #ifdef DCMSTATS
! 158: #define DCMRBSIZE 94
! 159: #define DCMXBSIZE 24
! 160:
! 161: struct dcmstats {
! 162: long xints; /* # of xmit ints */
! 163: long xchars; /* # of xmit chars */
! 164: long xempty; /* times outq is empty in dcmstart */
! 165: long xrestarts; /* times completed while xmitting */
! 166: long rints; /* # of recv ints */
! 167: long rchars; /* # of recv chars */
! 168: long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
! 169: long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
! 170: };
! 171: #endif
! 172:
! 173: #define DCMUNIT(x) (minor(x) & 0x7f)
! 174: #define DCMCUA(x) (minor(x) & 0x80)
! 175: #define DCMBOARD(x) (((x) >> 2) & 0x3f)
! 176: #define DCMPORT(x) ((x) & 3)
! 177:
! 178: /*
! 179: * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
! 180: * the distribution panel uses "HP DCE" conventions. If requested via
! 181: * the device flags, we swap the inputs to something closer to normal DCE,
! 182: * allowing a straight-through cable to a DTE or a reversed cable
! 183: * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
! 184: * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
! 185: * DSR or make RTS work, though). The following gives the full
! 186: * details of a cable from this mux panel to a modem:
! 187: *
! 188: * HP modem
! 189: * name pin pin name
! 190: * HP inputs:
! 191: * "Rx" 2 3 Tx
! 192: * CTS 4 5 CTS (only needed for CCTS_OFLOW)
! 193: * DCD 20 8 DCD
! 194: * "DSR" 9 6 DSR (unneeded)
! 195: * RI 22 22 RI (unneeded)
! 196: *
! 197: * HP outputs:
! 198: * "Tx" 3 2 Rx
! 199: * "DTR" 6 not connected
! 200: * "RTS" 8 20 DTR
! 201: * "SR" 23 4 RTS (often not needed)
! 202: */
! 203: #define hp2dce_in(ibits) (iconv[(ibits) & 0xf])
! 204: static char iconv[16] = {
! 205: 0, MI_DM, MI_CTS, MI_CTS|MI_DM,
! 206: MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM,
! 207: MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM,
! 208: MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
! 209: MI_RI|MI_CD|MI_CTS|MI_DM
! 210: };
! 211:
! 212: /*
! 213: * Note that 8-port boards appear as 2 4-port boards at consecutive
! 214: * select codes.
! 215: */
! 216: #define NDCMPORT 4
! 217:
! 218: struct dcm_softc {
! 219: struct device sc_dev; /* generic device glue */
! 220: struct isr sc_isr;
! 221: struct dcmdevice *sc_dcm; /* pointer to hardware */
! 222: struct tty *sc_tty[NDCMPORT]; /* our tty instances */
! 223: struct modemreg *sc_modem[NDCMPORT]; /* modem control */
! 224: char sc_mcndlast[NDCMPORT]; /* XXX last modem status for port */
! 225: short sc_softCAR; /* mask of ports with soft-carrier */
! 226: struct dcmischeme sc_scheme; /* interrupt scheme for board */
! 227: u_char sc_cua; /* callout mode */
! 228:
! 229: /*
! 230: * Mask of soft-carrier bits in config flags.
! 231: */
! 232: #define DCM_SOFTCAR 0x0000000f
! 233:
! 234: int sc_flags; /* misc. configuration info */
! 235:
! 236: /*
! 237: * Bits for sc_flags
! 238: */
! 239: #define DCM_ACTIVE 0x00000001 /* indicates board is alive */
! 240: #define DCM_ISCONSOLE 0x00000002 /* indicates board is console */
! 241: #define DCM_STDDCE 0x00000010 /* re-map DCE to standard */
! 242: #define DCM_FLAGMASK (DCM_STDDCE) /* mask of valid bits in config flags */
! 243:
! 244: #ifdef DCMSTATS
! 245: struct dcmstats sc_stats; /* metrics gathering */
! 246: #endif
! 247: };
! 248:
! 249: cdev_decl(dcm);
! 250:
! 251: int dcmintr(void *);
! 252: void dcmpint(struct dcm_softc *, int, int);
! 253: void dcmrint(struct dcm_softc *);
! 254: void dcmreadbuf(struct dcm_softc *, int);
! 255: void dcmxint(struct dcm_softc *, int);
! 256: void dcmmint(struct dcm_softc *, int, int);
! 257:
! 258: int dcmparam(struct tty *, struct termios *);
! 259: void dcmstart(struct tty *);
! 260: int dcmstop(struct tty *, int);
! 261: int dcmmctl(dev_t, int, int);
! 262: void dcmsetischeme(int, int);
! 263: void dcminit(struct dcmdevice *, int, int);
! 264:
! 265: int dcmselftest(struct dcm_softc *);
! 266:
! 267: int dcm_console_scan(int, caddr_t, void *);
! 268: cons_decl(dcm);
! 269:
! 270: int dcmmatch(struct device *, void *, void *);
! 271: void dcmattach(struct device *, struct device *, void *);
! 272:
! 273: struct cfattach dcm_ca = {
! 274: sizeof(struct dcm_softc), dcmmatch, dcmattach
! 275: };
! 276:
! 277: struct cfdriver dcm_cd = {
! 278: NULL, "dcm", DV_TTY
! 279: };
! 280:
! 281: int
! 282: dcmmatch(parent, match, aux)
! 283: struct device *parent;
! 284: void *match, *aux;
! 285: {
! 286: struct dio_attach_args *da = aux;
! 287:
! 288: switch (da->da_id) {
! 289: case DIO_DEVICE_ID_DCM:
! 290: case DIO_DEVICE_ID_DCMREM:
! 291: return (1);
! 292: }
! 293:
! 294: return (0);
! 295: }
! 296:
! 297: void
! 298: dcmattach(parent, self, aux)
! 299: struct device *parent, *self;
! 300: void *aux;
! 301: {
! 302: struct dcm_softc *sc = (struct dcm_softc *)self;
! 303: struct dio_attach_args *da = aux;
! 304: struct dcmdevice *dcm;
! 305: int brd = self->dv_unit;
! 306: int scode = da->da_scode;
! 307: int i, mbits, code, ipl;
! 308:
! 309: sc->sc_flags = 0;
! 310:
! 311: if (scode == conscode) {
! 312: dcm = (struct dcmdevice *)conaddr;
! 313: sc->sc_flags |= DCM_ISCONSOLE;
! 314:
! 315: /*
! 316: * We didn't know which unit this would be during
! 317: * the console probe, so we have to fixup cn_dev here.
! 318: * Note that we always assume port 1 on the board.
! 319: */
! 320: cn_tab->cn_dev = makedev(dcmmajor, (brd << 2) | DCMCONSPORT);
! 321: } else {
! 322: dcm = (struct dcmdevice *)iomap(dio_scodetopa(da->da_scode),
! 323: da->da_size);
! 324: if (dcm == NULL) {
! 325: printf("\n%s: can't map registers\n",
! 326: sc->sc_dev.dv_xname);
! 327: return;
! 328: }
! 329: }
! 330:
! 331: sc->sc_dcm = dcm;
! 332:
! 333: ipl = DIO_IPL(dcm);
! 334: printf(" ipl %d", ipl);
! 335:
! 336: /*
! 337: * XXX someone _should_ fix this; the self test screws
! 338: * autoconfig messages.
! 339: */
! 340: if ((sc->sc_flags & DCM_ISCONSOLE) && dcmselftest(sc)) {
! 341: printf("\n%s: self-test failed\n", sc->sc_dev.dv_xname);
! 342: return;
! 343: }
! 344:
! 345: /* Extract configuration info from flags. */
! 346: sc->sc_softCAR = self->dv_cfdata->cf_flags & DCM_SOFTCAR;
! 347: sc->sc_flags |= self->dv_cfdata->cf_flags & DCM_FLAGMASK;
! 348:
! 349: /* Mark our unit as configured. */
! 350: sc->sc_flags |= DCM_ACTIVE;
! 351:
! 352: /* Establish the interrupt handler. */
! 353: sc->sc_isr.isr_func = dcmintr;
! 354: sc->sc_isr.isr_arg = sc;
! 355: sc->sc_isr.isr_ipl = ipl;
! 356: sc->sc_isr.isr_priority = IPL_TTY;
! 357: dio_intr_establish(&sc->sc_isr, self->dv_xname);
! 358:
! 359: if (dcmistype == DIS_TIMER)
! 360: dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
! 361: else
! 362: dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
! 363:
! 364: /* load pointers to modem control */
! 365: sc->sc_modem[0] = &dcm->dcm_modem0;
! 366: sc->sc_modem[1] = &dcm->dcm_modem1;
! 367: sc->sc_modem[2] = &dcm->dcm_modem2;
! 368: sc->sc_modem[3] = &dcm->dcm_modem3;
! 369:
! 370: /* set DCD (modem) and CTS (flow control) on all ports */
! 371: if (sc->sc_flags & DCM_STDDCE)
! 372: mbits = hp2dce_in(MI_CD|MI_CTS);
! 373: else
! 374: mbits = MI_CD|MI_CTS;
! 375:
! 376: for (i = 0; i < NDCMPORT; i++)
! 377: sc->sc_modem[i]->mdmmsk = mbits;
! 378:
! 379: /*
! 380: * Get current state of mdmin register on all ports, so that
! 381: * deltas will work properly.
! 382: */
! 383: for (i = 0; i < NDCMPORT; i++) {
! 384: code = sc->sc_modem[i]->mdmin;
! 385: if (sc->sc_flags & DCM_STDDCE)
! 386: code = hp2dce_in(code);
! 387: sc->sc_mcndlast[i] = code;
! 388: }
! 389:
! 390: dcm->dcm_ic = IC_IE; /* turn all interrupts on */
! 391:
! 392: /*
! 393: * Need to reset baud rate, etc. of next print so reset dcmconsinit.
! 394: * Also make sure console is always "hardwired"
! 395: */
! 396: if (sc->sc_flags & DCM_ISCONSOLE) {
! 397: dcmconsinit = 0;
! 398: sc->sc_softCAR |= (1 << DCMCONSPORT);
! 399: printf(": console on port %d\n", DCMCONSPORT);
! 400: } else
! 401: printf("\n");
! 402:
! 403: #ifdef KGDB
! 404: if (major(kgdb_dev) == dcmmajor &&
! 405: DCMBOARD(DCMUNIT(kgdb_dev)) == brd) {
! 406: if (dcmconsole == DCMUNIT(kgdb_dev)) /* XXX fixme */
! 407: kgdb_dev = NODEV; /* can't debug over console port */
! 408: #ifndef KGDB_CHEAT
! 409: /*
! 410: * The following could potentially be replaced
! 411: * by the corresponding code in dcmcnprobe.
! 412: */
! 413: else {
! 414: dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)),
! 415: kgdb_rate);
! 416: if (kgdb_debug_init) {
! 417: printf("%s port %d: ", sc->sc_dev.dv_xname,
! 418: DCMPORT(DCMUNIT(kgdb_dev)));
! 419: kgdb_connect(1);
! 420: } else
! 421: printf("%s port %d: kgdb enabled\n",
! 422: sc->sc_dev.dv_xname,
! 423: DCMPORT(DCMUNIT(kgdb_dev)));
! 424: }
! 425: /* end could be replaced */
! 426: #endif /* KGDB_CHEAT */
! 427: }
! 428: #endif /* KGDB */
! 429: }
! 430:
! 431: /* ARGSUSED */
! 432: int
! 433: dcmopen(dev, flag, mode, p)
! 434: dev_t dev;
! 435: int flag, mode;
! 436: struct proc *p;
! 437: {
! 438: struct dcm_softc *sc;
! 439: struct tty *tp;
! 440: int unit, brd, port;
! 441: int error = 0, mbits, s;
! 442:
! 443: unit = DCMUNIT(dev);
! 444: brd = DCMBOARD(unit);
! 445: port = DCMPORT(unit);
! 446:
! 447: if (brd >= dcm_cd.cd_ndevs || port >= NDCMPORT ||
! 448: (sc = dcm_cd.cd_devs[brd]) == NULL)
! 449: return (ENXIO);
! 450:
! 451: if ((sc->sc_flags & DCM_ACTIVE) == 0)
! 452: return (ENXIO);
! 453:
! 454: s = spltty();
! 455: if (sc->sc_tty[port] == NULL) {
! 456: tp = sc->sc_tty[port] = ttymalloc();
! 457: } else
! 458: tp = sc->sc_tty[port];
! 459: splx(s);
! 460:
! 461: tp->t_oproc = dcmstart;
! 462: tp->t_param = dcmparam;
! 463: tp->t_dev = dev;
! 464:
! 465: if ((tp->t_state & TS_ISOPEN) == 0) {
! 466: /*
! 467: * Sanity clause: reset the card on first open.
! 468: * The card might be left in an inconsistent state
! 469: * if the card memory is read inadvertently.
! 470: */
! 471: dcminit(sc->sc_dcm, port, dcmdefaultrate);
! 472:
! 473: tp->t_state |= TS_WOPEN;
! 474: ttychars(tp);
! 475: tp->t_iflag = TTYDEF_IFLAG;
! 476: tp->t_oflag = TTYDEF_OFLAG;
! 477: tp->t_cflag = TTYDEF_CFLAG;
! 478: tp->t_lflag = TTYDEF_LFLAG;
! 479: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
! 480:
! 481: s = spltty();
! 482:
! 483: (void) dcmparam(tp, &tp->t_termios);
! 484: ttsetwater(tp);
! 485: } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
! 486: return (EBUSY);
! 487: else
! 488: s = spltty();
! 489:
! 490: /* Set modem control state. */
! 491: mbits = MO_ON;
! 492: if (sc->sc_flags & DCM_STDDCE)
! 493: mbits |= MO_SR; /* pin 23, could be used as RTS */
! 494:
! 495: (void) dcmmctl(dev, mbits, DMSET); /* enable port */
! 496:
! 497: /* Set soft-carrier if so configured. */
! 498: if ((sc->sc_softCAR & (1 << port)) || DCMCUA(dev) ||
! 499: (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
! 500: tp->t_state |= TS_CARR_ON;
! 501:
! 502: if (DCMCUA(dev)) {
! 503: if (tp->t_state & TS_ISOPEN) {
! 504: /* Ah, but someone already is dialed in... */
! 505: splx(s);
! 506: return (EBUSY);
! 507: }
! 508: sc->sc_cua = 1; /* We go into CUA mode */
! 509: }
! 510:
! 511: #ifdef DEBUG
! 512: if (dcmdebug & DDB_MODEM)
! 513: printf("%s: dcmopen port %d softcarr %c\n",
! 514: sc->sc_dev.dv_xname, port,
! 515: (tp->t_state & TS_CARR_ON) ? '1' : '0');
! 516: #endif
! 517:
! 518: /* Wait for carrier if necessary. */
! 519: if (flag & O_NONBLOCK) {
! 520: if (!DCMCUA(dev) && sc->sc_cua) {
! 521: /* Opening TTY non-blocking... but the CUA is busy */
! 522: splx(s);
! 523: return (EBUSY);
! 524: }
! 525: } else {
! 526: while (sc->sc_cua ||
! 527: ((tp->t_cflag & CLOCAL) == 0 &&
! 528: (tp->t_state & TS_CARR_ON) == 0)) {
! 529: tp->t_state |= TS_WOPEN;
! 530: error = ttysleep(tp, (caddr_t)&tp->t_rawq,
! 531: TTIPRI | PCATCH, ttopen, 0);
! 532: if (!DCMCUA(dev) && sc->sc_cua && error == EINTR)
! 533: continue;
! 534: if (error) {
! 535: if (DCMCUA(dev))
! 536: sc->sc_cua = 0;
! 537: splx(s);
! 538: return (error);
! 539: }
! 540: if (!DCMCUA(dev) && sc->sc_cua)
! 541: continue;
! 542: }
! 543: }
! 544: splx(s);
! 545:
! 546: #ifdef DEBUG
! 547: if (dcmdebug & DDB_OPENCLOSE)
! 548: printf("%s port %d: dcmopen: st %x fl %x\n",
! 549: sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags);
! 550: #endif
! 551: if (error == 0)
! 552: error = (*linesw[tp->t_line].l_open)(dev, tp);
! 553:
! 554: return (error);
! 555: }
! 556:
! 557: /*ARGSUSED*/
! 558: int
! 559: dcmclose(dev, flag, mode, p)
! 560: dev_t dev;
! 561: int flag, mode;
! 562: struct proc *p;
! 563: {
! 564: int s, unit, board, port;
! 565: struct dcm_softc *sc;
! 566: struct tty *tp;
! 567:
! 568: unit = DCMUNIT(dev);
! 569: board = DCMBOARD(unit);
! 570: port = DCMPORT(unit);
! 571:
! 572: sc = dcm_cd.cd_devs[board];
! 573: tp = sc->sc_tty[port];
! 574:
! 575: (*linesw[tp->t_line].l_close)(tp, flag);
! 576:
! 577: s = spltty();
! 578:
! 579: if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
! 580: (tp->t_state & TS_ISOPEN) == 0)
! 581: (void) dcmmctl(dev, MO_OFF, DMSET);
! 582: #ifdef DEBUG
! 583: if (dcmdebug & DDB_OPENCLOSE)
! 584: printf("%s port %d: dcmclose: st %x fl %x\n",
! 585: sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags);
! 586: #endif
! 587: sc->sc_cua = 0;
! 588: splx(s);
! 589: ttyclose(tp);
! 590: #if 0
! 591: ttyfree(tp);
! 592: sc->sc_tty[port] == NULL;
! 593: #endif
! 594: return (0);
! 595: }
! 596:
! 597: int
! 598: dcmread(dev, uio, flag)
! 599: dev_t dev;
! 600: struct uio *uio;
! 601: int flag;
! 602: {
! 603: int unit, board, port;
! 604: struct dcm_softc *sc;
! 605: struct tty *tp;
! 606:
! 607: unit = DCMUNIT(dev);
! 608: board = DCMBOARD(unit);
! 609: port = DCMPORT(unit);
! 610:
! 611: sc = dcm_cd.cd_devs[board];
! 612: tp = sc->sc_tty[port];
! 613:
! 614: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
! 615: }
! 616:
! 617: int
! 618: dcmwrite(dev, uio, flag)
! 619: dev_t dev;
! 620: struct uio *uio;
! 621: int flag;
! 622: {
! 623: int unit, board, port;
! 624: struct dcm_softc *sc;
! 625: struct tty *tp;
! 626:
! 627: unit = DCMUNIT(dev);
! 628: board = DCMBOARD(unit);
! 629: port = DCMPORT(unit);
! 630:
! 631: sc = dcm_cd.cd_devs[board];
! 632: tp = sc->sc_tty[port];
! 633:
! 634: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 635: }
! 636:
! 637: struct tty *
! 638: dcmtty(dev)
! 639: dev_t dev;
! 640: {
! 641: int unit, board, port;
! 642: struct dcm_softc *sc;
! 643:
! 644: unit = DCMUNIT(dev);
! 645: board = DCMBOARD(unit);
! 646: port = DCMPORT(unit);
! 647:
! 648: sc = dcm_cd.cd_devs[board];
! 649:
! 650: return (sc->sc_tty[port]);
! 651: }
! 652:
! 653: int
! 654: dcmintr(arg)
! 655: void *arg;
! 656: {
! 657: struct dcm_softc *sc = arg;
! 658: struct dcmdevice *dcm = sc->sc_dcm;
! 659: struct dcmischeme *dis = &sc->sc_scheme;
! 660: int brd = sc->sc_dev.dv_unit;
! 661: int code, i;
! 662: int pcnd[4], mcode, mcnd[4];
! 663:
! 664: /*
! 665: * Do all guarded accesses right off to minimize
! 666: * block out of hardware.
! 667: */
! 668: SEM_LOCK(dcm);
! 669: if ((dcm->dcm_ic & IC_IR) == 0) {
! 670: SEM_UNLOCK(dcm);
! 671: return (0);
! 672: }
! 673:
! 674: for (i = 0; i < 4; i++) {
! 675: pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
! 676: dcm->dcm_icrtab[i].dcm_data = 0;
! 677: code = sc->sc_modem[i]->mdmin;
! 678: if (sc->sc_flags & DCM_STDDCE)
! 679: code = hp2dce_in(code);
! 680: mcnd[i] = code;
! 681: }
! 682: code = dcm->dcm_iir & IIR_MASK;
! 683: dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */
! 684: mcode = dcm->dcm_modemintr;
! 685: dcm->dcm_modemintr = 0;
! 686: SEM_UNLOCK(dcm);
! 687:
! 688: #ifdef DEBUG
! 689: if (dcmdebug & DDB_INTR) {
! 690: printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ",
! 691: sc->sc_dev.dv_xname, code, pcnd[0], pcnd[1],
! 692: pcnd[2], pcnd[3]);
! 693: printf("miir %x mc %x/%x/%x/%x\n",
! 694: mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
! 695: }
! 696: #endif
! 697: if (code & IIR_TIMEO)
! 698: dcmrint(sc);
! 699: if (code & IIR_PORT0)
! 700: dcmpint(sc, 0, pcnd[0]);
! 701: if (code & IIR_PORT1)
! 702: dcmpint(sc, 1, pcnd[1]);
! 703: if (code & IIR_PORT2)
! 704: dcmpint(sc, 2, pcnd[2]);
! 705: if (code & IIR_PORT3)
! 706: dcmpint(sc, 3, pcnd[3]);
! 707: if (code & IIR_MODM) {
! 708: if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */
! 709: dcmmint(sc, 0, mcnd[0]);
! 710: if (mcode & 0x2)
! 711: dcmmint(sc, 1, mcnd[1]);
! 712: if (mcode & 0x4)
! 713: dcmmint(sc, 2, mcnd[2]);
! 714: if (mcode & 0x8)
! 715: dcmmint(sc, 3, mcnd[3]);
! 716: }
! 717:
! 718: /*
! 719: * Chalk up a receiver interrupt if the timer running or one of
! 720: * the ports reports a special character interrupt.
! 721: */
! 722: if ((code & IIR_TIMEO) ||
! 723: ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
! 724: dis->dis_intr++;
! 725: /*
! 726: * See if it is time to check/change the interrupt rate.
! 727: */
! 728: if (dcmistype < 0 &&
! 729: (i = time.tv_sec - dis->dis_time) >= dcminterval) {
! 730: /*
! 731: * If currently per-character and averaged over 70 interrupts
! 732: * per-second (66 is threshold of 600 baud) in last interval,
! 733: * switch to timer mode.
! 734: *
! 735: * XXX decay counts ala load average to avoid spikes?
! 736: */
! 737: if (dis->dis_perchar && dis->dis_intr > 70 * i)
! 738: dcmsetischeme(brd, DIS_TIMER);
! 739: /*
! 740: * If currently using timer and had more interrupts than
! 741: * received characters in the last interval, switch back
! 742: * to per-character. Note that after changing to per-char
! 743: * we must process any characters already in the queue
! 744: * since they may have arrived before the bitmap was setup.
! 745: *
! 746: * XXX decay counts?
! 747: */
! 748: else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
! 749: dcmsetischeme(brd, DIS_PERCHAR);
! 750: dcmrint(sc);
! 751: }
! 752: dis->dis_intr = dis->dis_char = 0;
! 753: dis->dis_time = time.tv_sec;
! 754: }
! 755: return (1);
! 756: }
! 757:
! 758: /*
! 759: * Port interrupt. Can be two things:
! 760: * First, it might be a special character (exception interrupt);
! 761: * Second, it may be a buffer empty (transmit interrupt);
! 762: */
! 763: void
! 764: dcmpint(sc, port, code)
! 765: struct dcm_softc *sc;
! 766: int port, code;
! 767: {
! 768:
! 769: if (code & IT_SPEC)
! 770: dcmreadbuf(sc, port);
! 771: if (code & IT_TX)
! 772: dcmxint(sc, port);
! 773: }
! 774:
! 775: void
! 776: dcmrint(sc)
! 777: struct dcm_softc *sc;
! 778: {
! 779: int port;
! 780:
! 781: for (port = 0; port < NDCMPORT; port++)
! 782: dcmreadbuf(sc, port);
! 783: }
! 784:
! 785: void
! 786: dcmreadbuf(sc, port)
! 787: struct dcm_softc *sc;
! 788: int port;
! 789: {
! 790: struct dcmdevice *dcm = sc->sc_dcm;
! 791: struct dcmpreg *pp = dcm_preg(dcm, port);
! 792: struct dcmrfifo *fifo;
! 793: struct tty *tp;
! 794: int c, stat;
! 795: u_int head;
! 796: int nch = 0;
! 797: #ifdef DCMSTATS
! 798: struct dcmstats *dsp = &sc->sc_stats;
! 799:
! 800: dsp->rints++;
! 801: #endif
! 802: tp = sc->sc_tty[port];
! 803: if (tp == NULL)
! 804: return;
! 805:
! 806: if ((tp->t_state & TS_ISOPEN) == 0) {
! 807: #ifdef KGDB
! 808: if ((makedev(dcmmajor, minor(tp->t_dev)) == kgdb_dev) &&
! 809: (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
! 810: dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
! 811: pp->r_head = (head + 2) & RX_MASK;
! 812: kgdb_connect(0); /* trap into kgdb */
! 813: return;
! 814: }
! 815: #endif /* KGDB */
! 816: pp->r_head = pp->r_tail & RX_MASK;
! 817: return;
! 818: }
! 819:
! 820: head = pp->r_head & RX_MASK;
! 821: fifo = &dcm->dcm_rfifos[3-port][head>>1];
! 822: /*
! 823: * XXX upper bound on how many chars we will take in one swallow?
! 824: */
! 825: while (head != (pp->r_tail & RX_MASK)) {
! 826: /*
! 827: * Get character/status and update head pointer as fast
! 828: * as possible to make room for more characters.
! 829: */
! 830: c = fifo->data_char;
! 831: stat = fifo->data_stat;
! 832: head = (head + 2) & RX_MASK;
! 833: pp->r_head = head;
! 834: fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
! 835: nch++;
! 836:
! 837: #ifdef DEBUG
! 838: if (dcmdebug & DDB_INPUT)
! 839: printf("%s port %d: dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n",
! 840: sc->sc_dev.dv_xname, port,
! 841: c&0xFF, c, stat&0xFF,
! 842: tp->t_flags, head, pp->r_tail);
! 843: #endif
! 844: /*
! 845: * Check for and handle errors
! 846: */
! 847: if (stat & RD_MASK) {
! 848: #ifdef DEBUG
! 849: if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
! 850: printf("%s port %d: dcmreadbuf: err: c%x('%c') s%x\n",
! 851: sc->sc_dev.dv_xname, port,
! 852: stat, c&0xFF, c);
! 853: #endif
! 854: if (stat & (RD_BD | RD_FE))
! 855: c |= TTY_FE;
! 856: else if (stat & RD_PE)
! 857: c |= TTY_PE;
! 858: else if (stat & RD_OVF)
! 859: log(LOG_WARNING,
! 860: "%s port %d: silo overflow\n",
! 861: sc->sc_dev.dv_xname, port);
! 862: else if (stat & RD_OE)
! 863: log(LOG_WARNING,
! 864: "%s port %d: uart overflow\n",
! 865: sc->sc_dev.dv_xname, port);
! 866: }
! 867: (*linesw[tp->t_line].l_rint)(c, tp);
! 868: }
! 869: sc->sc_scheme.dis_char += nch;
! 870:
! 871: #ifdef DCMSTATS
! 872: dsp->rchars += nch;
! 873: if (nch <= DCMRBSIZE)
! 874: dsp->rsilo[nch]++;
! 875: else
! 876: dsp->rsilo[DCMRBSIZE+1]++;
! 877: #endif
! 878: }
! 879:
! 880: void
! 881: dcmxint(sc, port)
! 882: struct dcm_softc *sc;
! 883: int port;
! 884: {
! 885: struct tty *tp;
! 886:
! 887: tp = sc->sc_tty[port];
! 888: if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
! 889: return;
! 890:
! 891: tp->t_state &= ~TS_BUSY;
! 892: if (tp->t_state & TS_FLUSH)
! 893: tp->t_state &= ~TS_FLUSH;
! 894: (*linesw[tp->t_line].l_start)(tp);
! 895: }
! 896:
! 897: void
! 898: dcmmint(sc, port, mcnd)
! 899: struct dcm_softc *sc;
! 900: int port, mcnd;
! 901: {
! 902: int delta;
! 903: struct tty *tp;
! 904: struct dcmdevice *dcm = sc->sc_dcm;
! 905:
! 906: tp = sc->sc_tty[port];
! 907: if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
! 908: return;
! 909:
! 910: #ifdef DEBUG
! 911: if (dcmdebug & DDB_MODEM)
! 912: printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n",
! 913: sc->sc_dev.dv_xname, port, mcnd, sc->sc_mcndlast[port]);
! 914: #endif
! 915: delta = mcnd ^ sc->sc_mcndlast[port];
! 916: sc->sc_mcndlast[port] = mcnd;
! 917: if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
! 918: (tp->t_flags & CCTS_OFLOW)) {
! 919: if (mcnd & MI_CTS) {
! 920: tp->t_state &= ~TS_TTSTOP;
! 921: ttstart(tp);
! 922: } else
! 923: tp->t_state |= TS_TTSTOP; /* inline dcmstop */
! 924: }
! 925: if (delta & MI_CD) {
! 926: if (mcnd & MI_CD)
! 927: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
! 928: else if ((sc->sc_softCAR & (1 << port)) == 0 &&
! 929: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
! 930: sc->sc_modem[port]->mdmout = MO_OFF;
! 931: SEM_LOCK(dcm);
! 932: dcm->dcm_modemchng |= (1 << port);
! 933: dcm->dcm_cr |= CR_MODM;
! 934: SEM_UNLOCK(dcm);
! 935: DELAY(10); /* time to change lines */
! 936: }
! 937: }
! 938: }
! 939:
! 940: int
! 941: dcmioctl(dev, cmd, data, flag, p)
! 942: dev_t dev;
! 943: u_long cmd;
! 944: caddr_t data;
! 945: int flag;
! 946: struct proc *p;
! 947: {
! 948: struct dcm_softc *sc;
! 949: struct tty *tp;
! 950: struct dcmdevice *dcm;
! 951: int board, port, unit = DCMUNIT(dev);
! 952: int error, s;
! 953:
! 954: port = DCMPORT(unit);
! 955: board = DCMBOARD(unit);
! 956:
! 957: sc = dcm_cd.cd_devs[board];
! 958: dcm = sc->sc_dcm;
! 959: tp = sc->sc_tty[port];
! 960:
! 961: #ifdef DEBUG
! 962: if (dcmdebug & DDB_IOCTL)
! 963: printf("%s port %d: dcmioctl: cmd %lx data %x flag %x\n",
! 964: sc->sc_dev.dv_xname, port, cmd, *data, flag);
! 965: #endif
! 966: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 967: if (error >= 0)
! 968: return (error);
! 969: error = ttioctl(tp, cmd, data, flag, p);
! 970: if (error >= 0)
! 971: return (error);
! 972:
! 973: switch (cmd) {
! 974: case TIOCSBRK:
! 975: /*
! 976: * Wait for transmitter buffer to empty
! 977: */
! 978: s = spltty();
! 979: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
! 980: DELAY(DCM_USPERCH(tp->t_ospeed));
! 981: SEM_LOCK(dcm);
! 982: dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
! 983: dcm->dcm_cr |= (1 << port); /* start break */
! 984: SEM_UNLOCK(dcm);
! 985: splx(s);
! 986: break;
! 987:
! 988: case TIOCCBRK:
! 989: SEM_LOCK(dcm);
! 990: dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
! 991: dcm->dcm_cr |= (1 << port); /* end break */
! 992: SEM_UNLOCK(dcm);
! 993: break;
! 994:
! 995: case TIOCSDTR:
! 996: (void) dcmmctl(dev, MO_ON, DMBIS);
! 997: break;
! 998:
! 999: case TIOCCDTR:
! 1000: (void) dcmmctl(dev, MO_ON, DMBIC);
! 1001: break;
! 1002:
! 1003: case TIOCMSET:
! 1004: (void) dcmmctl(dev, *(int *)data, DMSET);
! 1005: break;
! 1006:
! 1007: case TIOCMBIS:
! 1008: (void) dcmmctl(dev, *(int *)data, DMBIS);
! 1009: break;
! 1010:
! 1011: case TIOCMBIC:
! 1012: (void) dcmmctl(dev, *(int *)data, DMBIC);
! 1013: break;
! 1014:
! 1015: case TIOCMGET:
! 1016: *(int *)data = dcmmctl(dev, 0, DMGET);
! 1017: break;
! 1018:
! 1019: case TIOCGFLAGS: {
! 1020: int bits = 0;
! 1021:
! 1022: if ((sc->sc_softCAR & (1 << port)))
! 1023: bits |= TIOCFLAG_SOFTCAR;
! 1024:
! 1025: if (tp->t_cflag & CLOCAL)
! 1026: bits |= TIOCFLAG_CLOCAL;
! 1027:
! 1028: *(int *)data = bits;
! 1029: break;
! 1030: }
! 1031:
! 1032: case TIOCSFLAGS: {
! 1033: int userbits;
! 1034:
! 1035: error = suser(p, 0);
! 1036: if (error)
! 1037: return (EPERM);
! 1038:
! 1039: userbits = *(int *)data;
! 1040:
! 1041: if ((userbits & TIOCFLAG_SOFTCAR) ||
! 1042: ((sc->sc_flags & DCM_ISCONSOLE) &&
! 1043: (port == DCMCONSPORT)))
! 1044: sc->sc_softCAR |= (1 << port);
! 1045:
! 1046: if (userbits & TIOCFLAG_CLOCAL)
! 1047: tp->t_cflag |= CLOCAL;
! 1048:
! 1049: break;
! 1050: }
! 1051:
! 1052: default:
! 1053: return (ENOTTY);
! 1054: }
! 1055: return (0);
! 1056: }
! 1057:
! 1058: int
! 1059: dcmparam(tp, t)
! 1060: struct tty *tp;
! 1061: struct termios *t;
! 1062: {
! 1063: struct dcm_softc *sc;
! 1064: struct dcmdevice *dcm;
! 1065: int unit, board, port, mode, cflag = t->c_cflag;
! 1066: int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
! 1067:
! 1068: unit = DCMUNIT(tp->t_dev);
! 1069: board = DCMBOARD(unit);
! 1070: port = DCMPORT(unit);
! 1071:
! 1072: sc = dcm_cd.cd_devs[board];
! 1073: dcm = sc->sc_dcm;
! 1074:
! 1075: /* check requested parameters */
! 1076: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
! 1077: return (EINVAL);
! 1078: /* and copy to tty */
! 1079: tp->t_ispeed = t->c_ispeed;
! 1080: tp->t_ospeed = t->c_ospeed;
! 1081: tp->t_cflag = cflag;
! 1082: if (ospeed == 0) {
! 1083: (void) dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET);
! 1084: return (0);
! 1085: }
! 1086:
! 1087: mode = 0;
! 1088: switch (cflag&CSIZE) {
! 1089: case CS5:
! 1090: mode = LC_5BITS; break;
! 1091: case CS6:
! 1092: mode = LC_6BITS; break;
! 1093: case CS7:
! 1094: mode = LC_7BITS; break;
! 1095: case CS8:
! 1096: mode = LC_8BITS; break;
! 1097: }
! 1098: if (cflag&PARENB) {
! 1099: if (cflag&PARODD)
! 1100: mode |= LC_PODD;
! 1101: else
! 1102: mode |= LC_PEVEN;
! 1103: }
! 1104: if (cflag&CSTOPB)
! 1105: mode |= LC_2STOP;
! 1106: else
! 1107: mode |= LC_1STOP;
! 1108: #ifdef DEBUG
! 1109: if (dcmdebug & DDB_PARAM)
! 1110: printf("%s port %d: dcmparam: cflag %x mode %x speed %d uperch %d\n",
! 1111: sc->sc_dev.dv_xname, port, cflag, mode, tp->t_ospeed,
! 1112: DCM_USPERCH(tp->t_ospeed));
! 1113: #endif
! 1114:
! 1115: /*
! 1116: * Wait for transmitter buffer to empty.
! 1117: */
! 1118: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
! 1119: DELAY(DCM_USPERCH(tp->t_ospeed));
! 1120: /*
! 1121: * Make changes known to hardware.
! 1122: */
! 1123: dcm->dcm_data[port].dcm_baud = ospeed;
! 1124: dcm->dcm_data[port].dcm_conf = mode;
! 1125: SEM_LOCK(dcm);
! 1126: dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
! 1127: dcm->dcm_cr |= (1 << port);
! 1128: SEM_UNLOCK(dcm);
! 1129: /*
! 1130: * Delay for config change to take place. Weighted by baud.
! 1131: * XXX why do we do this?
! 1132: */
! 1133: DELAY(16 * DCM_USPERCH(tp->t_ospeed));
! 1134: return (0);
! 1135: }
! 1136:
! 1137: void
! 1138: dcmstart(tp)
! 1139: struct tty *tp;
! 1140: {
! 1141: struct dcm_softc *sc;
! 1142: struct dcmdevice *dcm;
! 1143: struct dcmpreg *pp;
! 1144: struct dcmtfifo *fifo;
! 1145: char *bp;
! 1146: u_int head, tail, next;
! 1147: int unit, board, port, nch;
! 1148: char buf[16];
! 1149: int s;
! 1150: #ifdef DCMSTATS
! 1151: struct dcmstats *dsp = &sc->sc_stats;
! 1152: int tch = 0;
! 1153: #endif
! 1154:
! 1155: unit = DCMUNIT(tp->t_dev);
! 1156: board = DCMBOARD(unit);
! 1157: port = DCMPORT(unit);
! 1158:
! 1159: sc = dcm_cd.cd_devs[board];
! 1160: dcm = sc->sc_dcm;
! 1161:
! 1162: s = spltty();
! 1163: #ifdef DCMSTATS
! 1164: dsp->xints++;
! 1165: #endif
! 1166: #ifdef DEBUG
! 1167: if (dcmdebug & DDB_OUTPUT)
! 1168: printf("%s port %d: dcmstart: state %x flags %x outcc %d\n",
! 1169: sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags,
! 1170: tp->t_outq.c_cc);
! 1171: #endif
! 1172: if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
! 1173: goto out;
! 1174: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 1175: if (tp->t_state&TS_ASLEEP) {
! 1176: tp->t_state &= ~TS_ASLEEP;
! 1177: wakeup((caddr_t)&tp->t_outq);
! 1178: }
! 1179: selwakeup(&tp->t_wsel);
! 1180: }
! 1181: if (tp->t_outq.c_cc == 0) {
! 1182: #ifdef DCMSTATS
! 1183: dsp->xempty++;
! 1184: #endif
! 1185: goto out;
! 1186: }
! 1187:
! 1188: pp = dcm_preg(dcm, port);
! 1189: tail = pp->t_tail & TX_MASK;
! 1190: next = (tail + 1) & TX_MASK;
! 1191: head = pp->t_head & TX_MASK;
! 1192: if (head == next)
! 1193: goto out;
! 1194: fifo = &dcm->dcm_tfifos[3-port][tail];
! 1195: again:
! 1196: nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
! 1197: #ifdef DCMSTATS
! 1198: tch += nch;
! 1199: #endif
! 1200: #ifdef DEBUG
! 1201: if (dcmdebug & DDB_OUTPUT)
! 1202: printf("\thead %x tail %x nch %d\n", head, tail, nch);
! 1203: #endif
! 1204: /*
! 1205: * Loop transmitting all the characters we can.
! 1206: */
! 1207: for (bp = buf; --nch >= 0; bp++) {
! 1208: fifo->data_char = *bp;
! 1209: pp->t_tail = next;
! 1210: /*
! 1211: * If this is the first character,
! 1212: * get the hardware moving right now.
! 1213: */
! 1214: if (bp == buf) {
! 1215: tp->t_state |= TS_BUSY;
! 1216: SEM_LOCK(dcm);
! 1217: dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
! 1218: dcm->dcm_cr |= (1 << port);
! 1219: SEM_UNLOCK(dcm);
! 1220: }
! 1221: tail = next;
! 1222: fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
! 1223: next = (next + 1) & TX_MASK;
! 1224: }
! 1225: /*
! 1226: * Head changed while we were loading the buffer,
! 1227: * go back and load some more if we can.
! 1228: */
! 1229: if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
! 1230: #ifdef DCMSTATS
! 1231: dsp->xrestarts++;
! 1232: #endif
! 1233: head = pp->t_head & TX_MASK;
! 1234: goto again;
! 1235: }
! 1236:
! 1237: /*
! 1238: * Kick it one last time in case it finished while we were
! 1239: * loading the last bunch.
! 1240: */
! 1241: if (bp > &buf[1]) {
! 1242: tp->t_state |= TS_BUSY;
! 1243: SEM_LOCK(dcm);
! 1244: dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
! 1245: dcm->dcm_cr |= (1 << port);
! 1246: SEM_UNLOCK(dcm);
! 1247: }
! 1248: #ifdef DEBUG
! 1249: if (dcmdebug & DDB_INTR)
! 1250: printf("%s port %d: dcmstart: head %x tail %x outqcc %d\n",
! 1251: sc->sc_dev.dv_xname, port, head, tail, tp->t_outq.c_cc);
! 1252: #endif
! 1253: out:
! 1254: #ifdef DCMSTATS
! 1255: dsp->xchars += tch;
! 1256: if (tch <= DCMXBSIZE)
! 1257: dsp->xsilo[tch]++;
! 1258: else
! 1259: dsp->xsilo[DCMXBSIZE+1]++;
! 1260: #endif
! 1261: splx(s);
! 1262: }
! 1263:
! 1264: /*
! 1265: * Stop output on a line.
! 1266: */
! 1267: int
! 1268: dcmstop(tp, flag)
! 1269: struct tty *tp;
! 1270: int flag;
! 1271: {
! 1272: int s;
! 1273:
! 1274: s = spltty();
! 1275: if (tp->t_state & TS_BUSY) {
! 1276: /* XXX is there some way to safely stop transmission? */
! 1277: if ((tp->t_state&TS_TTSTOP) == 0)
! 1278: tp->t_state |= TS_FLUSH;
! 1279: }
! 1280: splx(s);
! 1281: return (0);
! 1282: }
! 1283:
! 1284: /*
! 1285: * Modem control
! 1286: */
! 1287: int
! 1288: dcmmctl(dev, bits, how)
! 1289: dev_t dev;
! 1290: int bits, how;
! 1291: {
! 1292: struct dcm_softc *sc;
! 1293: struct dcmdevice *dcm;
! 1294: int s, unit, brd, port, hit = 0;
! 1295:
! 1296: unit = DCMUNIT(dev);
! 1297: brd = DCMBOARD(unit);
! 1298: port = DCMPORT(unit);
! 1299:
! 1300: sc = dcm_cd.cd_devs[brd];
! 1301: dcm = sc->sc_dcm;
! 1302:
! 1303: #ifdef DEBUG
! 1304: if (dcmdebug & DDB_MODEM)
! 1305: printf("%s port %d: dcmmctl: bits 0x%x how %x\n",
! 1306: sc->sc_dev.dv_xname, port, bits, how);
! 1307: #endif
! 1308:
! 1309: s = spltty();
! 1310:
! 1311: switch (how) {
! 1312: case DMSET:
! 1313: sc->sc_modem[port]->mdmout = bits;
! 1314: hit++;
! 1315: break;
! 1316:
! 1317: case DMBIS:
! 1318: sc->sc_modem[port]->mdmout |= bits;
! 1319: hit++;
! 1320: break;
! 1321:
! 1322: case DMBIC:
! 1323: sc->sc_modem[port]->mdmout &= ~bits;
! 1324: hit++;
! 1325: break;
! 1326:
! 1327: case DMGET:
! 1328: bits = sc->sc_modem[port]->mdmin;
! 1329: if (sc->sc_flags & DCM_STDDCE)
! 1330: bits = hp2dce_in(bits);
! 1331: break;
! 1332: }
! 1333: if (hit) {
! 1334: SEM_LOCK(dcm);
! 1335: dcm->dcm_modemchng |= 1<<(unit & 3);
! 1336: dcm->dcm_cr |= CR_MODM;
! 1337: SEM_UNLOCK(dcm);
! 1338: DELAY(10); /* delay until done */
! 1339: splx(s);
! 1340: }
! 1341: return (bits);
! 1342: }
! 1343:
! 1344: /*
! 1345: * Set board to either interrupt per-character or at a fixed interval.
! 1346: */
! 1347: void
! 1348: dcmsetischeme(brd, flags)
! 1349: int brd, flags;
! 1350: {
! 1351: struct dcm_softc *sc = dcm_cd.cd_devs[brd];
! 1352: struct dcmdevice *dcm = sc->sc_dcm;
! 1353: struct dcmischeme *dis = &sc->sc_scheme;
! 1354: int i;
! 1355: u_char mask;
! 1356: int perchar = flags & DIS_PERCHAR;
! 1357:
! 1358: #ifdef DEBUG
! 1359: if (dcmdebug & DDB_INTSCHM)
! 1360: printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n",
! 1361: sc->sc_dev.dv_xname, perchar, dis->dis_perchar,
! 1362: dis->dis_intr, dis->dis_char);
! 1363: if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
! 1364: printf("%s: dcmsetischeme: redundant request %d\n",
! 1365: sc->sc_dev.dv_xname, perchar);
! 1366: return;
! 1367: }
! 1368: #endif
! 1369: /*
! 1370: * If perchar is non-zero, we enable interrupts on all characters
! 1371: * otherwise we disable perchar interrupts and use periodic
! 1372: * polling interrupts.
! 1373: */
! 1374: dis->dis_perchar = perchar;
! 1375: mask = perchar ? 0xf : 0x0;
! 1376: for (i = 0; i < 256; i++)
! 1377: dcm->dcm_bmap[i].data_data = mask;
! 1378: /*
! 1379: * Don't slow down tandem mode, interrupt on flow control
! 1380: * chars for any port on the board.
! 1381: */
! 1382: if (!perchar) {
! 1383: struct tty *tp;
! 1384: int c;
! 1385:
! 1386: for (i = 0; i < NDCMPORT; i++) {
! 1387: tp = sc->sc_tty[i];
! 1388:
! 1389: if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
! 1390: dcm->dcm_bmap[c].data_data |= (1 << i);
! 1391: if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
! 1392: dcm->dcm_bmap[c].data_data |= (1 << i);
! 1393: }
! 1394: }
! 1395: /*
! 1396: * Board starts with timer disabled so if first call is to
! 1397: * set perchar mode then we don't want to toggle the timer.
! 1398: */
! 1399: if (flags == (DIS_RESET|DIS_PERCHAR))
! 1400: return;
! 1401: /*
! 1402: * Toggle card 16.7ms interrupts (we first make sure that card
! 1403: * has cleared the bit so it will see the toggle).
! 1404: */
! 1405: while (dcm->dcm_cr & CR_TIMER)
! 1406: ;
! 1407: SEM_LOCK(dcm);
! 1408: dcm->dcm_cr |= CR_TIMER;
! 1409: SEM_UNLOCK(dcm);
! 1410: }
! 1411:
! 1412: void
! 1413: dcminit(dcm, port, rate)
! 1414: struct dcmdevice *dcm;
! 1415: int port, rate;
! 1416: {
! 1417: int s, mode;
! 1418:
! 1419: mode = LC_8BITS | LC_1STOP;
! 1420:
! 1421: s = splhigh();
! 1422:
! 1423: /*
! 1424: * Wait for transmitter buffer to empty.
! 1425: */
! 1426: while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
! 1427: DELAY(DCM_USPERCH(rate));
! 1428:
! 1429: /*
! 1430: * Make changes known to hardware.
! 1431: */
! 1432: dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
! 1433: dcm->dcm_data[port].dcm_conf = mode;
! 1434: SEM_LOCK(dcm);
! 1435: dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
! 1436: dcm->dcm_cr |= (1 << port);
! 1437: SEM_UNLOCK(dcm);
! 1438:
! 1439: /*
! 1440: * Delay for config change to take place. Weighted by baud.
! 1441: * XXX why do we do this?
! 1442: */
! 1443: DELAY(16 * DCM_USPERCH(rate));
! 1444: splx(s);
! 1445: }
! 1446:
! 1447: /*
! 1448: * Empirically derived self-test magic
! 1449: */
! 1450: int
! 1451: dcmselftest(sc)
! 1452: struct dcm_softc *sc;
! 1453: {
! 1454: struct dcmdevice *dcm = sc->sc_dcm;
! 1455: int timo = 0;
! 1456: int s, rv;
! 1457:
! 1458: rv = 1;
! 1459:
! 1460: s = splhigh();
! 1461: dcm->dcm_rsid = DCMRS;
! 1462: DELAY(50000); /* 5000 is not long enough */
! 1463: dcm->dcm_rsid = 0;
! 1464: dcm->dcm_ic = IC_IE;
! 1465: dcm->dcm_cr = CR_SELFT;
! 1466: while ((dcm->dcm_ic & IC_IR) == 0) {
! 1467: if (++timo == 20000)
! 1468: goto out;
! 1469: DELAY(1);
! 1470: }
! 1471: DELAY(50000); /* XXX why is this needed ???? */
! 1472: while ((dcm->dcm_iir & IIR_SELFT) == 0) {
! 1473: if (++timo == 400000)
! 1474: goto out;
! 1475: DELAY(1);
! 1476: }
! 1477: DELAY(50000); /* XXX why is this needed ???? */
! 1478: if (dcm->dcm_stcon != ST_OK) {
! 1479: #if 0
! 1480: if (hd->hp_args->hw_sc != conscode)
! 1481: printf("dcm%d: self test failed: %x\n",
! 1482: brd, dcm->dcm_stcon);
! 1483: #endif
! 1484: goto out;
! 1485: }
! 1486: dcm->dcm_ic = IC_ID;
! 1487: rv = 0;
! 1488:
! 1489: out:
! 1490: splx(s);
! 1491: return (rv);
! 1492: }
! 1493:
! 1494: /*
! 1495: * Following are all routines needed for DCM to act as console
! 1496: */
! 1497:
! 1498: int
! 1499: dcm_console_scan(scode, va, arg)
! 1500: int scode;
! 1501: caddr_t va;
! 1502: void *arg;
! 1503: {
! 1504: struct dcmdevice *dcm = (struct dcmdevice *)va;
! 1505: struct consdev *cp = arg;
! 1506: u_int pri;
! 1507:
! 1508: switch (dcm->dcm_rsid) {
! 1509: case DCMID:
! 1510: pri = CN_NORMAL;
! 1511: break;
! 1512:
! 1513: case DCMID|DCMCON:
! 1514: pri = CN_REMOTE;
! 1515: break;
! 1516:
! 1517: default:
! 1518: return (0);
! 1519: }
! 1520:
! 1521: #ifdef CONSCODE
! 1522: /*
! 1523: * Raise our priority, if appropriate.
! 1524: */
! 1525: if (scode == CONSCODE)
! 1526: pri = CN_FORCED;
! 1527: #endif
! 1528:
! 1529: /* Only raise priority. */
! 1530: if (pri > cp->cn_pri)
! 1531: cp->cn_pri = pri;
! 1532:
! 1533: /*
! 1534: * If our priority is higher than the currently-remembered
! 1535: * console, stash our priority, for the benefit of dcmcninit().
! 1536: */
! 1537: if (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri) {
! 1538: cn_tab = cp;
! 1539: conscode = scode;
! 1540: return (DIO_SIZE(scode, va));
! 1541: }
! 1542: return (0);
! 1543: }
! 1544:
! 1545: void
! 1546: dcmcnprobe(cp)
! 1547: struct consdev *cp;
! 1548: {
! 1549:
! 1550: /* locate the major number */
! 1551: for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++)
! 1552: if (cdevsw[dcmmajor].d_open == dcmopen)
! 1553: break;
! 1554:
! 1555: /* initialize required fields */
! 1556: cp->cn_dev = makedev(dcmmajor, 0); /* XXX */
! 1557:
! 1558: console_scan(dcm_console_scan, cp);
! 1559:
! 1560: #ifdef KGDB_CHEAT
! 1561: /* XXX this needs to be fixed. */
! 1562: /*
! 1563: * This doesn't currently work, at least not with ite consoles;
! 1564: * the console hasn't been initialized yet.
! 1565: */
! 1566: if (major(kgdb_dev) == dcmmajor &&
! 1567: DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) {
! 1568: dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate);
! 1569: if (kgdb_debug_init) {
! 1570: /*
! 1571: * We assume that console is ready for us...
! 1572: * this assumes that a dca or ite console
! 1573: * has been selected already and will init
! 1574: * on the first putc.
! 1575: */
! 1576: printf("dcm%d: ", DCMUNIT(kgdb_dev));
! 1577: kgdb_connect(1);
! 1578: }
! 1579: }
! 1580: #endif
! 1581: }
! 1582:
! 1583: /* ARGSUSED */
! 1584: void
! 1585: dcmcninit(cp)
! 1586: struct consdev *cp;
! 1587: {
! 1588:
! 1589: /*
! 1590: * We are not interested by the second console pass.
! 1591: */
! 1592: if (consolepass != 0)
! 1593: return;
! 1594:
! 1595: dcm_cn = (struct dcmdevice *)conaddr;
! 1596: dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
! 1597: dcmconsinit = 1;
! 1598: }
! 1599:
! 1600: /* ARGSUSED */
! 1601: int
! 1602: dcmcngetc(dev)
! 1603: dev_t dev;
! 1604: {
! 1605: struct dcmrfifo *fifo;
! 1606: struct dcmpreg *pp;
! 1607: u_int head;
! 1608: int s, c, stat;
! 1609:
! 1610: pp = dcm_preg(dcm_cn, DCMCONSPORT);
! 1611:
! 1612: s = splhigh();
! 1613: head = pp->r_head & RX_MASK;
! 1614: fifo = &dcm_cn->dcm_rfifos[3-DCMCONSPORT][head>>1];
! 1615: while (head == (pp->r_tail & RX_MASK))
! 1616: ;
! 1617: /*
! 1618: * If board interrupts are enabled, just let our received char
! 1619: * interrupt through in case some other port on the board was
! 1620: * busy. Otherwise we must clear the interrupt.
! 1621: */
! 1622: SEM_LOCK(dcm_cn);
! 1623: if ((dcm_cn->dcm_ic & IC_IE) == 0)
! 1624: stat = dcm_cn->dcm_iir;
! 1625: SEM_UNLOCK(dcm_cn);
! 1626: c = fifo->data_char;
! 1627: stat = fifo->data_stat;
! 1628: pp->r_head = (head + 2) & RX_MASK;
! 1629: splx(s);
! 1630: return (c);
! 1631: }
! 1632:
! 1633: /*
! 1634: * Console kernel output character routine.
! 1635: */
! 1636: /* ARGSUSED */
! 1637: void
! 1638: dcmcnputc(dev, c)
! 1639: dev_t dev;
! 1640: int c;
! 1641: {
! 1642: struct dcmpreg *pp;
! 1643: unsigned tail;
! 1644: int s, stat;
! 1645:
! 1646: pp = dcm_preg(dcm_cn, DCMCONSPORT);
! 1647:
! 1648: s = splhigh();
! 1649: #ifdef KGDB
! 1650: if (dev != kgdb_dev)
! 1651: #endif
! 1652: if (dcmconsinit == 0) {
! 1653: dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
! 1654: dcmconsinit = 1;
! 1655: }
! 1656: tail = pp->t_tail & TX_MASK;
! 1657: while (tail != (pp->t_head & TX_MASK))
! 1658: ;
! 1659: dcm_cn->dcm_tfifos[3-DCMCONSPORT][tail].data_char = c;
! 1660: pp->t_tail = tail = (tail + 1) & TX_MASK;
! 1661: SEM_LOCK(dcm_cn);
! 1662: dcm_cn->dcm_cmdtab[DCMCONSPORT].dcm_data |= CT_TX;
! 1663: dcm_cn->dcm_cr |= (1 << DCMCONSPORT);
! 1664: SEM_UNLOCK(dcm_cn);
! 1665: while (tail != (pp->t_head & TX_MASK))
! 1666: ;
! 1667: /*
! 1668: * If board interrupts are enabled, just let our completion
! 1669: * interrupt through in case some other port on the board
! 1670: * was busy. Otherwise we must clear the interrupt.
! 1671: */
! 1672: if ((dcm_cn->dcm_ic & IC_IE) == 0) {
! 1673: SEM_LOCK(dcm_cn);
! 1674: stat = dcm_cn->dcm_iir;
! 1675: SEM_UNLOCK(dcm_cn);
! 1676: }
! 1677: splx(s);
! 1678: }
CVSweb