Annotation of sys/arch/hp300/dev/apci.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: apci.c,v 1.29 2007/01/06 20:09:12 miod Exp $ */
! 2: /* $NetBSD: apci.c,v 1.9 2000/11/02 00:35:05 eeh Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1996, 1997, 1999 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Copyright (c) 1997 Michael Smith. All rights reserved.
! 42: * Copyright (c) 1982, 1986, 1990, 1993
! 43: * The Regents of the University of California. All rights reserved.
! 44: *
! 45: * Redistribution and use in source and binary forms, with or without
! 46: * modification, are permitted provided that the following conditions
! 47: * are met:
! 48: * 1. Redistributions of source code must retain the above copyright
! 49: * notice, this list of conditions and the following disclaimer.
! 50: * 2. Redistributions in binary form must reproduce the above copyright
! 51: * notice, this list of conditions and the following disclaimer in the
! 52: * documentation and/or other materials provided with the distribution.
! 53: * 3. Neither the name of the University nor the names of its contributors
! 54: * may be used to endorse or promote products derived from this software
! 55: * without specific prior written permission.
! 56: *
! 57: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 58: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 59: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 60: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 61: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 62: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 63: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 64: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 65: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 66: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 67: * SUCH DAMAGE.
! 68: *
! 69: * @(#)dca.c 8.2 (Berkeley) 1/12/94
! 70: */
! 71:
! 72: /*
! 73: * Device driver for the APCI 8250-like UARTs found on the Apollo
! 74: * Utility Chip on HP 9000/400-series workstations.
! 75: *
! 76: * There are 4 APCI UARTs on the Frodo ASIC. The first one
! 77: * is used to communicate with the Domain keyboard. The second
! 78: * one is the serial console port when the firmware is in Domain/OS
! 79: * mode, and is mapped to select code 9 by the HP-UX firmware (except
! 80: * on 425e models).
! 81: *
! 82: * We don't bother attaching a tty to the first UART; it lacks modem/flow
! 83: * control, and is directly connected to the keyboard connector anyhow.
! 84: */
! 85:
! 86: /*
! 87: * XXX This driver is very similar to the dca driver, and much
! 88: * XXX more code could be shared. (Currently, no code is shared.)
! 89: * XXX FIXME!
! 90: */
! 91:
! 92: #include <sys/param.h>
! 93: #include <sys/systm.h>
! 94: #include <sys/ioctl.h>
! 95: #include <sys/proc.h>
! 96: #include <sys/tty.h>
! 97: #include <sys/conf.h>
! 98: #include <sys/file.h>
! 99: #include <sys/uio.h>
! 100: #include <sys/kernel.h>
! 101: #include <sys/syslog.h>
! 102: #include <sys/device.h>
! 103: #include <sys/timeout.h>
! 104:
! 105: #include <machine/autoconf.h>
! 106: #include <machine/bus.h>
! 107: #include <machine/cpu.h>
! 108: #include <machine/hp300spu.h>
! 109:
! 110: #include <dev/cons.h>
! 111:
! 112: #include <hp300/dev/dioreg.h> /* to check for dca at 9 */
! 113: #include <hp300/dev/diovar.h>
! 114: #include <hp300/dev/diodevs.h>
! 115:
! 116: #include <hp300/dev/frodoreg.h>
! 117: #include <hp300/dev/frodovar.h>
! 118: #include <hp300/dev/apcireg.h>
! 119: #include <hp300/dev/apcivar.h>
! 120: #include <hp300/dev/dcareg.h> /* register bit definitions */
! 121:
! 122: #ifdef DDB
! 123: #include <ddb/db_var.h>
! 124: #endif
! 125:
! 126: struct apci_softc {
! 127: struct device sc_dev; /* generic device glue */
! 128: struct isr sc_isr;
! 129: struct apciregs *sc_apci; /* device registers */
! 130: struct tty *sc_tty; /* tty glue */
! 131: struct timeout sc_timeout; /* timeout */
! 132: int sc_ferr,
! 133: sc_perr,
! 134: sc_oflow,
! 135: sc_toterr; /* stats */
! 136: int sc_flags;
! 137: u_char sc_cua; /* callout mode */
! 138: };
! 139:
! 140: /* sc_flags */
! 141: #define APCI_HASFIFO 0x01 /* unit has a fifo */
! 142: #define APCI_ISCONSOLE 0x02 /* unit is console */
! 143: #define APCI_SOFTCAR 0x04 /* soft carrier */
! 144:
! 145: int apcimatch(struct device *, void *, void *);
! 146: void apciattach(struct device *, struct device *, void *);
! 147:
! 148: struct cfattach apci_ca = {
! 149: sizeof(struct apci_softc), apcimatch, apciattach
! 150: };
! 151:
! 152: struct cfdriver apci_cd = {
! 153: NULL, "apci", DV_TTY
! 154: };
! 155:
! 156: int apciintr(void *);
! 157: void apcieint(struct apci_softc *, int);
! 158: void apcimint(struct apci_softc *, u_char);
! 159: int apciparam(struct tty *, struct termios *);
! 160: void apcistart(struct tty *);
! 161: int apcimctl(struct apci_softc *, int, int);
! 162: void apcitimeout(void *);
! 163:
! 164: cdev_decl(apci);
! 165:
! 166: #define APCIUNIT(x) (minor(x) & 0x7f)
! 167: #define APCICUA(x) (minor(x) & 0x80)
! 168:
! 169: int apcidefaultrate = TTYDEF_SPEED;
! 170:
! 171: /*
! 172: * Console support.
! 173: */
! 174: struct apciregs *apci_cn = NULL; /* console hardware */
! 175: int apciconsinit; /* has been initialized */
! 176: int apcimajor; /* our major number */
! 177:
! 178: cons_decl(apci);
! 179:
! 180: int
! 181: apcimatch(parent, match, aux)
! 182: struct device *parent;
! 183: void *match, *aux;
! 184: {
! 185: struct frodo_attach_args *fa = aux;
! 186:
! 187: /* Looking for an apci? */
! 188: if (strcmp(fa->fa_name, apci_cd.cd_name) != 0)
! 189: return (0);
! 190:
! 191: /* Are we checking a valid APCI offset? */
! 192: switch (fa->fa_offset) {
! 193: case FRODO_APCI_OFFSET(1):
! 194: case FRODO_APCI_OFFSET(2):
! 195: case FRODO_APCI_OFFSET(3):
! 196: /* Yup, we exist! */
! 197: return (1);
! 198: }
! 199:
! 200: return (0);
! 201: }
! 202:
! 203: void
! 204: apciattach(parent, self, aux)
! 205: struct device *parent, *self;
! 206: void *aux;
! 207: {
! 208: struct apci_softc *sc = (struct apci_softc *)self;
! 209: struct apciregs *apci;
! 210: struct frodo_attach_args *fa = aux;
! 211:
! 212: sc->sc_apci = apci =
! 213: (struct apciregs *)IIOV(FRODO_BASE + fa->fa_offset);
! 214: sc->sc_flags = 0;
! 215:
! 216: /* Initialize timeout structure */
! 217: timeout_set(&sc->sc_timeout, apcitimeout, sc);
! 218:
! 219: /* Are we the console? */
! 220: if (apci == apci_cn) {
! 221: sc->sc_flags |= APCI_ISCONSOLE;
! 222: delay(100000);
! 223:
! 224: /*
! 225: * We didn't know which unit this would be during
! 226: * the console probe, so we have to fixup cn_dev here.
! 227: */
! 228: cn_tab->cn_dev = makedev(apcimajor, self->dv_unit);
! 229: }
! 230:
! 231: /* Look for a FIFO. */
! 232: apci->ap_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
! 233: delay(100);
! 234: if ((apci->ap_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
! 235: sc->sc_flags |= APCI_HASFIFO;
! 236:
! 237: /* Establish our interrupt handler. */
! 238: sc->sc_isr.isr_func = apciintr;
! 239: sc->sc_isr.isr_arg = sc;
! 240: sc->sc_isr.isr_priority =
! 241: (sc->sc_flags & APCI_HASFIFO) ? IPL_TTY : IPL_TTYNOBUF;
! 242: frodo_intr_establish(parent, fa->fa_line, &sc->sc_isr, self->dv_xname);
! 243:
! 244: /* Set soft carrier if requested by operator. */
! 245: if (self->dv_cfdata->cf_flags)
! 246: sc->sc_flags |= APCI_SOFTCAR;
! 247:
! 248: /*
! 249: * Need to reset baud rate, etc. of next print, so reset apciconsinit.
! 250: * Also make sure console is always "hardwired".
! 251: */
! 252: if (sc->sc_flags & APCI_ISCONSOLE) {
! 253: apciconsinit = 0;
! 254: sc->sc_flags |= APCI_SOFTCAR;
! 255: printf(": console, ");
! 256: } else
! 257: printf(": ");
! 258:
! 259: if (sc->sc_flags & APCI_HASFIFO)
! 260: printf("working fifo\n");
! 261: else
! 262: printf("no fifo\n");
! 263: }
! 264:
! 265: /* ARGSUSED */
! 266: int
! 267: apciopen(dev, flag, mode, p)
! 268: dev_t dev;
! 269: int flag, mode;
! 270: struct proc *p;
! 271: {
! 272: int unit = APCIUNIT(dev);
! 273: struct apci_softc *sc;
! 274: struct tty *tp;
! 275: struct apciregs *apci;
! 276: u_char code;
! 277: int s, error = 0;
! 278:
! 279: if (unit >= apci_cd.cd_ndevs ||
! 280: (sc = apci_cd.cd_devs[unit]) == NULL)
! 281: return (ENXIO);
! 282:
! 283: apci = sc->sc_apci;
! 284:
! 285: s = spltty();
! 286: if (sc->sc_tty == NULL) {
! 287: tp = sc->sc_tty = ttymalloc();
! 288: } else
! 289: tp = sc->sc_tty;
! 290: splx(s);
! 291:
! 292: tp->t_oproc = apcistart;
! 293: tp->t_param = apciparam;
! 294: tp->t_dev = dev;
! 295:
! 296: if ((tp->t_state & TS_ISOPEN) == 0) {
! 297: /*
! 298: * Sanity clause: reset the chip on first open.
! 299: * The chip might be left in an inconsistent state
! 300: * if it is read inadventently.
! 301: */
! 302: apciinit(apci, apcidefaultrate, CFCR_8BITS);
! 303:
! 304: tp->t_state |= TS_WOPEN;
! 305: ttychars(tp);
! 306: tp->t_iflag = TTYDEF_IFLAG;
! 307: tp->t_oflag = TTYDEF_OFLAG;
! 308: tp->t_cflag = TTYDEF_CFLAG;
! 309: tp->t_lflag = TTYDEF_LFLAG;
! 310: tp->t_ispeed = tp->t_ospeed = apcidefaultrate;
! 311:
! 312: s = spltty();
! 313:
! 314: apciparam(tp, &tp->t_termios);
! 315: ttsetwater(tp);
! 316:
! 317: /* Set the FIFO threshold based on the receive speed. */
! 318: if (sc->sc_flags & APCI_HASFIFO)
! 319: apci->ap_fifo = FIFO_ENABLE | FIFO_RCV_RST |
! 320: FIFO_XMT_RST |
! 321: (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 :
! 322: FIFO_TRIGGER_14);
! 323:
! 324: /* Flush any pending I/O. */
! 325: while ((apci->ap_iir & IIR_IMASK) == IIR_RXRDY)
! 326: code = apci->ap_data;
! 327: } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
! 328: return (EBUSY);
! 329: else
! 330: s = spltty();
! 331:
! 332: /* Set the modem control state. */
! 333: (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMSET);
! 334:
! 335: /* Set soft-carrier if so configured. */
! 336: if ((sc->sc_flags & APCI_SOFTCAR) || APCICUA(dev) ||
! 337: (apcimctl(sc, 0, DMGET) & MSR_DCD))
! 338: tp->t_state |= TS_CARR_ON;
! 339:
! 340: if (APCICUA(dev)) {
! 341: if (tp->t_state & TS_ISOPEN) {
! 342: /* Ah, but someone already is dialed in... */
! 343: splx(s);
! 344: return (EBUSY);
! 345: }
! 346: sc->sc_cua = 1; /* We go into CUA mode */
! 347: }
! 348:
! 349: /* Wait for carrier if necessary. */
! 350: if (flag & O_NONBLOCK) {
! 351: if (!APCICUA(dev) && sc->sc_cua) {
! 352: /* Opening TTY non-blocking... but the CUA is busy */
! 353: splx(s);
! 354: return (EBUSY);
! 355: }
! 356: } else {
! 357: while (sc->sc_cua ||
! 358: ((tp->t_cflag & CLOCAL) == 0 &&
! 359: (tp->t_state & TS_CARR_ON) == 0)) {
! 360: tp->t_state |= TS_WOPEN;
! 361: error = ttysleep(tp, (caddr_t)&tp->t_rawq,
! 362: TTIPRI | PCATCH, ttopen, 0);
! 363: if (!APCICUA(dev) && sc->sc_cua && error == EINTR)
! 364: continue;
! 365: if (error) {
! 366: if (APCICUA(dev))
! 367: sc->sc_cua = 0;
! 368: splx(s);
! 369: return (error);
! 370: }
! 371: if (!APCICUA(dev) && sc->sc_cua)
! 372: continue;
! 373: }
! 374: }
! 375:
! 376: splx(s);
! 377:
! 378: if (error == 0)
! 379: error = (*linesw[tp->t_line].l_open)(dev, tp);
! 380:
! 381: if (error == 0) {
! 382: /* clear errors, start timeout */
! 383: sc->sc_ferr = sc->sc_perr = sc->sc_oflow = sc->sc_toterr = 0;
! 384: timeout_add(&sc->sc_timeout, hz);
! 385: }
! 386:
! 387: return (error);
! 388: }
! 389:
! 390: /* ARGSUSED */
! 391: int
! 392: apciclose(dev, flag, mode, p)
! 393: dev_t dev;
! 394: int flag, mode;
! 395: struct proc *p;
! 396: {
! 397: struct apci_softc *sc;
! 398: struct tty *tp;
! 399: struct apciregs *apci;
! 400: int unit = APCIUNIT(dev);
! 401: int s;
! 402:
! 403: sc = apci_cd.cd_devs[unit];
! 404: apci = sc->sc_apci;
! 405: tp = sc->sc_tty;
! 406:
! 407: (*linesw[tp->t_line].l_close)(tp, flag);
! 408:
! 409: s = spltty();
! 410:
! 411: apci->ap_cfcr &= ~CFCR_SBREAK;
! 412: apci->ap_ier = 0;
! 413: if (tp->t_cflag & HUPCL && (sc->sc_flags & APCI_SOFTCAR) == 0) {
! 414: /* XXX perhaps only clear DTR */
! 415: (void) apcimctl(sc, 0, DMSET);
! 416: }
! 417: tp->t_state &= ~(TS_BUSY | TS_FLUSH);
! 418: sc->sc_cua = 0;
! 419: splx(s);
! 420: ttyclose(tp);
! 421: #if 0
! 422: ttyfree(tp);
! 423: sc->sc_tty = NULL;
! 424: #endif
! 425: return (0);
! 426: }
! 427:
! 428: int
! 429: apciread(dev, uio, flag)
! 430: dev_t dev;
! 431: struct uio *uio;
! 432: int flag;
! 433: {
! 434: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
! 435: struct tty *tp = sc->sc_tty;
! 436:
! 437: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
! 438: }
! 439:
! 440: int
! 441: apciwrite(dev, uio, flag)
! 442: dev_t dev;
! 443: struct uio *uio;
! 444: int flag;
! 445: {
! 446: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
! 447: struct tty *tp = sc->sc_tty;
! 448:
! 449: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 450: }
! 451:
! 452: struct tty *
! 453: apcitty(dev)
! 454: dev_t dev;
! 455: {
! 456: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
! 457:
! 458: return (sc->sc_tty);
! 459: }
! 460:
! 461: int
! 462: apciintr(arg)
! 463: void *arg;
! 464: {
! 465: struct apci_softc *sc = arg;
! 466: struct apciregs *apci = sc->sc_apci;
! 467: struct tty *tp = sc->sc_tty;
! 468: u_char iir, lsr, c;
! 469: int iflowdone = 0, claimed = 0;
! 470:
! 471: #define RCVBYTE() \
! 472: c = apci->ap_data; \
! 473: if (tp != NULL && (tp->t_state & TS_ISOPEN) != 0) \
! 474: (*linesw[tp->t_line].l_rint)(c, tp)
! 475:
! 476: for (;;) {
! 477: iir = apci->ap_iir; /* get UART status */
! 478:
! 479: switch (iir & IIR_IMASK) {
! 480: case IIR_RLS:
! 481: apcieint(sc, apci->ap_lsr);
! 482: break;
! 483:
! 484: case IIR_RXRDY:
! 485: case IIR_RXTOUT:
! 486: RCVBYTE();
! 487: if (sc->sc_flags & APCI_HASFIFO) {
! 488: while ((lsr = apci->ap_lsr) & LSR_RCV_MASK) {
! 489: if (lsr == LSR_RXRDY) {
! 490: RCVBYTE();
! 491: } else
! 492: apcieint(sc, lsr);
! 493: }
! 494: }
! 495: if (iflowdone == 0 && tp != NULL &&
! 496: (tp->t_cflag & CRTS_IFLOW) &&
! 497: tp->t_rawq.c_cc > (TTYHOG / 2)) {
! 498: apci->ap_mcr &= ~MCR_RTS;
! 499: iflowdone = 1;
! 500: }
! 501: break;
! 502:
! 503: case IIR_TXRDY:
! 504: if (tp != NULL) {
! 505: tp->t_state &=~ (TS_BUSY|TS_FLUSH);
! 506: if (tp->t_line)
! 507: (*linesw[tp->t_line].l_start)(tp);
! 508: else
! 509: apcistart(tp);
! 510: }
! 511: break;
! 512:
! 513: default:
! 514: if (iir & IIR_NOPEND)
! 515: return (claimed);
! 516: log(LOG_WARNING, "%s: weird interrupt: 0x%x\n",
! 517: sc->sc_dev.dv_xname, iir);
! 518: /* FALLTHROUGH */
! 519:
! 520: case IIR_MLSC:
! 521: apcimint(sc, apci->ap_msr);
! 522: break;
! 523: }
! 524:
! 525: claimed = 1;
! 526: }
! 527: }
! 528:
! 529: void
! 530: apcieint(sc, stat)
! 531: struct apci_softc *sc;
! 532: int stat;
! 533: {
! 534: struct tty *tp = sc->sc_tty;
! 535: struct apciregs *apci = sc->sc_apci;
! 536: int c;
! 537:
! 538: c = apci->ap_data;
! 539:
! 540: #ifdef DDB
! 541: if ((sc->sc_flags & APCI_ISCONSOLE) && db_console && (stat & LSR_BI)) {
! 542: Debugger();
! 543: return;
! 544: }
! 545: #endif
! 546:
! 547: if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
! 548: return;
! 549:
! 550: if (stat & (LSR_BI | LSR_FE)) {
! 551: c |= TTY_FE;
! 552: sc->sc_ferr++;
! 553: } else if (stat & LSR_PE) {
! 554: c |= TTY_PE;
! 555: sc->sc_perr++;
! 556: } else if (stat & LSR_OE)
! 557: sc->sc_oflow++;
! 558: (*linesw[tp->t_line].l_rint)(c, tp);
! 559: }
! 560:
! 561: void
! 562: apcimint(sc, stat)
! 563: struct apci_softc *sc;
! 564: u_char stat;
! 565: {
! 566: struct tty *tp = sc->sc_tty;
! 567: struct apciregs *apci = sc->sc_apci;
! 568:
! 569: if (tp == NULL)
! 570: return;
! 571:
! 572: if ((stat & MSR_DDCD) &&
! 573: (sc->sc_flags & APCI_SOFTCAR) == 0) {
! 574: if (stat & MSR_DCD)
! 575: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
! 576: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
! 577: apci->ap_mcr &= ~(MCR_DTR | MCR_RTS);
! 578: }
! 579:
! 580: /*
! 581: * CTS change.
! 582: * If doing HW output flow control, start/stop output as appropriate.
! 583: */
! 584: if ((stat & MSR_DCTS) &&
! 585: (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
! 586: if (stat & MSR_CTS) {
! 587: tp->t_state &=~ TS_TTSTOP;
! 588: apcistart(tp);
! 589: } else
! 590: tp->t_state |= TS_TTSTOP;
! 591: }
! 592: }
! 593:
! 594: int
! 595: apciioctl(dev, cmd, data, flag, p)
! 596: dev_t dev;
! 597: u_long cmd;
! 598: caddr_t data;
! 599: int flag;
! 600: struct proc *p;
! 601: {
! 602: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
! 603: struct tty *tp = sc->sc_tty;
! 604: struct apciregs *apci = sc->sc_apci;
! 605: int error;
! 606:
! 607: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 608: if (error >= 0)
! 609: return (error);
! 610: error = ttioctl(tp, cmd, data, flag, p);
! 611: if (error >= 0)
! 612: return (error);
! 613:
! 614: switch (cmd) {
! 615: case TIOCSBRK:
! 616: apci->ap_cfcr |= CFCR_SBREAK;
! 617: break;
! 618:
! 619: case TIOCCBRK:
! 620: apci->ap_cfcr &= ~CFCR_SBREAK;
! 621: break;
! 622:
! 623: case TIOCSDTR:
! 624: (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMBIS);
! 625: break;
! 626:
! 627: case TIOCCDTR:
! 628: (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMBIC);
! 629: break;
! 630:
! 631: case TIOCMSET:
! 632: (void) apcimctl(sc, *(int *)data, DMSET);
! 633: break;
! 634:
! 635: case TIOCMBIS:
! 636: (void) apcimctl(sc, *(int *)data, DMBIS);
! 637: break;
! 638:
! 639: case TIOCMBIC:
! 640: (void) apcimctl(sc, *(int *)data, DMBIC);
! 641: break;
! 642:
! 643: case TIOCMGET:
! 644: *(int *)data = apcimctl(sc, 0, DMGET);
! 645: break;
! 646:
! 647: case TIOCGFLAGS: {
! 648: int bits = 0;
! 649:
! 650: if (sc->sc_flags & APCI_SOFTCAR)
! 651: bits |= TIOCFLAG_SOFTCAR;
! 652:
! 653: if (tp->t_cflag & CLOCAL)
! 654: bits |= TIOCFLAG_CLOCAL;
! 655:
! 656: *(int *)data = bits;
! 657: break;
! 658: }
! 659:
! 660: case TIOCSFLAGS: {
! 661: int userbits;
! 662:
! 663: error = suser(p, 0);
! 664: if (error)
! 665: return (EPERM);
! 666:
! 667: userbits = *(int *)data;
! 668:
! 669: if ((userbits & TIOCFLAG_SOFTCAR) ||
! 670: (sc->sc_flags & APCI_ISCONSOLE))
! 671: sc->sc_flags |= APCI_SOFTCAR;
! 672:
! 673: if (userbits & TIOCFLAG_CLOCAL)
! 674: tp->t_cflag |= CLOCAL;
! 675:
! 676: break;
! 677: }
! 678:
! 679: default:
! 680: return (ENOTTY);
! 681: }
! 682: return (0);
! 683: }
! 684:
! 685: int
! 686: apciparam(tp, t)
! 687: struct tty *tp;
! 688: struct termios *t;
! 689: {
! 690: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(tp->t_dev)];
! 691: struct apciregs *apci = sc->sc_apci;
! 692: int cfcr, cflag = t->c_cflag;
! 693: int ospeed = ttspeedtab(t->c_ospeed, apcispeedtab);
! 694: int s;
! 695:
! 696: /* check requested parameters */
! 697: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
! 698: return (EINVAL);
! 699:
! 700: switch (cflag & CSIZE) {
! 701: case CS5:
! 702: cfcr = CFCR_5BITS;
! 703: break;
! 704:
! 705: case CS6:
! 706: cfcr = CFCR_6BITS;
! 707: break;
! 708:
! 709: case CS7:
! 710: cfcr = CFCR_7BITS;
! 711: break;
! 712:
! 713: case CS8:
! 714: default: /* XXX gcc whines about cfcr being uninitialized... */
! 715: cfcr = CFCR_8BITS;
! 716: break;
! 717: }
! 718: if (cflag & PARENB) {
! 719: cfcr |= CFCR_PENAB;
! 720: if ((cflag & PARODD) == 0)
! 721: cfcr |= CFCR_PEVEN;
! 722: }
! 723: if (cflag & CSTOPB)
! 724: cfcr |= CFCR_STOPB;
! 725:
! 726: s = spltty();
! 727:
! 728: if (ospeed == 0)
! 729: (void) apcimctl(sc, 0, DMSET); /* hang up line */
! 730:
! 731: /*
! 732: * Set the FIFO threshold based on the receive speed, if we
! 733: * are changing it.
! 734: */
! 735: if (tp->t_ispeed != t->c_ispeed) {
! 736: if (sc->sc_flags & APCI_HASFIFO)
! 737: apci->ap_fifo = FIFO_ENABLE |
! 738: (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 :
! 739: FIFO_TRIGGER_14);
! 740: }
! 741:
! 742: if (ospeed != 0) {
! 743: apci->ap_cfcr |= CFCR_DLAB;
! 744: apci->ap_data = ospeed & 0xff;
! 745: apci->ap_ier = (ospeed >> 8) & 0xff;
! 746: apci->ap_cfcr = cfcr;
! 747: } else
! 748: apci->ap_cfcr = cfcr;
! 749:
! 750: /* and copy to tty */
! 751: tp->t_ispeed = t->c_ispeed;
! 752: tp->t_ospeed = t->c_ospeed;
! 753: tp->t_cflag = cflag;
! 754:
! 755: apci->ap_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
! 756:
! 757: splx(s);
! 758: return (0);
! 759: }
! 760:
! 761: void
! 762: apcistart(tp)
! 763: struct tty *tp;
! 764: {
! 765: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(tp->t_dev)];
! 766: struct apciregs *apci = sc->sc_apci;
! 767: int s, c;
! 768:
! 769: s = spltty();
! 770:
! 771: if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
! 772: goto out;
! 773: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 774: if (tp->t_state & TS_ASLEEP) {
! 775: tp->t_state &= ~TS_ASLEEP;
! 776: wakeup((caddr_t)&tp->t_outq);
! 777: }
! 778: if (tp->t_outq.c_cc == 0)
! 779: goto out;
! 780: selwakeup(&tp->t_wsel);
! 781: }
! 782: if (apci->ap_lsr & LSR_TXRDY) {
! 783: tp->t_state |= TS_BUSY;
! 784: if (sc->sc_flags & APCI_HASFIFO) {
! 785: for (c = 0; c < 16 && tp->t_outq.c_cc; ++c)
! 786: apci->ap_data = getc(&tp->t_outq);
! 787: } else
! 788: apci->ap_data = getc(&tp->t_outq);
! 789: }
! 790:
! 791: out:
! 792: splx(s);
! 793: }
! 794:
! 795: /*
! 796: * Stop output on a line.
! 797: */
! 798: /* ARGSUSED */
! 799: int
! 800: apcistop(tp, flag)
! 801: struct tty *tp;
! 802: int flag;
! 803: {
! 804: int s;
! 805:
! 806: s = spltty();
! 807: if (tp->t_state & TS_BUSY)
! 808: if ((tp->t_state & TS_TTSTOP) == 0)
! 809: tp->t_state |= TS_FLUSH;
! 810: splx(s);
! 811: return (0);
! 812: }
! 813:
! 814: int
! 815: apcimctl(sc, bits, how)
! 816: struct apci_softc *sc;
! 817: int bits, how;
! 818: {
! 819: struct apciregs *apci = sc->sc_apci;
! 820: int s;
! 821:
! 822: s = spltty();
! 823:
! 824: switch (how) {
! 825: case DMSET:
! 826: apci->ap_mcr = bits;
! 827: break;
! 828:
! 829: case DMBIS:
! 830: apci->ap_mcr |= bits;
! 831: break;
! 832:
! 833: case DMBIC:
! 834: apci->ap_mcr &= ~bits;
! 835: break;
! 836:
! 837: case DMGET:
! 838: bits = apci->ap_msr;
! 839: break;
! 840: }
! 841:
! 842: splx(s);
! 843: return (bits);
! 844: }
! 845:
! 846: void
! 847: apcitimeout(arg)
! 848: void *arg;
! 849: {
! 850: struct apci_softc *sc = arg;
! 851: int ferr, perr, oflow, s;
! 852:
! 853: if (sc->sc_tty == NULL ||
! 854: (sc->sc_tty->t_state & TS_ISOPEN) == 0)
! 855: return;
! 856:
! 857: /* Log any errors. */
! 858: if (sc->sc_ferr || sc->sc_perr || sc->sc_oflow) {
! 859: s = spltty(); /* XXX necessary? */
! 860: ferr = sc->sc_ferr;
! 861: perr = sc->sc_perr;
! 862: oflow = sc->sc_oflow;
! 863: sc->sc_ferr = sc->sc_perr = sc->sc_oflow = 0;
! 864: splx(s);
! 865: sc->sc_toterr += ferr + perr + oflow;
! 866: log(LOG_WARNING,
! 867: "%s: %d frame, %d parity, %d overflow, %d total errors\n",
! 868: sc->sc_dev.dv_xname, ferr, perr, oflow, sc->sc_toterr);
! 869: }
! 870:
! 871: timeout_add(&sc->sc_timeout, hz);
! 872: }
! 873:
! 874: /*
! 875: * The following routines are required for the APCI to act as the console.
! 876: */
! 877:
! 878: void
! 879: apcicnprobe(cp)
! 880: struct consdev *cp;
! 881: {
! 882: volatile u_int8_t *frodoregs;
! 883:
! 884: /* locate the major number */
! 885: for (apcimajor = 0; apcimajor < nchrdev; apcimajor++)
! 886: if (cdevsw[apcimajor].d_open == apciopen)
! 887: break;
! 888:
! 889: /* initialize the required fields */
! 890: cp->cn_dev = makedev(apcimajor, 0); /* XXX */
! 891:
! 892: /*
! 893: * The APCI can only be a console on a 425e; on other 4xx
! 894: * models, the "first" serial port is mapped to the DCA
! 895: * at select code 9. See frodo.c for the autoconfiguration
! 896: * version of this check.
! 897: */
! 898: if (machineid != HP_425 || mmuid != MMUID_425_E)
! 899: return;
! 900:
! 901: /*
! 902: * Check the service switch. On the 425e, this is a physical
! 903: * switch, unlike other frodo-based machines, so we can use it
! 904: * as a serial vs internal video selector, since the PROM can not
! 905: * be configured for serial console.
! 906: */
! 907: frodoregs = (volatile u_int8_t *)IIOV(FRODO_BASE);
! 908: if (badaddr((caddr_t)frodoregs) == 0 &&
! 909: !ISSET(frodoregs[FRODO_IISR], FRODO_IISR_SERVICE))
! 910: cp->cn_pri = CN_REMOTE;
! 911: else
! 912: cp->cn_pri = CN_NORMAL;
! 913:
! 914: /*
! 915: * If our priority is higher than the currently-remembered
! 916: * console, install ourselves.
! 917: */
! 918: if (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri) {
! 919: cn_tab = cp;
! 920: conscode = CONSCODE_INVALID;
! 921: }
! 922: }
! 923:
! 924: /* ARGSUSED */
! 925: void
! 926: apcicninit(cp)
! 927: struct consdev *cp;
! 928: {
! 929:
! 930: /*
! 931: * We are not interested by the second console pass.
! 932: */
! 933: if (consolepass != 0)
! 934: return;
! 935:
! 936: apci_cn = (struct apciregs *)IIOV(FRODO_BASE + FRODO_APCI_OFFSET(1));
! 937: apciinit(apci_cn, apcidefaultrate, CFCR_8BITS);
! 938: apciconsinit = 1;
! 939: }
! 940:
! 941: /* ARGSUSED */
! 942: int
! 943: apcicngetc(dev)
! 944: dev_t dev;
! 945: {
! 946: u_char stat;
! 947: int c, s;
! 948:
! 949: s = splhigh();
! 950: while (((stat = apci_cn->ap_lsr) & LSR_RXRDY) == 0)
! 951: ;
! 952: c = apci_cn->ap_data;
! 953:
! 954: /* clear any interrupts generated by this transmission */
! 955: stat = apci_cn->ap_iir;
! 956: splx(s);
! 957: return (c);
! 958: }
! 959:
! 960: /* ARGSUSED */
! 961: void
! 962: apcicnputc(dev, c)
! 963: dev_t dev;
! 964: int c;
! 965: {
! 966: int timo;
! 967: u_char stat;
! 968: int s;
! 969:
! 970: s = splhigh();
! 971:
! 972: if (apciconsinit == 0) {
! 973: apciinit(apci_cn, apcidefaultrate, CFCR_8BITS);
! 974: apciconsinit = 1;
! 975: }
! 976:
! 977: /* wait for any pending transmission to finish */
! 978: timo = 50000;
! 979: while (((stat = apci_cn->ap_lsr) & LSR_TXRDY) == 0 && --timo)
! 980: ;
! 981:
! 982: apci_cn->ap_data = c & 0xff;
! 983:
! 984: /* wait for this transmission to complete */
! 985: timo = 1500000;
! 986: while (((stat = apci_cn->ap_lsr) & LSR_TXRDY) == 0 && --timo)
! 987: ;
! 988:
! 989: /* clear any interrupts generated by this transmission */
! 990: stat = apci_cn->ap_iir;
! 991: splx(s);
! 992: }
CVSweb