Annotation of sys/arch/hp300/dev/dca.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: dca.c,v 1.31 2006/01/01 11:59:37 miod Exp $ */
! 2: /* $NetBSD: dca.c,v 1.35 1997/05/05 20:58:18 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1995, 1996, 1997 Jason R. Thorpe. All rights reserved.
! 6: * Copyright (c) 1982, 1986, 1990, 1993
! 7: * The Regents of the University of California. All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: *
! 33: * @(#)dca.c 8.2 (Berkeley) 1/12/94
! 34: */
! 35:
! 36: /*
! 37: * Driver for the 98626/98644/internal serial interface on hp300/hp400,
! 38: * based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs.
! 39: *
! 40: * N.B. On the hp700 and some hp300s, there is a "secret bit" with
! 41: * undocumented behavior. The third bit of the Modem Control Register
! 42: * (MCR_IEN == 0x08) must be set to enable interrupts. Failure to do
! 43: * so can result in deadlock on those machines, whereas the don't seem to
! 44: * be any harmful side-effects from setting this bit on non-affected
! 45: * machines.
! 46: */
! 47:
! 48: #include <sys/param.h>
! 49: #include <sys/systm.h>
! 50: #include <sys/ioctl.h>
! 51: #include <sys/proc.h>
! 52: #include <sys/tty.h>
! 53: #include <sys/conf.h>
! 54: #include <sys/file.h>
! 55: #include <sys/uio.h>
! 56: #include <sys/kernel.h>
! 57: #include <sys/syslog.h>
! 58: #include <sys/device.h>
! 59:
! 60: #include <machine/autoconf.h>
! 61: #include <machine/bus.h>
! 62: #include <machine/cpu.h>
! 63: #include <machine/intr.h>
! 64:
! 65: #include <dev/cons.h>
! 66:
! 67: #include <hp300/dev/dioreg.h>
! 68: #include <hp300/dev/diovar.h>
! 69: #include <hp300/dev/diodevs.h>
! 70: #include <hp300/dev/dcareg.h>
! 71:
! 72: #ifdef DDB
! 73: #include <ddb/db_var.h>
! 74: #endif
! 75:
! 76: struct dca_softc {
! 77: struct device sc_dev; /* generic device glue */
! 78: struct isr sc_isr;
! 79: struct dcadevice *sc_dca; /* pointer to hardware */
! 80: struct tty *sc_tty; /* our tty instance */
! 81: int sc_oflows; /* overflow counter */
! 82: short sc_flags; /* state flags */
! 83: u_char sc_cua; /* callout mode */
! 84:
! 85: /*
! 86: * Bits for sc_flags.
! 87: */
! 88: #define DCA_ACTIVE 0x0001 /* indicates live unit */
! 89: #define DCA_SOFTCAR 0x0002 /* indicates soft-carrier */
! 90: #define DCA_HASFIFO 0x0004 /* indicates unit has FIFO */
! 91: #define DCA_ISCONSOLE 0x0008 /* indicates unit is console */
! 92:
! 93: };
! 94:
! 95: int dcamatch(struct device *, void *, void *);
! 96: void dcaattach(struct device *, struct device *, void *);
! 97:
! 98: struct cfattach dca_ca = {
! 99: sizeof(struct dca_softc), dcamatch, dcaattach
! 100: };
! 101:
! 102: struct cfdriver dca_cd = {
! 103: NULL, "dca", DV_TTY
! 104: };
! 105:
! 106: int dcadefaultrate = TTYDEF_SPEED;
! 107: int dcamajor;
! 108:
! 109: cdev_decl(dca);
! 110:
! 111: int dcaintr(void *);
! 112: void dcaeint(struct dca_softc *, int);
! 113: void dcamint(struct dca_softc *);
! 114:
! 115: int dcaparam(struct tty *, struct termios *);
! 116: void dcastart(struct tty *);
! 117: int dcastop(struct tty *, int);
! 118: int dcamctl(struct dca_softc *, int, int);
! 119: void dcainit(struct dcadevice *, int);
! 120:
! 121: int dca_console_scan(int, caddr_t, void *);
! 122: cons_decl(dca);
! 123:
! 124: /*
! 125: * Stuff for DCA console support.
! 126: */
! 127: static struct dcadevice *dca_cn = NULL; /* pointer to hardware */
! 128: static int dcaconsinit; /* has been initialized */
! 129:
! 130: const struct speedtab dcaspeedtab[] = {
! 131: { 0, 0 },
! 132: { 50, DCABRD(50) },
! 133: { 75, DCABRD(75) },
! 134: { 110, DCABRD(110) },
! 135: { 134, DCABRD(134) },
! 136: { 150, DCABRD(150) },
! 137: { 200, DCABRD(200) },
! 138: { 300, DCABRD(300) },
! 139: { 600, DCABRD(600) },
! 140: { 1200, DCABRD(1200) },
! 141: { 1800, DCABRD(1800) },
! 142: { 2400, DCABRD(2400) },
! 143: { 4800, DCABRD(4800) },
! 144: { 9600, DCABRD(9600) },
! 145: { 19200, DCABRD(19200) },
! 146: { 38400, DCABRD(38400) },
! 147: { -1, -1 },
! 148: };
! 149:
! 150: #ifdef KGDB
! 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 DCAUNIT(x) (minor(x) & 0x7f)
! 159: #define DCACUA(x) (minor(x) & 0x80)
! 160:
! 161: #ifdef DEBUG
! 162: long fifoin[17];
! 163: long fifoout[17];
! 164: long dcaintrcount[16];
! 165: long dcamintcount[16];
! 166: #endif
! 167:
! 168: void dcainit(struct dcadevice *, int);
! 169:
! 170: int
! 171: dcamatch(parent, match, aux)
! 172: struct device *parent;
! 173: void *match, *aux;
! 174: {
! 175: struct dio_attach_args *da = aux;
! 176:
! 177: switch (da->da_id) {
! 178: case DIO_DEVICE_ID_DCA0:
! 179: case DIO_DEVICE_ID_DCA0REM:
! 180: case DIO_DEVICE_ID_DCA1:
! 181: case DIO_DEVICE_ID_DCA1REM:
! 182: return (1);
! 183: }
! 184:
! 185: return (0);
! 186: }
! 187:
! 188: void
! 189: dcaattach(parent, self, aux)
! 190: struct device *parent, *self;
! 191: void *aux;
! 192: {
! 193: struct dca_softc *sc = (struct dca_softc *)self;
! 194: struct dio_attach_args *da = aux;
! 195: struct dcadevice *dca;
! 196: int unit = self->dv_unit;
! 197: int scode = da->da_scode;
! 198: int ipl;
! 199:
! 200: if (scode == conscode) {
! 201: dca = (struct dcadevice *)conaddr;
! 202: sc->sc_flags |= DCA_ISCONSOLE;
! 203: DELAY(100000);
! 204:
! 205: /*
! 206: * We didn't know which unit this would be during
! 207: * the console probe, so we have to fixup cn_dev here.
! 208: */
! 209: cn_tab->cn_dev = makedev(dcamajor, unit);
! 210: } else {
! 211: dca = (struct dcadevice *)iomap(dio_scodetopa(da->da_scode),
! 212: da->da_size);
! 213: if (dca == NULL) {
! 214: printf("\n%s: can't map registers\n",
! 215: sc->sc_dev.dv_xname);
! 216: return;
! 217: }
! 218: }
! 219:
! 220: sc->sc_dca = dca;
! 221:
! 222: ipl = DIO_IPL(dca);
! 223: printf(" ipl %d", ipl);
! 224:
! 225: dca->dca_reset = 0xFF;
! 226: DELAY(100);
! 227:
! 228: /* look for a NS 16550AF UART with FIFOs */
! 229: dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
! 230: DELAY(100);
! 231: if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
! 232: sc->sc_flags |= DCA_HASFIFO;
! 233:
! 234: /* Establish interrupt handler. */
! 235: sc->sc_isr.isr_func = dcaintr;
! 236: sc->sc_isr.isr_arg = sc;
! 237: sc->sc_isr.isr_ipl = ipl;
! 238: sc->sc_isr.isr_priority =
! 239: (sc->sc_flags & DCA_HASFIFO) ? IPL_TTY : IPL_TTYNOBUF;
! 240: dio_intr_establish(&sc->sc_isr, self->dv_xname);
! 241:
! 242: sc->sc_flags |= DCA_ACTIVE;
! 243: if (self->dv_cfdata->cf_flags)
! 244: sc->sc_flags |= DCA_SOFTCAR;
! 245:
! 246: /* Enable interrupts. */
! 247: dca->dca_ic = IC_IE;
! 248:
! 249: /*
! 250: * Need to reset baud rate, etc. of next print so reset dcaconsinit.
! 251: * Also make sure console is always "hardwired."
! 252: */
! 253: if (sc->sc_flags & DCA_ISCONSOLE) {
! 254: dcaconsinit = 0;
! 255: sc->sc_flags |= DCA_SOFTCAR;
! 256: printf(": console, ");
! 257: } else
! 258: printf(": ");
! 259:
! 260: if (sc->sc_flags & DCA_HASFIFO)
! 261: printf("working fifo\n");
! 262: else
! 263: printf("no fifo\n");
! 264:
! 265: #ifdef KGDB
! 266: if (kgdb_dev == makedev(dcamajor, unit)) {
! 267: if (sc->sc_flags & DCA_ISCONSOLE)
! 268: kgdb_dev = NODEV; /* can't debug over console port */
! 269: else {
! 270: dcainit(dca, kgdb_rate);
! 271: dcaconsinit = 1; /* don't re-init in dcaputc */
! 272: if (kgdb_debug_init) {
! 273: /*
! 274: * Print prefix of device name,
! 275: * let kgdb_connect print the rest.
! 276: */
! 277: printf("%s: ", sc->sc_dev.dv_xname);
! 278: kgdb_connect(1);
! 279: } else
! 280: printf("%s: kgdb enabled\n",
! 281: sc->sc_dev.dv_xname);
! 282: }
! 283: }
! 284: #endif
! 285: }
! 286:
! 287: /* ARGSUSED */
! 288: int
! 289: dcaopen(dev, flag, mode, p)
! 290: dev_t dev;
! 291: int flag, mode;
! 292: struct proc *p;
! 293: {
! 294: int unit = DCAUNIT(dev);
! 295: struct dca_softc *sc;
! 296: struct tty *tp;
! 297: struct dcadevice *dca;
! 298: u_char code;
! 299: int s, error = 0;
! 300:
! 301: if (unit >= dca_cd.cd_ndevs ||
! 302: (sc = dca_cd.cd_devs[unit]) == NULL)
! 303: return (ENXIO);
! 304:
! 305: if ((sc->sc_flags & DCA_ACTIVE) == 0)
! 306: return (ENXIO);
! 307:
! 308: dca = sc->sc_dca;
! 309:
! 310: s = spltty();
! 311: if (sc->sc_tty == NULL) {
! 312: tp = sc->sc_tty = ttymalloc();
! 313: } else
! 314: tp = sc->sc_tty;
! 315: splx(s);
! 316:
! 317: tp->t_oproc = dcastart;
! 318: tp->t_param = dcaparam;
! 319: tp->t_dev = dev;
! 320:
! 321: if ((tp->t_state & TS_ISOPEN) == 0) {
! 322: /*
! 323: * Sanity clause: reset the card on first open.
! 324: * The card might be left in an inconsistent state
! 325: * if card memory is read inadvertently.
! 326: */
! 327: dcainit(dca, dcadefaultrate);
! 328:
! 329: tp->t_state |= TS_WOPEN;
! 330: ttychars(tp);
! 331: tp->t_iflag = TTYDEF_IFLAG;
! 332: tp->t_oflag = TTYDEF_OFLAG;
! 333: tp->t_cflag = TTYDEF_CFLAG;
! 334: tp->t_lflag = TTYDEF_LFLAG;
! 335: tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
! 336:
! 337: s = spltty();
! 338:
! 339: dcaparam(tp, &tp->t_termios);
! 340: ttsetwater(tp);
! 341:
! 342: /* Set the FIFO threshold based on the receive speed. */
! 343: if (sc->sc_flags & DCA_HASFIFO)
! 344: dca->dca_fifo = FIFO_ENABLE | FIFO_RCV_RST |
! 345: FIFO_XMT_RST |
! 346: (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 :
! 347: FIFO_TRIGGER_14);
! 348:
! 349: /* Flush any pending I/O */
! 350: while ((dca->dca_iir & IIR_IMASK) == IIR_RXRDY)
! 351: code = dca->dca_data;
! 352:
! 353: } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
! 354: return (EBUSY);
! 355: else
! 356: s = spltty();
! 357:
! 358: /* Set modem control state. */
! 359: (void) dcamctl(sc, MCR_DTR | MCR_RTS, DMSET);
! 360:
! 361: /* Set soft-carrier if so configured. */
! 362: if ((sc->sc_flags & DCA_SOFTCAR) || DCACUA(dev) ||
! 363: (dcamctl(sc, 0, DMGET) & MSR_DCD))
! 364: tp->t_state |= TS_CARR_ON;
! 365:
! 366: if (DCACUA(dev)) {
! 367: if (tp->t_state & TS_ISOPEN) {
! 368: /* Ah, but someone already is dialed in... */
! 369: splx(s);
! 370: return (EBUSY);
! 371: }
! 372: sc->sc_cua = 1; /* We go into CUA mode */
! 373: }
! 374:
! 375: /* Wait for carrier if necessary. */
! 376: if (flag & O_NONBLOCK) {
! 377: if (!DCACUA(dev) && sc->sc_cua) {
! 378: /* Opening TTY non-blocking... but the CUA is busy */
! 379: splx(s);
! 380: return (EBUSY);
! 381: }
! 382: } else {
! 383: while (sc->sc_cua ||
! 384: ((tp->t_cflag & CLOCAL) == 0 &&
! 385: (tp->t_state & TS_CARR_ON) == 0)) {
! 386: tp->t_state |= TS_WOPEN;
! 387: error = ttysleep(tp, (caddr_t)&tp->t_rawq,
! 388: TTIPRI | PCATCH, ttopen, 0);
! 389: if (!DCACUA(dev) && sc->sc_cua && error == EINTR)
! 390: continue;
! 391: if (error) {
! 392: if (DCACUA(dev))
! 393: sc->sc_cua = 0;
! 394: splx(s);
! 395: return (error);
! 396: }
! 397: if (!DCACUA(dev) && sc->sc_cua)
! 398: continue;
! 399: }
! 400: }
! 401: splx(s);
! 402:
! 403: if (error == 0)
! 404: error = (*linesw[tp->t_line].l_open)(dev, tp);
! 405:
! 406: return (error);
! 407: }
! 408:
! 409: /*ARGSUSED*/
! 410: int
! 411: dcaclose(dev, flag, mode, p)
! 412: dev_t dev;
! 413: int flag, mode;
! 414: struct proc *p;
! 415: {
! 416: struct dca_softc *sc;
! 417: struct tty *tp;
! 418: struct dcadevice *dca;
! 419: int unit;
! 420: int s;
! 421:
! 422: unit = DCAUNIT(dev);
! 423:
! 424: sc = dca_cd.cd_devs[unit];
! 425:
! 426: dca = sc->sc_dca;
! 427: tp = sc->sc_tty;
! 428: (*linesw[tp->t_line].l_close)(tp, flag);
! 429:
! 430: s = spltty();
! 431:
! 432: dca->dca_cfcr &= ~CFCR_SBREAK;
! 433: #ifdef KGDB
! 434: /* do not disable interrupts if debugging */
! 435: if (dev != kgdb_dev)
! 436: #endif
! 437: dca->dca_ier = 0;
! 438: if (tp->t_cflag & HUPCL && (sc->sc_flags & DCA_SOFTCAR) == 0) {
! 439: /* XXX perhaps only clear DTR */
! 440: (void) dcamctl(sc, 0, DMSET);
! 441: }
! 442: tp->t_state &= ~(TS_BUSY | TS_FLUSH);
! 443: sc->sc_cua = 0;
! 444: splx(s);
! 445: ttyclose(tp);
! 446: #if 0
! 447: ttyfree(tp);
! 448: sc->sc_tty = NULL;
! 449: #endif
! 450: return (0);
! 451: }
! 452:
! 453: int
! 454: dcaread(dev, uio, flag)
! 455: dev_t dev;
! 456: struct uio *uio;
! 457: int flag;
! 458: {
! 459: int unit = DCAUNIT(dev);
! 460: struct dca_softc *sc;
! 461: struct tty *tp;
! 462: int error, of;
! 463:
! 464: sc = dca_cd.cd_devs[unit];
! 465:
! 466: tp = sc->sc_tty;
! 467: of = sc->sc_oflows;
! 468: error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
! 469: /*
! 470: * XXX hardly a reasonable thing to do, but reporting overflows
! 471: * at interrupt time just exacerbates the problem.
! 472: */
! 473: if (sc->sc_oflows != of)
! 474: log(LOG_WARNING, "%s: silo overflow\n", sc->sc_dev.dv_xname);
! 475: return (error);
! 476: }
! 477:
! 478: int
! 479: dcawrite(dev, uio, flag)
! 480: dev_t dev;
! 481: struct uio *uio;
! 482: int flag;
! 483: {
! 484: struct dca_softc *sc = dca_cd.cd_devs[DCAUNIT(dev)];
! 485: struct tty *tp = sc->sc_tty;
! 486:
! 487: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 488: }
! 489:
! 490: struct tty *
! 491: dcatty(dev)
! 492: dev_t dev;
! 493: {
! 494: struct dca_softc *sc = dca_cd.cd_devs[DCAUNIT(dev)];
! 495:
! 496: return (sc->sc_tty);
! 497: }
! 498:
! 499: int
! 500: dcaintr(arg)
! 501: void *arg;
! 502: {
! 503: struct dca_softc *sc = arg;
! 504: #ifdef KGDB
! 505: int unit = sc->sc_dev.dv_unit;
! 506: #endif
! 507: struct dcadevice *dca = sc->sc_dca;
! 508: struct tty *tp = sc->sc_tty;
! 509: u_char code;
! 510: int iflowdone = 0;
! 511:
! 512: /*
! 513: * If interrupts aren't enabled, then the interrupt can't
! 514: * be for us.
! 515: */
! 516: if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
! 517: return (0);
! 518:
! 519: for (;;) {
! 520: code = dca->dca_iir;
! 521: #ifdef DEBUG
! 522: dcaintrcount[code & IIR_IMASK]++;
! 523: #endif
! 524:
! 525: switch (code & IIR_IMASK) {
! 526: case IIR_NOPEND:
! 527: return (1);
! 528: case IIR_RXTOUT:
! 529: case IIR_RXRDY:
! 530: /* do time-critical read in-line */
! 531: /*
! 532: * Process a received byte. Inline for speed...
! 533: */
! 534: #ifdef KGDB
! 535: #define RCVBYTE() \
! 536: code = dca->dca_data; \
! 537: if (tp != NULL) { \
! 538: if ((tp->t_state & TS_ISOPEN) == 0) { \
! 539: if (code == FRAME_END && \
! 540: kgdb_dev == makedev(dcamajor, unit)) \
! 541: kgdb_connect(0); /* trap into kgdb */ \
! 542: } else \
! 543: (*linesw[tp->t_line].l_rint)(code, tp) \
! 544: }
! 545: #else
! 546: #define RCVBYTE() \
! 547: code = dca->dca_data; \
! 548: if (tp != NULL && (tp->t_state & TS_ISOPEN) != 0) \
! 549: (*linesw[tp->t_line].l_rint)(code, tp)
! 550: #endif
! 551: RCVBYTE();
! 552: if (sc->sc_flags & DCA_HASFIFO) {
! 553: #ifdef DEBUG
! 554: int fifocnt = 1;
! 555: #endif
! 556: while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
! 557: if (code == LSR_RXRDY) {
! 558: RCVBYTE();
! 559: } else
! 560: dcaeint(sc, code);
! 561: #ifdef DEBUG
! 562: fifocnt++;
! 563: #endif
! 564: }
! 565: #ifdef DEBUG
! 566: if (fifocnt > 16)
! 567: fifoin[0]++;
! 568: else
! 569: fifoin[fifocnt]++;
! 570: #endif
! 571: }
! 572: if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) &&
! 573: tp->t_rawq.c_cc > TTYHOG/2) {
! 574: dca->dca_mcr &= ~MCR_RTS;
! 575: iflowdone = 1;
! 576: }
! 577: break;
! 578: case IIR_TXRDY:
! 579: if (tp != NULL) {
! 580: tp->t_state &=~ (TS_BUSY|TS_FLUSH);
! 581: if (tp->t_line)
! 582: (*linesw[tp->t_line].l_start)(tp);
! 583: else
! 584: dcastart(tp);
! 585: }
! 586: break;
! 587: case IIR_RLS:
! 588: dcaeint(sc, dca->dca_lsr);
! 589: break;
! 590: default:
! 591: if (code & IIR_NOPEND)
! 592: return (1);
! 593: log(LOG_WARNING, "%s: weird interrupt: 0x%x\n",
! 594: sc->sc_dev.dv_xname, code);
! 595: /* FALLTHROUGH */
! 596: case IIR_MLSC:
! 597: dcamint(sc);
! 598: break;
! 599: }
! 600: }
! 601: }
! 602:
! 603: void
! 604: dcaeint(sc, stat)
! 605: struct dca_softc *sc;
! 606: int stat;
! 607: {
! 608: struct tty *tp = sc->sc_tty;
! 609: struct dcadevice *dca = sc->sc_dca;
! 610: int c;
! 611:
! 612: c = dca->dca_data;
! 613:
! 614: #if defined(DDB) && !defined(KGDB)
! 615: if ((sc->sc_flags & DCA_ISCONSOLE) && db_console && (stat & LSR_BI)) {
! 616: Debugger();
! 617: return;
! 618: }
! 619: #endif
! 620:
! 621: if (tp == NULL)
! 622: return;
! 623:
! 624: if ((tp->t_state & TS_ISOPEN) == 0) {
! 625: #ifdef KGDB
! 626: /* we don't care about parity errors */
! 627: if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
! 628: kgdb_dev == makedev(dcamajor, sc->sc_hd->hp_unit) &&
! 629: c == FRAME_END)
! 630: kgdb_connect(0); /* trap into kgdb */
! 631: #endif
! 632: return;
! 633: }
! 634:
! 635: if (stat & (LSR_BI | LSR_FE))
! 636: c |= TTY_FE;
! 637: else if (stat & LSR_PE)
! 638: c |= TTY_PE;
! 639: else if (stat & LSR_OE)
! 640: sc->sc_oflows++;
! 641: (*linesw[tp->t_line].l_rint)(c, tp);
! 642: }
! 643:
! 644: void
! 645: dcamint(sc)
! 646: struct dca_softc *sc;
! 647: {
! 648: struct tty *tp = sc->sc_tty;
! 649: struct dcadevice *dca = sc->sc_dca;
! 650: u_char stat;
! 651:
! 652: stat = dca->dca_msr;
! 653: #ifdef DEBUG
! 654: dcamintcount[stat & 0xf]++;
! 655: #endif
! 656:
! 657: if (tp == NULL)
! 658: return;
! 659:
! 660: if ((stat & MSR_DDCD) &&
! 661: (sc->sc_flags & DCA_SOFTCAR) == 0) {
! 662: if (stat & MSR_DCD)
! 663: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
! 664: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
! 665: dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
! 666: }
! 667: /*
! 668: * CTS change.
! 669: * If doing HW output flow control start/stop output as appropriate.
! 670: */
! 671: if ((stat & MSR_DCTS) &&
! 672: (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
! 673: if (stat & MSR_CTS) {
! 674: tp->t_state &=~ TS_TTSTOP;
! 675: dcastart(tp);
! 676: } else {
! 677: tp->t_state |= TS_TTSTOP;
! 678: }
! 679: }
! 680: }
! 681:
! 682: int
! 683: dcaioctl(dev, cmd, data, flag, p)
! 684: dev_t dev;
! 685: u_long cmd;
! 686: caddr_t data;
! 687: int flag;
! 688: struct proc *p;
! 689: {
! 690: int unit = DCAUNIT(dev);
! 691: struct dca_softc *sc = dca_cd.cd_devs[unit];
! 692: struct tty *tp = sc->sc_tty;
! 693: struct dcadevice *dca = sc->sc_dca;
! 694: int error;
! 695:
! 696: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 697: if (error >= 0)
! 698: return (error);
! 699: error = ttioctl(tp, cmd, data, flag, p);
! 700: if (error >= 0)
! 701: return (error);
! 702:
! 703: switch (cmd) {
! 704: case TIOCSBRK:
! 705: dca->dca_cfcr |= CFCR_SBREAK;
! 706: break;
! 707:
! 708: case TIOCCBRK:
! 709: dca->dca_cfcr &= ~CFCR_SBREAK;
! 710: break;
! 711:
! 712: case TIOCSDTR:
! 713: (void) dcamctl(sc, MCR_DTR | MCR_RTS, DMBIS);
! 714: break;
! 715:
! 716: case TIOCCDTR:
! 717: (void) dcamctl(sc, MCR_DTR | MCR_RTS, DMBIC);
! 718: break;
! 719:
! 720: case TIOCMSET:
! 721: (void) dcamctl(sc, *(int *)data, DMSET);
! 722: break;
! 723:
! 724: case TIOCMBIS:
! 725: (void) dcamctl(sc, *(int *)data, DMBIS);
! 726: break;
! 727:
! 728: case TIOCMBIC:
! 729: (void) dcamctl(sc, *(int *)data, DMBIC);
! 730: break;
! 731:
! 732: case TIOCMGET:
! 733: *(int *)data = dcamctl(sc, 0, DMGET);
! 734: break;
! 735:
! 736: case TIOCGFLAGS: {
! 737: int bits = 0;
! 738:
! 739: if (sc->sc_flags & DCA_SOFTCAR)
! 740: bits |= TIOCFLAG_SOFTCAR;
! 741:
! 742: if (tp->t_cflag & CLOCAL)
! 743: bits |= TIOCFLAG_CLOCAL;
! 744:
! 745: *(int *)data = bits;
! 746: break;
! 747: }
! 748:
! 749: case TIOCSFLAGS: {
! 750: int userbits;
! 751:
! 752: error = suser(p, 0);
! 753: if (error)
! 754: return (EPERM);
! 755:
! 756: userbits = *(int *)data;
! 757:
! 758: if ((userbits & TIOCFLAG_SOFTCAR) ||
! 759: (sc->sc_flags & DCA_ISCONSOLE))
! 760: sc->sc_flags |= DCA_SOFTCAR;
! 761:
! 762: if (userbits & TIOCFLAG_CLOCAL)
! 763: tp->t_cflag |= CLOCAL;
! 764:
! 765: break;
! 766: }
! 767:
! 768: default:
! 769: return (ENOTTY);
! 770: }
! 771: return (0);
! 772: }
! 773:
! 774: int
! 775: dcaparam(tp, t)
! 776: struct tty *tp;
! 777: struct termios *t;
! 778: {
! 779: int unit = DCAUNIT(tp->t_dev);
! 780: struct dca_softc *sc = dca_cd.cd_devs[unit];
! 781: struct dcadevice *dca = sc->sc_dca;
! 782: int cfcr, cflag = t->c_cflag;
! 783: int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
! 784: int s;
! 785:
! 786: /* check requested parameters */
! 787: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
! 788: return (EINVAL);
! 789:
! 790: switch (cflag & CSIZE) {
! 791: case CS5:
! 792: cfcr = CFCR_5BITS;
! 793: break;
! 794:
! 795: case CS6:
! 796: cfcr = CFCR_6BITS;
! 797: break;
! 798:
! 799: case CS7:
! 800: cfcr = CFCR_7BITS;
! 801: break;
! 802:
! 803: case CS8:
! 804: default: /* XXX gcc whines about cfcr being unitialized... */
! 805: cfcr = CFCR_8BITS;
! 806: break;
! 807: }
! 808: if (cflag & PARENB) {
! 809: cfcr |= CFCR_PENAB;
! 810: if ((cflag & PARODD) == 0)
! 811: cfcr |= CFCR_PEVEN;
! 812: }
! 813: if (cflag & CSTOPB)
! 814: cfcr |= CFCR_STOPB;
! 815:
! 816: s = spltty();
! 817:
! 818: if (ospeed == 0)
! 819: (void) dcamctl(sc, 0, DMSET); /* hang up line */
! 820:
! 821: /*
! 822: * Set the FIFO threshold based on the receive speed, if we
! 823: * are changing it.
! 824: */
! 825: if (tp->t_ispeed != t->c_ispeed) {
! 826: if (sc->sc_flags & DCA_HASFIFO)
! 827: dca->dca_fifo = FIFO_ENABLE |
! 828: (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 :
! 829: FIFO_TRIGGER_14);
! 830: }
! 831:
! 832: if (ospeed != 0) {
! 833: dca->dca_cfcr |= CFCR_DLAB;
! 834: dca->dca_data = ospeed & 0xFF;
! 835: dca->dca_ier = ospeed >> 8;
! 836: dca->dca_cfcr = cfcr;
! 837: } else
! 838: dca->dca_cfcr = cfcr;
! 839:
! 840: /* and copy to tty */
! 841: tp->t_ispeed = t->c_ispeed;
! 842: tp->t_ospeed = t->c_ospeed;
! 843: tp->t_cflag = cflag;
! 844:
! 845: dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
! 846: dca->dca_mcr |= MCR_IEN;
! 847:
! 848: splx(s);
! 849: return (0);
! 850: }
! 851:
! 852: void
! 853: dcastart(tp)
! 854: struct tty *tp;
! 855: {
! 856: int s, c, unit = DCAUNIT(tp->t_dev);
! 857: struct dca_softc *sc = dca_cd.cd_devs[unit];
! 858: struct dcadevice *dca = sc->sc_dca;
! 859:
! 860: s = spltty();
! 861:
! 862: if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
! 863: goto out;
! 864: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 865: if (tp->t_state & TS_ASLEEP) {
! 866: tp->t_state &= ~TS_ASLEEP;
! 867: wakeup((caddr_t)&tp->t_outq);
! 868: }
! 869: if (tp->t_outq.c_cc == 0)
! 870: goto out;
! 871: selwakeup(&tp->t_wsel);
! 872: }
! 873: if (dca->dca_lsr & LSR_TXRDY) {
! 874: tp->t_state |= TS_BUSY;
! 875: if (sc->sc_flags & DCA_HASFIFO) {
! 876: for (c = 0; c < 16 && tp->t_outq.c_cc; ++c)
! 877: dca->dca_data = getc(&tp->t_outq);
! 878: #ifdef DEBUG
! 879: if (c > 16)
! 880: fifoout[0]++;
! 881: else
! 882: fifoout[c]++;
! 883: #endif
! 884: } else
! 885: dca->dca_data = getc(&tp->t_outq);
! 886: }
! 887:
! 888: out:
! 889: splx(s);
! 890: }
! 891:
! 892: /*
! 893: * Stop output on a line.
! 894: */
! 895: /*ARGSUSED*/
! 896: int
! 897: dcastop(tp, flag)
! 898: struct tty *tp;
! 899: int flag;
! 900: {
! 901: int s;
! 902:
! 903: s = spltty();
! 904: if (tp->t_state & TS_BUSY)
! 905: if ((tp->t_state & TS_TTSTOP) == 0)
! 906: tp->t_state |= TS_FLUSH;
! 907: splx(s);
! 908: return (0);
! 909: }
! 910:
! 911: int
! 912: dcamctl(sc, bits, how)
! 913: struct dca_softc *sc;
! 914: int bits, how;
! 915: {
! 916: struct dcadevice *dca = sc->sc_dca;
! 917: int s;
! 918:
! 919: /*
! 920: * Always make sure MCR_IEN is set (unless setting to 0)
! 921: */
! 922: #ifdef KGDB
! 923: if (how == DMSET && kgdb_dev == makedev(dcamajor, sc->sc_hd->hp_unit))
! 924: bits |= MCR_IEN;
! 925: else
! 926: #endif
! 927: if (how == DMBIS || (how == DMSET && bits))
! 928: bits |= MCR_IEN;
! 929: else if (how == DMBIC)
! 930: bits &= ~MCR_IEN;
! 931: s = spltty();
! 932:
! 933: switch (how) {
! 934: case DMSET:
! 935: dca->dca_mcr = bits;
! 936: break;
! 937:
! 938: case DMBIS:
! 939: dca->dca_mcr |= bits;
! 940: break;
! 941:
! 942: case DMBIC:
! 943: dca->dca_mcr &= ~bits;
! 944: break;
! 945:
! 946: case DMGET:
! 947: bits = dca->dca_msr;
! 948: break;
! 949: }
! 950: splx(s);
! 951: return (bits);
! 952: }
! 953:
! 954: void
! 955: dcainit(dca, rate)
! 956: struct dcadevice *dca;
! 957: int rate;
! 958: {
! 959: int s;
! 960: short stat;
! 961:
! 962: s = splhigh();
! 963:
! 964: dca->dca_reset = 0xFF;
! 965: DELAY(100);
! 966: dca->dca_ic = IC_IE;
! 967:
! 968: dca->dca_cfcr = CFCR_DLAB;
! 969: rate = ttspeedtab(rate, dcaspeedtab);
! 970: dca->dca_data = rate & 0xFF;
! 971: dca->dca_ier = rate >> 8;
! 972: dca->dca_cfcr = CFCR_8BITS;
! 973: dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
! 974: dca->dca_fifo =
! 975: FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1;
! 976: dca->dca_mcr = MCR_DTR | MCR_RTS;
! 977: DELAY(100);
! 978: stat = dca->dca_iir;
! 979: splx(s);
! 980: }
! 981:
! 982: /*
! 983: * Following are all routines needed for DCA to act as console
! 984: */
! 985:
! 986: int
! 987: dca_console_scan(scode, va, arg)
! 988: int scode;
! 989: caddr_t va;
! 990: void *arg;
! 991: {
! 992: struct dcadevice *dca = (struct dcadevice *)va;
! 993: struct consdev *cp = arg;
! 994: u_int pri;
! 995:
! 996: switch (dca->dca_id) {
! 997: case DCAID0:
! 998: case DCAID1:
! 999: pri = CN_NORMAL;
! 1000: break;
! 1001:
! 1002: case DCAID0 | DCACON:
! 1003: case DCAID1 | DCACON:
! 1004: pri = CN_REMOTE;
! 1005: break;
! 1006:
! 1007: default:
! 1008: return (0);
! 1009: }
! 1010:
! 1011: #ifdef CONSCODE
! 1012: /*
! 1013: * Raise our priority, if appropriate.
! 1014: */
! 1015: if (scode == CONSCODE)
! 1016: pri = CN_FORCED;
! 1017: #endif
! 1018:
! 1019: /* Only raise priority. */
! 1020: if (pri > cp->cn_pri)
! 1021: cp->cn_pri = pri;
! 1022:
! 1023: /*
! 1024: * If our priority is higher than the currently-remembered
! 1025: * console, stash our priority, for the benefit of dcacninit().
! 1026: */
! 1027: if (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri) {
! 1028: cn_tab = cp;
! 1029: conscode = scode;
! 1030: return (DIO_SIZE(scode, va));
! 1031: }
! 1032: return (0);
! 1033: }
! 1034:
! 1035: void
! 1036: dcacnprobe(cp)
! 1037: struct consdev *cp;
! 1038: {
! 1039:
! 1040: /* locate the major number */
! 1041: for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
! 1042: if (cdevsw[dcamajor].d_open == dcaopen)
! 1043: break;
! 1044:
! 1045: /* initialize required fields */
! 1046: cp->cn_dev = makedev(dcamajor, 0); /* XXX */
! 1047:
! 1048: console_scan(dca_console_scan, cp);
! 1049:
! 1050: #ifdef KGDB
! 1051: /* XXX this needs to be fixed. */
! 1052: if (major(kgdb_dev) == 1) /* XXX */
! 1053: kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
! 1054: #endif
! 1055: }
! 1056:
! 1057: /* ARGSUSED */
! 1058: void
! 1059: dcacninit(cp)
! 1060: struct consdev *cp;
! 1061: {
! 1062:
! 1063: /*
! 1064: * We are not interested by the second console pass.
! 1065: */
! 1066: if (consolepass != 0)
! 1067: return;
! 1068:
! 1069: dca_cn = (struct dcadevice *)conaddr;
! 1070: dcainit(dca_cn, dcadefaultrate);
! 1071: dcaconsinit = 1;
! 1072: }
! 1073:
! 1074: /* ARGSUSED */
! 1075: int
! 1076: dcacngetc(dev)
! 1077: dev_t dev;
! 1078: {
! 1079: u_char stat;
! 1080: int c, s;
! 1081:
! 1082: #ifdef lint
! 1083: stat = dev; if (stat) return (0);
! 1084: #endif
! 1085:
! 1086: s = splhigh();
! 1087: while (((stat = dca_cn->dca_lsr) & LSR_RXRDY) == 0)
! 1088: ;
! 1089: c = dca_cn->dca_data;
! 1090: stat = dca_cn->dca_iir;
! 1091: splx(s);
! 1092: return (c);
! 1093: }
! 1094:
! 1095: /*
! 1096: * Console kernel output character routine.
! 1097: */
! 1098: /* ARGSUSED */
! 1099: void
! 1100: dcacnputc(dev, c)
! 1101: dev_t dev;
! 1102: int c;
! 1103: {
! 1104: int timo;
! 1105: u_char stat;
! 1106: int s = splhigh();
! 1107:
! 1108: #ifdef lint
! 1109: stat = dev; if (stat) return;
! 1110: #endif
! 1111:
! 1112: if (dcaconsinit == 0) {
! 1113: dcainit(dca_cn, dcadefaultrate);
! 1114: dcaconsinit = 1;
! 1115: }
! 1116: /* wait for any pending transmission to finish */
! 1117: timo = 50000;
! 1118: while (((stat = dca_cn->dca_lsr) & LSR_TXRDY) == 0 && --timo)
! 1119: ;
! 1120: dca_cn->dca_data = c;
! 1121: /* wait for this transmission to complete */
! 1122: timo = 1500000;
! 1123: while (((stat = dca_cn->dca_lsr) & LSR_TXRDY) == 0 && --timo)
! 1124: ;
! 1125: /* clear any interrupts generated by this transmission */
! 1126: stat = dca_cn->dca_iir;
! 1127: splx(s);
! 1128: }
CVSweb