Annotation of sys/arch/alpha/tc/scc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: scc.c,v 1.20 2004/09/19 21:34:42 mickey Exp $ */
! 2: /* $NetBSD: scc.c,v 1.58 2002/03/17 19:40:27 atatat Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1991,1990,1989,1994,1995,1996 Carnegie Mellon University
! 6: * All Rights Reserved.
! 7: *
! 8: * Permission to use, copy, modify and distribute this software and its
! 9: * documentation is hereby granted, provided that both the copyright
! 10: * notice and this permission notice appear in all copies of the
! 11: * software, derivative works or modified versions, and any portions
! 12: * thereof, and that both notices appear in supporting documentation.
! 13: *
! 14: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
! 15: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
! 16: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
! 17: *
! 18: * Carnegie Mellon requests users of this software to return to
! 19: *
! 20: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
! 21: * School of Computer Science
! 22: * Carnegie Mellon University
! 23: * Pittsburgh PA 15213-3890
! 24: *
! 25: * any improvements or extensions that they make and grant Carnegie the
! 26: * rights to redistribute these changes.
! 27: */
! 28:
! 29: /*-
! 30: * Copyright (c) 1992, 1993
! 31: * The Regents of the University of California. All rights reserved.
! 32: *
! 33: * This code is derived from software contributed to Berkeley by
! 34: * Ralph Campbell and Rick Macklem.
! 35: *
! 36: * Redistribution and use in source and binary forms, with or without
! 37: * modification, are permitted provided that the following conditions
! 38: * are met:
! 39: * 1. Redistributions of source code must retain the above copyright
! 40: * notice, this list of conditions and the following disclaimer.
! 41: * 2. Redistributions in binary form must reproduce the above copyright
! 42: * notice, this list of conditions and the following disclaimer in the
! 43: * documentation and/or other materials provided with the distribution.
! 44: * 3. Neither the name of the University nor the names of its contributors
! 45: * may be used to endorse or promote products derived from this software
! 46: * without specific prior written permission.
! 47: *
! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 58: * SUCH DAMAGE.
! 59: *
! 60: * @(#)scc.c 8.2 (Berkeley) 11/30/93
! 61: */
! 62:
! 63: /*
! 64: * Intel 82530 dual usart chip driver. Supports the serial port(s) on the
! 65: * Personal DECstation 5000/xx and DECstation 5000/1xx, plus the keyboard
! 66: * and mouse on the 5000/1xx. (Don't ask me where the A channel signals
! 67: * are on the 5000/xx.)
! 68: *
! 69: * See: Intel MicroCommunications Handbook, Section 2, pg. 155-173, 1992.
! 70: */
! 71: #include <sys/param.h>
! 72: #include <sys/systm.h>
! 73: #include <sys/ioctl.h>
! 74: #include <sys/tty.h>
! 75: #include <sys/proc.h>
! 76: #include <sys/buf.h>
! 77: #include <sys/file.h>
! 78: #include <sys/uio.h>
! 79: #include <sys/kernel.h>
! 80: #include <sys/syslog.h>
! 81: #include <sys/device.h>
! 82:
! 83: #include <dev/cons.h>
! 84:
! 85: #include <dev/ic/z8530reg.h>
! 86: #include <alpha/tc/sccreg.h>
! 87: #include <alpha/tc/sccvar.h>
! 88:
! 89: #include <machine/rpb.h>
! 90: #include <machine/conf.h>
! 91:
! 92: #include <dev/tc/tcvar.h>
! 93: #include <dev/tc/ioasicreg.h>
! 94: #include <dev/tc/ioasicvar.h>
! 95:
! 96: #undef SCCDEV
! 97: #define SCCDEV 15 /* XXX */
! 98:
! 99: #define raster_console() 1 /* Treat test for cn_screen as true */
! 100: #define CONSOLE_ON_UNIT(unit) 0 /* No raster console on Alphas */
! 101:
! 102: #define NSCCLINE (NSCC*2)
! 103: #define SCCUNIT(dev) (minor(dev) >> 1)
! 104: #define SCCLINE(dev) (minor(dev) & 0x1)
! 105:
! 106: #ifdef DEBUG
! 107: int debugChar;
! 108: #endif
! 109:
! 110: struct scc_softc {
! 111: struct device sc_dv;
! 112: struct pdma scc_pdma[2];
! 113: struct {
! 114: u_char wr1;
! 115: u_char wr3;
! 116: u_char wr4;
! 117: u_char wr5;
! 118: u_char wr14;
! 119: } scc_wreg[2];
! 120: struct tty *scc_tty[2];
! 121: int scc_softCAR;
! 122:
! 123: int scc_flags[2];
! 124: #define SCC_CHAN_NEEDSDELAY 0x01 /* sw must delay 1.6us between output*/
! 125: #define SCC_CHAN_NOMODEM 0x02 /* don't touch modem ctl lines (may
! 126: be left floating or x-wired */
! 127: #define SCC_CHAN_MODEM_CROSSED 0x04 /* modem lines wired to other channel*/
! 128: #define SCC_CHAN_KBDLINE 0x08 /* XXX special-case keyboard lines */
! 129: };
! 130:
! 131: /*
! 132: * BRG formula is:
! 133: * ClockFrequency
! 134: * BRGconstant = --------------------------- - 2
! 135: * 2 * BaudRate * ClockDivider
! 136: *
! 137: * Speed selections with Pclk=7.3728MHz, clock x16
! 138: */
! 139: const struct speedtab sccspeedtab[] = {
! 140: { 0, 0, },
! 141: { 50, 4606, },
! 142: { 75, 3070, },
! 143: { 110, 2093, },
! 144: { 134.5, 1711, },
! 145: { 150, 1534, },
! 146: { 200, 1150, },
! 147: { 300, 766, },
! 148: { 600, 382, },
! 149: { 1200, 190, },
! 150: { 1800, 126, },
! 151: { 2400, 94, },
! 152: { 4800, 46, },
! 153: { 7200, 30, }, /* non-POSIX */
! 154: { 9600, 22, },
! 155: { 14400, 14, }, /* non-POSIX */
! 156: { 19200, 10, },
! 157: { 28800, 6, }, /* non-POSIX */
! 158: { 38400, 4, }, /* non-POSIX */
! 159: { 57600, 2, }, /* non-POSIX */
! 160: { -1, -1, },
! 161: };
! 162:
! 163: #ifndef PORTSELECTOR
! 164: #define ISPEED TTYDEF_SPEED
! 165: #define LFLAG TTYDEF_LFLAG
! 166: #else
! 167: #define ISPEED B4800
! 168: #define LFLAG (TTYDEF_LFLAG & ~ECHO)
! 169: #endif
! 170:
! 171: /* Definition of the driver for autoconfig. */
! 172: int sccmatch(struct device *, void *, void *);
! 173: void sccattach(struct device *, struct device *, void *);
! 174:
! 175: struct cfattach scc_ca = {
! 176: sizeof (struct scc_softc), sccmatch, sccattach,
! 177: };
! 178:
! 179: struct cfdriver scc_cd = {
! 180: NULL, "scc", DV_TTY,
! 181: };
! 182:
! 183: cdev_decl(scc);
! 184:
! 185: int sccGetc(dev_t);
! 186: void sccPutc(dev_t, int);
! 187: void sccPollc(dev_t, int);
! 188: int sccparam(struct tty *, struct termios *);
! 189: void sccstart(struct tty *);
! 190:
! 191: int sccmctl(struct scc_softc *, int, int, int);
! 192: int cold_sccparam(struct tty *, struct termios *,
! 193: struct scc_softc *sc, int line);
! 194:
! 195: #ifdef SCC_DEBUG
! 196: void rr(char *, scc_regmap_t *);
! 197: #endif
! 198: void scc_modem_intr(dev_t);
! 199: void sccreset(struct scc_softc *);
! 200:
! 201: int sccintr(void *);
! 202: void scc_alphaintr(int);
! 203:
! 204: /*
! 205: * console variables, for using serial console while still cold and
! 206: * autoconfig has not attached the scc device.
! 207: */
! 208: scc_regmap_t *scc_cons_addr = 0;
! 209: struct consdev scccons = {
! 210: NULL, NULL, sccGetc, sccPutc, sccPollc, NULL, NODEV, 0
! 211: };
! 212:
! 213: /*
! 214: * Test to see if device is present.
! 215: * Return true if found.
! 216: */
! 217: int
! 218: sccmatch(parent, vcf, aux)
! 219: struct device *parent;
! 220: void *vcf, *aux;
! 221: {
! 222: extern struct cfdriver ioasic_cd; /* XXX */
! 223: struct ioasicdev_attach_args *d = aux;
! 224: struct cfdata *cf = vcf;
! 225: void *sccaddr;
! 226:
! 227: if (parent->dv_cfdata->cf_driver != &ioasic_cd) {
! 228: #ifdef DIAGNOSTIC
! 229: printf("Cannot attach scc on %s\n", parent->dv_xname);
! 230: #endif
! 231: return (0);
! 232: }
! 233:
! 234: /* Make sure that we're looking for this type of device. */
! 235: if ((strncmp(d->iada_modname, "z8530 ", TC_ROM_LLEN) != 0) &&
! 236: (strncmp(d->iada_modname, "scc", TC_ROM_LLEN)!= 0))
! 237: return (0);
! 238:
! 239: /*
! 240: * Check user-specified offset against the ioasic offset.
! 241: * Allow it to be wildcarded.
! 242: */
! 243: if (cf->cf_loc[0] != -1 &&
! 244: cf->cf_loc[0] != d->iada_offset)
! 245: return (0);
! 246:
! 247: /* Get the address, and check it for validity. */
! 248: sccaddr = (void *)d->iada_addr;
! 249: #ifdef SPARSE
! 250: sccaddr = (void *)TC_DENSE_TO_SPARSE((tc_addr_t)sccaddr);
! 251: #endif
! 252: if (badaddr(sccaddr, 2))
! 253: return (0);
! 254:
! 255: return (1);
! 256: }
! 257:
! 258: /*
! 259: * Enable ioasic SCC interrupts and scc DMA engine interrupts.
! 260: * XXX does not really belong here.
! 261: */
! 262: void
! 263: scc_alphaintr(onoff)
! 264: int onoff;
! 265: {
! 266: if (onoff) {
! 267: *(volatile u_int *)(ioasic_base + IOASIC_IMSK) |=
! 268: IOASIC_INTR_SCC_1 | IOASIC_INTR_SCC_0;
! 269: #if !defined(DEC_3000_300) && defined(SCC_DMA)
! 270: *(volatile u_int *)(ioasic_base + IOASIC_CSR) |=
! 271: IOASIC_CSR_DMAEN_T1 | IOASIC_CSR_DMAEN_R1 |
! 272: IOASIC_CSR_DMAEN_T2 | IOASIC_CSR_DMAEN_R2;
! 273: #endif
! 274: } else {
! 275: *(volatile u_int *)(ioasic_base + IOASIC_IMSK) &=
! 276: ~(IOASIC_INTR_SCC_1 | IOASIC_INTR_SCC_0);
! 277: #if !defined(DEC_3000_300) && defined(SCC_DMA)
! 278: *(volatile u_int *)(ioasic_base + IOASIC_CSR) &=
! 279: ~(IOASIC_CSR_DMAEN_T1 | IOASIC_CSR_DMAEN_R1 |
! 280: IOASIC_CSR_DMAEN_T2 | IOASIC_CSR_DMAEN_R2);
! 281: #endif
! 282: }
! 283: tc_mb();
! 284: }
! 285:
! 286: void
! 287: sccattach(parent, self, aux)
! 288: struct device *parent;
! 289: struct device *self;
! 290: void *aux;
! 291: {
! 292: struct scc_softc *sc = (struct scc_softc *)self;
! 293: struct ioasicdev_attach_args *d = aux;
! 294: struct pdma *pdp;
! 295: struct tty *tp;
! 296: void *sccaddr;
! 297: int cntr;
! 298: struct termios cterm;
! 299: struct tty ctty;
! 300: int s;
! 301: int unit;
! 302:
! 303: unit = sc->sc_dv.dv_unit;
! 304:
! 305: /* Get the address, and check it for validity. */
! 306: sccaddr = (void *)d->iada_addr;
! 307: #ifdef SPARSE
! 308: sccaddr = (void *)TC_DENSE_TO_SPARSE((tc_addr_t)sccaddr);
! 309: #endif
! 310:
! 311: /* Register the interrupt handler. */
! 312: ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_TTY,
! 313: sccintr, (void *)sc);
! 314:
! 315: /*
! 316: * For a remote console, wait a while for previous output to
! 317: * complete.
! 318: */
! 319: if ((cputype == ST_DEC_3000_500 && sc->sc_dv.dv_unit == 1) ||
! 320: (cputype == ST_DEC_3000_300 && sc->sc_dv.dv_unit == 0))
! 321: DELAY(10000);
! 322: pdp = &sc->scc_pdma[0];
! 323:
! 324: /* init pseudo DMA structures */
! 325: for (cntr = 0; cntr < 2; cntr++) {
! 326: pdp->p_addr = (void *)sccaddr;
! 327: tp = sc->scc_tty[cntr] = ttymalloc();
! 328: pdp->p_arg = (long)tp;
! 329: pdp->p_fcn = (void (*)(struct tty*))0;
! 330: tp->t_dev = (dev_t)((sc->sc_dv.dv_unit << 1) | cntr);
! 331: pdp++;
! 332: }
! 333: /* What's the warning here? Defaulting to softCAR on line 2? */
! 334: sc->scc_softCAR = sc->sc_dv.dv_cfdata->cf_flags | 0x2; /* XXX */
! 335:
! 336: /* reset chip, initialize register-copies in softc */
! 337: sccreset(sc);
! 338:
! 339: /*
! 340: * Special handling for consoles.
! 341: */
! 342: if (1 /* SCCUNIT(cn_tab.cn_dev) == sc->sc_dv.dv_unit */) {
! 343: s = spltty();
! 344: cterm.c_cflag = (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8;
! 345: cterm.c_ospeed = cterm.c_ispeed = 9600;
! 346: (void) cold_sccparam(&ctty, &cterm, sc,
! 347: SCCLINE((sc->sc_dv.dv_unit == 0) ?
! 348: SCCCOMM2_PORT : SCCCOMM3_PORT));
! 349: DELAY(1000);
! 350: splx(s);
! 351: }
! 352:
! 353: /*
! 354: * XXX
! 355: * Unit 1 is the remote console, wire it up now.
! 356: */
! 357: if ((cputype == ST_DEC_3000_500 && sc->sc_dv.dv_unit == 1) ||
! 358: (cputype == ST_DEC_3000_300 && sc->sc_dv.dv_unit == 0)) {
! 359: if (alpha_donot_kludge_scc)
! 360: printf("\nSWITCHING TO SERIAL CONSOLE!\n");
! 361: cn_tab = &scccons;
! 362: cn_tab->cn_dev = makedev(SCCDEV, sc->sc_dv.dv_unit * 2);
! 363:
! 364: printf("%s console\n", alpha_donot_kludge_scc ? "\n***" : ":");
! 365:
! 366: /* wire carrier for console. */
! 367: sc->scc_softCAR |= SCCLINE(cn_tab->cn_dev);
! 368: } else
! 369: printf("\n");
! 370: }
! 371:
! 372: /*
! 373: * Reset the chip.
! 374: */
! 375: void
! 376: sccreset(sc)
! 377: register struct scc_softc *sc;
! 378: {
! 379: register scc_regmap_t *regs;
! 380: register u_char val;
! 381:
! 382: regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
! 383: /*
! 384: * Chip once-only initialization
! 385: *
! 386: * NOTE: The wiring we assume is the one on the 3min:
! 387: *
! 388: * out A-TxD --> TxD keybd or mouse
! 389: * in A-RxD --> RxD keybd or mouse
! 390: * out A-DTR~ --> DTR comm
! 391: * out A-RTS~ --> RTS comm
! 392: * in A-CTS~ --> SI comm
! 393: * in A-DCD~ --> RI comm
! 394: * in A-SYNCH~--> DSR comm
! 395: * out B-TxD --> TxD comm
! 396: * in B-RxD --> RxD comm
! 397: * in B-RxC --> TRxCB comm
! 398: * in B-TxC --> RTxCB comm
! 399: * out B-RTS~ --> SS comm
! 400: * in B-CTS~ --> CTS comm
! 401: * in B-DCD~ --> CD comm
! 402: */
! 403: SCC_INIT_REG(regs, SCC_CHANNEL_A);
! 404: SCC_INIT_REG(regs, SCC_CHANNEL_B);
! 405:
! 406: SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, ZSWR9_HARD_RESET);
! 407: DELAY(50000); /*enough ? */
! 408: SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, 0);
! 409:
! 410: /* program the interrupt vector */
! 411: SCC_WRITE_REG(regs, SCC_CHANNEL_A, ZSWR_IVEC, 0xf0);
! 412: SCC_WRITE_REG(regs, SCC_CHANNEL_B, ZSWR_IVEC, 0xf0);
! 413: SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, ZSWR9_VECTOR_INCL_STAT);
! 414:
! 415: /* receive parameters and control */
! 416: sc->scc_wreg[SCC_CHANNEL_A].wr3 = 0;
! 417: sc->scc_wreg[SCC_CHANNEL_B].wr3 = 0;
! 418:
! 419: /* timing base defaults */
! 420: sc->scc_wreg[SCC_CHANNEL_A].wr4 = ZSWR4_CLK_X16;
! 421: sc->scc_wreg[SCC_CHANNEL_B].wr4 = ZSWR4_CLK_X16;
! 422:
! 423: /* enable DTR, RTS and SS */
! 424: sc->scc_wreg[SCC_CHANNEL_B].wr5 = 0;
! 425: sc->scc_wreg[SCC_CHANNEL_A].wr5 = ZSWR5_RTS | ZSWR5_DTR;
! 426:
! 427: /* baud rates */
! 428: val = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK;
! 429: sc->scc_wreg[SCC_CHANNEL_B].wr14 = val;
! 430: sc->scc_wreg[SCC_CHANNEL_A].wr14 = val;
! 431:
! 432: /* interrupt conditions */
! 433: val = ZSWR1_RIE | ZSWR1_PE_SC | ZSWR1_SIE | ZSWR1_TIE;
! 434: sc->scc_wreg[SCC_CHANNEL_A].wr1 = val;
! 435: sc->scc_wreg[SCC_CHANNEL_B].wr1 = val;
! 436: }
! 437:
! 438: int
! 439: sccopen(dev, flag, mode, p)
! 440: dev_t dev;
! 441: int flag, mode;
! 442: struct proc *p;
! 443: {
! 444: register struct scc_softc *sc;
! 445: register struct tty *tp;
! 446: register int unit, line;
! 447: int s, error = 0;
! 448: int firstopen = 0;
! 449:
! 450: unit = SCCUNIT(dev);
! 451: if (unit >= scc_cd.cd_ndevs)
! 452: return (ENXIO);
! 453: sc = scc_cd.cd_devs[unit];
! 454: if (!sc)
! 455: return (ENXIO);
! 456:
! 457: line = SCCLINE(dev);
! 458: if (sc->scc_pdma[line].p_addr == NULL)
! 459: return (ENXIO);
! 460: tp = sc->scc_tty[line];
! 461: if (tp == NULL) {
! 462: tp = sc->scc_tty[line] = ttymalloc();
! 463: }
! 464: tp->t_oproc = sccstart;
! 465: tp->t_param = sccparam;
! 466: tp->t_dev = dev;
! 467: if ((tp->t_state & TS_ISOPEN) == 0) {
! 468: ttychars(tp);
! 469: firstopen = 1;
! 470: #ifndef PORTSELECTOR
! 471: if (tp->t_ispeed == 0) {
! 472: #endif
! 473: tp->t_iflag = TTYDEF_IFLAG;
! 474: tp->t_oflag = TTYDEF_OFLAG;
! 475: tp->t_cflag = TTYDEF_CFLAG;
! 476: tp->t_lflag = LFLAG;
! 477: tp->t_ispeed = tp->t_ospeed = ISPEED;
! 478: #ifdef PORTSELECTOR
! 479: tp->t_cflag |= HUPCL;
! 480: #else
! 481: }
! 482: #endif
! 483: (void) sccparam(tp, &tp->t_termios);
! 484: ttsetwater(tp);
! 485: } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
! 486: return (EBUSY);
! 487: (void) sccmctl(sc, SCCLINE(dev), DML_DTR, DMSET);
! 488: s = spltty();
! 489: while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
! 490: !(tp->t_state & TS_CARR_ON)) {
! 491: tp->t_state |= TS_WOPEN;
! 492: error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
! 493: ttopen, 0);
! 494: tp->t_state &= ~TS_WOPEN;
! 495: if (error != 0)
! 496: break;
! 497: }
! 498: splx(s);
! 499: if (error)
! 500: return (error);
! 501: error = (*linesw[tp->t_line].l_open)(dev, tp);
! 502:
! 503: return (error);
! 504: }
! 505:
! 506: /*ARGSUSED*/
! 507: int
! 508: sccclose(dev, flag, mode, p)
! 509: dev_t dev;
! 510: int flag, mode;
! 511: struct proc *p;
! 512: {
! 513: register struct scc_softc *sc = scc_cd.cd_devs[SCCUNIT(dev)];
! 514: register struct tty *tp;
! 515: register int line;
! 516:
! 517: line = SCCLINE(dev);
! 518: tp = sc->scc_tty[line];
! 519: if (sc->scc_wreg[line].wr5 & ZSWR5_BREAK) {
! 520: sc->scc_wreg[line].wr5 &= ~ZSWR5_BREAK;
! 521: ttyoutput(0, tp);
! 522: }
! 523: (*linesw[tp->t_line].l_close)(tp, flag);
! 524: if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
! 525: !(tp->t_state & TS_ISOPEN))
! 526: (void) sccmctl(sc, line, 0, DMSET);
! 527: return (ttyclose(tp));
! 528: }
! 529:
! 530: int
! 531: sccread(dev, uio, flag)
! 532: dev_t dev;
! 533: struct uio *uio;
! 534: int flag;
! 535: {
! 536: register struct scc_softc *sc;
! 537: register struct tty *tp;
! 538:
! 539: sc = scc_cd.cd_devs[SCCUNIT(dev)]; /* XXX*/
! 540: tp = sc->scc_tty[SCCLINE(dev)];
! 541: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
! 542: }
! 543:
! 544: int
! 545: sccwrite(dev, uio, flag)
! 546: dev_t dev;
! 547: struct uio *uio;
! 548: int flag;
! 549: {
! 550: register struct scc_softc *sc;
! 551: register struct tty *tp;
! 552:
! 553: sc = scc_cd.cd_devs[SCCUNIT(dev)]; /* XXX*/
! 554: tp = sc->scc_tty[SCCLINE(dev)];
! 555: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
! 556: }
! 557:
! 558: struct tty *
! 559: scctty(dev)
! 560: dev_t dev;
! 561: {
! 562: register struct scc_softc *sc;
! 563: register struct tty *tp;
! 564: register int unit = SCCUNIT(dev);
! 565:
! 566: if ((unit >= scc_cd.cd_ndevs) || (sc = scc_cd.cd_devs[unit]) == 0)
! 567: return (0);
! 568: tp = sc->scc_tty[SCCLINE(dev)];
! 569: return (tp);
! 570: }
! 571:
! 572: /*ARGSUSED*/
! 573: int
! 574: sccioctl(dev, cmd, data, flag, p)
! 575: dev_t dev;
! 576: u_long cmd;
! 577: caddr_t data;
! 578: int flag;
! 579: struct proc *p;
! 580: {
! 581: register struct scc_softc *sc;
! 582: register struct tty *tp;
! 583: int error, line;
! 584:
! 585: line = SCCLINE(dev);
! 586: sc = scc_cd.cd_devs[SCCUNIT(dev)];
! 587: tp = sc->scc_tty[line];
! 588: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
! 589: if (error >= 0)
! 590: return (error);
! 591: error = ttioctl(tp, cmd, data, flag, p);
! 592: if (error >= 0)
! 593: return (error);
! 594:
! 595: switch (cmd) {
! 596:
! 597: case TIOCSBRK:
! 598: sc->scc_wreg[line].wr5 |= ZSWR5_BREAK;
! 599: ttyoutput(0, tp);
! 600: break;
! 601:
! 602: case TIOCCBRK:
! 603: sc->scc_wreg[line].wr5 &= ~ZSWR5_BREAK;
! 604: ttyoutput(0, tp);
! 605: break;
! 606:
! 607: case TIOCSDTR:
! 608: (void) sccmctl(sc, line, DML_DTR|DML_RTS, DMBIS);
! 609: break;
! 610:
! 611: case TIOCCDTR:
! 612: (void) sccmctl(sc, line, DML_DTR|DML_RTS, DMBIC);
! 613: break;
! 614:
! 615: case TIOCMSET:
! 616: (void) sccmctl(sc, line, *(int *)data, DMSET);
! 617: break;
! 618:
! 619: case TIOCMBIS:
! 620: (void) sccmctl(sc, line, *(int *)data, DMBIS);
! 621: break;
! 622:
! 623: case TIOCMBIC:
! 624: (void) sccmctl(sc, line, *(int *)data, DMBIC);
! 625: break;
! 626:
! 627: case TIOCMGET:
! 628: *(int *)data = sccmctl(sc, line, 0, DMGET);
! 629: break;
! 630:
! 631: default:
! 632: return (ENOTTY);
! 633: }
! 634: return (0);
! 635: }
! 636:
! 637:
! 638:
! 639: /*
! 640: * Set line parameters -- tty t_param entry point.
! 641: */
! 642: int
! 643: sccparam(tp, t)
! 644: register struct tty *tp;
! 645: register struct termios *t;
! 646: {
! 647: register struct scc_softc *sc;
! 648:
! 649: /* Extract the softc and call cold_sccparam to do all the work. */
! 650: sc = scc_cd.cd_devs[SCCUNIT(tp->t_dev)];
! 651: return cold_sccparam(tp, t, sc, SCCLINE(tp->t_dev));
! 652: }
! 653:
! 654:
! 655: /*
! 656: * Do what sccparam() (t_param entry point) does, but callable when cold.
! 657: */
! 658: int
! 659: cold_sccparam(tp, t, sc, line)
! 660: register struct tty *tp;
! 661: register struct termios *t;
! 662: register struct scc_softc *sc;
! 663: register int line;
! 664: {
! 665: register scc_regmap_t *regs;
! 666: register u_char value, wvalue;
! 667: register int cflag = t->c_cflag;
! 668: int ospeed;
! 669:
! 670: /* Check arguments */
! 671: if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
! 672: return (EINVAL);
! 673: ospeed = ttspeedtab(t->c_ospeed, sccspeedtab);
! 674: if (ospeed < 0)
! 675: return (EINVAL);
! 676: /* and copy to tty */
! 677: tp->t_ispeed = t->c_ispeed;
! 678: tp->t_ospeed = t->c_ospeed;
! 679: tp->t_cflag = cflag;
! 680:
! 681: /*
! 682: * Handle console specially.
! 683: */
! 684: {
! 685: cflag = CS8;
! 686: ospeed = ttspeedtab(9600, sccspeedtab);
! 687: }
! 688: if (ospeed == 0) {
! 689: (void) sccmctl(sc, line, 0, DMSET); /* hang up line */
! 690: return (0);
! 691: }
! 692:
! 693: regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
! 694:
! 695: /*
! 696: * pmax driver used to reset the SCC here. That reset causes the
! 697: * other channel on the SCC to drop outpur chars: at least that's
! 698: * what CGD reports for the Alpha. It's a bug.
! 699: */
! 700: #if 0
! 701: /* reset line */
! 702: if (line == SCC_CHANNEL_A)
! 703: value = ZSWR9_A_RESET;
! 704: else
! 705: value = ZSWR9_B_RESET;
! 706: SCC_WRITE_REG(regs, line, SCC_WR9, value);
! 707: DELAY(25);
! 708: #endif
! 709:
! 710: /* stop bits, normally 1 */
! 711: value = sc->scc_wreg[line].wr4 & 0xf0;
! 712: if (cflag & CSTOPB)
! 713: value |= ZSWR4_TWOSB;
! 714: else
! 715: value |= ZSWR4_ONESB;
! 716: if ((cflag & PARODD) == 0)
! 717: value |= ZSWR4_EVENP;
! 718: if (cflag & PARENB)
! 719: value |= ZSWR4_PARENB;
! 720:
! 721: /* set it now, remember it must be first after reset */
! 722: sc->scc_wreg[line].wr4 = value;
! 723: SCC_WRITE_REG(regs, line, SCC_WR4, value);
! 724:
! 725: /* vector again */
! 726: SCC_WRITE_REG(regs, line, ZSWR_IVEC, 0xf0);
! 727:
! 728: /* clear break, keep rts dtr */
! 729: wvalue = sc->scc_wreg[line].wr5 & (ZSWR5_DTR|ZSWR5_RTS);
! 730: switch (cflag & CSIZE) {
! 731: case CS5:
! 732: value = ZSWR3_RX_5;
! 733: wvalue |= ZSWR5_TX_5;
! 734: break;
! 735: case CS6:
! 736: value = ZSWR3_RX_6;
! 737: wvalue |= ZSWR5_TX_6;
! 738: break;
! 739: case CS7:
! 740: value = ZSWR3_RX_7;
! 741: wvalue |= ZSWR5_TX_7;
! 742: break;
! 743: case CS8:
! 744: default:
! 745: value = ZSWR3_RX_8;
! 746: wvalue |= ZSWR5_TX_8;
! 747: };
! 748: sc->scc_wreg[line].wr3 = value;
! 749: SCC_WRITE_REG(regs, line, SCC_WR3, value);
! 750:
! 751: sc->scc_wreg[line].wr5 = wvalue;
! 752: SCC_WRITE_REG(regs, line, SCC_WR5, wvalue);
! 753:
! 754: /*
! 755: * XXX Does the SCC chip require us to refresh the WR5 register
! 756: * for the other channel after writing the other, or not?
! 757: */
! 758: #ifdef notdef
! 759: /* XXX */
! 760: {
! 761: int otherline = (line + 1) & 1;
! 762: SCC_WRITE_REG(regs, otherline, SCC_WR5, sc->scc_wreg[otherline].wr5);
! 763: }
! 764: #endif
! 765:
! 766: SCC_WRITE_REG(regs, line, ZSWR_SYNCLO, 0);
! 767: SCC_WRITE_REG(regs, line, ZSWR_SYNCHI, 0);
! 768: SCC_WRITE_REG(regs, line, SCC_WR9, ZSWR9_VECTOR_INCL_STAT);
! 769: SCC_WRITE_REG(regs, line, SCC_WR10, 0);
! 770: value = ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD |
! 771: ZSWR11_TRXC_OUT_ENA | ZSWR11_TRXC_BAUD;
! 772: SCC_WRITE_REG(regs, line, SCC_WR11, value);
! 773: SCC_SET_TIMING_BASE(regs, line, ospeed);
! 774: value = sc->scc_wreg[line].wr14;
! 775: SCC_WRITE_REG(regs, line, SCC_WR14, value);
! 776:
! 777: if (sc->sc_dv.dv_unit == 1) {
! 778: /* On unit one, on the flamingo, modem control is floating! */
! 779: value = ZSWR15_BREAK_IE;
! 780: } else
! 781: {
! 782: value = ZSWR15_BREAK_IE | ZSWR15_CTS_IE | ZSWR15_DCD_IE;
! 783: }
! 784: SCC_WRITE_REG(regs, line, SCC_WR15, value);
! 785:
! 786: /* and now the enables */
! 787: value = sc->scc_wreg[line].wr3 | ZSWR3_RX_ENABLE;
! 788: SCC_WRITE_REG(regs, line, SCC_WR3, value);
! 789: value = sc->scc_wreg[line].wr5 | ZSWR5_TX_ENABLE;
! 790: sc->scc_wreg[line].wr5 = value;
! 791: SCC_WRITE_REG(regs, line, SCC_WR5, value);
! 792:
! 793: /* master inter enable */
! 794: value = ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT;
! 795: SCC_WRITE_REG(regs, line, SCC_WR9, value);
! 796: SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1);
! 797: tc_mb();
! 798:
! 799: scc_alphaintr(1); /* XXX XXX XXX */
! 800:
! 801: return (0);
! 802: }
! 803:
! 804:
! 805: /*
! 806: * Check for interrupts from all devices.
! 807: */
! 808: int
! 809: sccintr(xxxsc)
! 810: void *xxxsc;
! 811: {
! 812: register struct scc_softc *sc = (struct scc_softc *)xxxsc;
! 813: register int unit = (long)sc->sc_dv.dv_unit;
! 814: register scc_regmap_t *regs;
! 815: register struct tty *tp;
! 816: register struct pdma *dp;
! 817: register int cc, chan, rr1, rr2, rr3;
! 818: int overrun = 0;
! 819:
! 820: rr1 = 0; /* shut up gcc -Wall */
! 821: regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
! 822: unit <<= 1;
! 823: for (;;) {
! 824: SCC_READ_REG(regs, SCC_CHANNEL_B, ZSRR_IVEC, rr2);
! 825: rr2 = SCC_RR2_STATUS(rr2);
! 826: /* are we done yet ? */
! 827: if (rr2 == 6) { /* strange, distinguished value */
! 828: SCC_READ_REG(regs, SCC_CHANNEL_A, ZSRR_IPEND, rr3);
! 829: if (rr3 == 0)
! 830: return 1;
! 831: }
! 832:
! 833: SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, ZSWR0_CLR_INTR);
! 834: if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) {
! 835: chan = (rr2 == SCC_RR2_A_XMIT_DONE) ?
! 836: SCC_CHANNEL_A : SCC_CHANNEL_B;
! 837: tp = sc->scc_tty[chan];
! 838: dp = &sc->scc_pdma[chan];
! 839: if (dp->p_mem < dp->p_end) {
! 840: SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
! 841: tc_mb();
! 842: } else {
! 843: tp->t_state &= ~TS_BUSY;
! 844: if (tp->t_state & TS_FLUSH)
! 845: tp->t_state &= ~TS_FLUSH;
! 846: else {
! 847: ndflush(&tp->t_outq, dp->p_mem -
! 848: (caddr_t) tp->t_outq.c_cf);
! 849: dp->p_end = dp->p_mem = tp->t_outq.c_cf;
! 850: }
! 851: (*linesw[tp->t_line].l_start)(tp);
! 852: if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
! 853: SCC_READ_REG(regs, chan, SCC_RR15, cc);
! 854: cc &= ~ZSWR15_TXUEOM_IE;
! 855: SCC_WRITE_REG(regs, chan, SCC_WR15, cc);
! 856: cc = sc->scc_wreg[chan].wr1 & ~ZSWR1_TIE;
! 857: SCC_WRITE_REG(regs, chan, SCC_WR1, cc);
! 858: sc->scc_wreg[chan].wr1 = cc;
! 859: tc_mb();
! 860: }
! 861: }
! 862: } else if (rr2 == SCC_RR2_A_RECV_DONE ||
! 863: rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL ||
! 864: rr2 == SCC_RR2_B_RECV_SPECIAL) {
! 865: if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL)
! 866: chan = SCC_CHANNEL_A;
! 867: else
! 868: chan = SCC_CHANNEL_B;
! 869: tp = sc->scc_tty[chan];
! 870: SCC_READ_DATA(regs, chan, cc);
! 871: if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
! 872: rr2 == SCC_RR2_B_RECV_SPECIAL) {
! 873: SCC_READ_REG(regs, chan, SCC_RR1, rr1);
! 874: SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_ERRORS);
! 875: if ((rr1 & ZSRR1_DO) && overrun == 0) {
! 876: log(LOG_WARNING, "scc%d,%d: silo overflow\n",
! 877: unit >> 1, chan);
! 878: overrun = 1;
! 879: }
! 880: }
! 881:
! 882: if (!(tp->t_state & TS_ISOPEN)) {
! 883: wakeup((caddr_t)&tp->t_rawq);
! 884: #ifdef PORTSELECTOR
! 885: if (!(tp->t_state & TS_WOPEN))
! 886: #endif
! 887: continue;
! 888: }
! 889: if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
! 890: rr2 == SCC_RR2_B_RECV_SPECIAL) {
! 891: if (rr1 & ZSRR1_PE)
! 892: cc |= TTY_PE;
! 893: if (rr1 & ZSRR1_FE)
! 894: cc |= TTY_FE;
! 895: }
! 896: (*linesw[tp->t_line].l_rint)(cc, tp);
! 897: } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) {
! 898: chan = (rr2 == SCC_RR2_A_EXT_STATUS) ?
! 899: SCC_CHANNEL_A : SCC_CHANNEL_B;
! 900: SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_STATUS);
! 901: scc_modem_intr(unit | chan);
! 902: }
! 903: }
! 904: return 0; /* XXX */
! 905: }
! 906:
! 907: void
! 908: sccstart(tp)
! 909: register struct tty *tp;
! 910: {
! 911: register struct pdma *dp;
! 912: register scc_regmap_t *regs;
! 913: register struct scc_softc *sc;
! 914: register int cc, chan;
! 915: u_char temp;
! 916: int s, sendone;
! 917:
! 918: sc = scc_cd.cd_devs[SCCUNIT(tp->t_dev)];
! 919: dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];
! 920: regs = (scc_regmap_t *)dp->p_addr;
! 921: s = spltty();
! 922: if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
! 923: goto out;
! 924: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 925: if (tp->t_state & TS_ASLEEP) {
! 926: tp->t_state &= ~TS_ASLEEP;
! 927: wakeup((caddr_t)&tp->t_outq);
! 928: }
! 929: selwakeup(&tp->t_wsel);
! 930: }
! 931: if (tp->t_outq.c_cc == 0)
! 932: goto out;
! 933: /* handle console specially */
! 934: if (tp == scctty(makedev(SCCDEV,SCCKBD_PORT)) && raster_console()) {
! 935: while (tp->t_outq.c_cc > 0) {
! 936: cc = getc(&tp->t_outq) & 0x7f;
! 937: cnputc(cc);
! 938: }
! 939: /*
! 940: * After we flush the output queue we may need to wake
! 941: * up the process that made the output.
! 942: */
! 943: if (tp->t_outq.c_cc <= tp->t_lowat) {
! 944: if (tp->t_state & TS_ASLEEP) {
! 945: tp->t_state &= ~TS_ASLEEP;
! 946: wakeup((caddr_t)&tp->t_outq);
! 947: }
! 948: selwakeup(&tp->t_wsel);
! 949: }
! 950: goto out;
! 951: }
! 952: cc = ndqb(&tp->t_outq, 0);
! 953:
! 954: tp->t_state |= TS_BUSY;
! 955: dp->p_end = dp->p_mem = tp->t_outq.c_cf;
! 956: dp->p_end += cc;
! 957:
! 958: /*
! 959: * Enable transmission and send the first char, as required.
! 960: */
! 961: chan = SCCLINE(tp->t_dev);
! 962: SCC_READ_REG(regs, chan, SCC_RR0, temp);
! 963: sendone = (temp & ZSRR0_TX_READY);
! 964: SCC_READ_REG(regs, chan, SCC_RR15, temp);
! 965: temp |= ZSWR15_TXUEOM_IE;
! 966: SCC_WRITE_REG(regs, chan, SCC_WR15, temp);
! 967: temp = sc->scc_wreg[chan].wr1 | ZSWR1_TIE;
! 968: SCC_WRITE_REG(regs, chan, SCC_WR1, temp);
! 969: sc->scc_wreg[chan].wr1 = temp;
! 970: if (sendone) {
! 971: #ifdef DIAGNOSTIC
! 972: if (cc == 0)
! 973: panic("sccstart: No chars");
! 974: #endif
! 975: SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
! 976: }
! 977: tc_mb();
! 978: out:
! 979: splx(s);
! 980: }
! 981:
! 982: /*
! 983: * Stop output on a line.
! 984: */
! 985: /*ARGSUSED*/
! 986: int
! 987: sccstop(tp, flag)
! 988: register struct tty *tp;
! 989: int flag;
! 990: {
! 991: register struct pdma *dp;
! 992: register struct scc_softc *sc;
! 993: register int s;
! 994:
! 995: sc = scc_cd.cd_devs[SCCUNIT(tp->t_dev)];
! 996: dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];
! 997: s = spltty();
! 998: if (tp->t_state & TS_BUSY) {
! 999: dp->p_end = dp->p_mem;
! 1000: if (!(tp->t_state & TS_TTSTOP))
! 1001: tp->t_state |= TS_FLUSH;
! 1002: }
! 1003: splx(s);
! 1004: return 0;
! 1005: }
! 1006:
! 1007: int
! 1008: sccmctl(sc, line, bits, how)
! 1009: struct scc_softc *sc;
! 1010: int line, bits, how;
! 1011: {
! 1012: register scc_regmap_t *regs;
! 1013: register int mbits;
! 1014: register u_char value;
! 1015: int s;
! 1016:
! 1017: regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
! 1018: s = spltty();
! 1019: /*
! 1020: * only channel B has modem control, however the DTR and RTS
! 1021: * pins on the comm port are wired to the DTR and RTS A channel
! 1022: * signals.
! 1023: */
! 1024: mbits = DML_DTR | DML_DSR | DML_CAR;
! 1025: if (line == SCC_CHANNEL_B) {
! 1026: if (sc->scc_wreg[SCC_CHANNEL_A].wr5 & ZSWR5_DTR)
! 1027: mbits = DML_DTR | DML_DSR;
! 1028: else
! 1029: mbits = 0;
! 1030: SCC_READ_REG_ZERO(regs, SCC_CHANNEL_B, value);
! 1031: if (value & ZSRR0_DCD)
! 1032: mbits |= DML_CAR;
! 1033: }
! 1034: switch (how) {
! 1035: case DMSET:
! 1036: mbits = bits;
! 1037: break;
! 1038:
! 1039: case DMBIS:
! 1040: mbits |= bits;
! 1041: break;
! 1042:
! 1043: case DMBIC:
! 1044: mbits &= ~bits;
! 1045: break;
! 1046:
! 1047: case DMGET:
! 1048: (void) splx(s);
! 1049: return (mbits);
! 1050: }
! 1051: if (line == SCC_CHANNEL_B) {
! 1052: if (mbits & DML_DTR)
! 1053: sc->scc_wreg[SCC_CHANNEL_A].wr5 |= ZSWR5_DTR;
! 1054: else
! 1055: sc->scc_wreg[SCC_CHANNEL_A].wr5 &= ~ZSWR5_DTR;
! 1056: SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR5,
! 1057: sc->scc_wreg[SCC_CHANNEL_A].wr5);
! 1058: }
! 1059: if ((mbits & DML_DTR) || (sc->scc_softCAR & (1 << line)))
! 1060: sc->scc_tty[line]->t_state |= TS_CARR_ON;
! 1061: (void) splx(s);
! 1062: return (mbits);
! 1063: }
! 1064:
! 1065: /*
! 1066: * Check for carrier transition.
! 1067: */
! 1068: void
! 1069: scc_modem_intr(dev)
! 1070: dev_t dev;
! 1071: {
! 1072: register scc_regmap_t *regs;
! 1073: register struct scc_softc *sc;
! 1074: register struct tty *tp;
! 1075: register int car, chan;
! 1076: register u_char value;
! 1077: int s;
! 1078:
! 1079: chan = SCCLINE(dev);
! 1080: sc = scc_cd.cd_devs[SCCUNIT(dev)];
! 1081: tp = sc->scc_tty[chan];
! 1082: regs = (scc_regmap_t *)sc->scc_pdma[chan].p_addr;
! 1083: if (chan == SCC_CHANNEL_A)
! 1084: return;
! 1085: s = spltty();
! 1086: if (sc->scc_softCAR & (1 << chan))
! 1087: car = 1;
! 1088: else {
! 1089: SCC_READ_REG_ZERO(regs, chan, value);
! 1090: car = value & ZSRR0_DCD;
! 1091: }
! 1092:
! 1093: /* Break on serial console drops into the debugger */
! 1094: if ((value & ZSRR0_BREAK) && CONSOLE_ON_UNIT(sc->sc_dv.dv_unit)) {
! 1095: #ifdef DDB
! 1096: splx(s); /* spl0()? */
! 1097: Debugger();
! 1098: return;
! 1099: #else
! 1100: /* XXX maybe fall back to PROM? */
! 1101: #endif
! 1102: }
! 1103:
! 1104: splx(s);
! 1105: }
! 1106:
! 1107: /*
! 1108: * Get a char off the appropriate line via. a busy wait loop.
! 1109: */
! 1110: int
! 1111: sccGetc(dev)
! 1112: dev_t dev;
! 1113: {
! 1114: register scc_regmap_t *regs;
! 1115: register int c, line;
! 1116: register u_char value;
! 1117: int s;
! 1118:
! 1119: line = SCCLINE(dev);
! 1120: if (cold && scc_cons_addr) {
! 1121: regs = scc_cons_addr;
! 1122: } else {
! 1123: register struct scc_softc *sc;
! 1124: sc = scc_cd.cd_devs[SCCUNIT(dev)];
! 1125: regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
! 1126: }
! 1127:
! 1128: if (!regs)
! 1129: return (0);
! 1130: s = splhigh();
! 1131: for (;;) {
! 1132: SCC_READ_REG(regs, line, SCC_RR0, value);
! 1133: if (value & ZSRR0_RX_READY) {
! 1134: SCC_READ_REG(regs, line, SCC_RR1, value);
! 1135: SCC_READ_DATA(regs, line, c);
! 1136: if (value & (ZSRR1_PE | ZSRR1_DO | ZSRR1_FE)) {
! 1137: SCC_WRITE_REG(regs, line, SCC_WR0,
! 1138: ZSWR0_RESET_ERRORS);
! 1139: SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
! 1140: ZSWR0_CLR_INTR);
! 1141: } else {
! 1142: SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
! 1143: ZSWR0_CLR_INTR);
! 1144: splx(s);
! 1145: return (c & 0xff);
! 1146: }
! 1147: } else
! 1148: DELAY(10);
! 1149: }
! 1150: }
! 1151:
! 1152: /*
! 1153: * Send a char on a port, via a busy wait loop.
! 1154: */
! 1155: void
! 1156: sccPutc(dev, c)
! 1157: dev_t dev;
! 1158: int c;
! 1159: {
! 1160: register scc_regmap_t *regs;
! 1161: register int line;
! 1162: register u_char value;
! 1163: int s;
! 1164:
! 1165: s = splhigh();
! 1166: line = SCCLINE(dev);
! 1167: if (cold && scc_cons_addr) {
! 1168: regs = scc_cons_addr;
! 1169: } else {
! 1170: register struct scc_softc *sc;
! 1171: sc = scc_cd.cd_devs[SCCUNIT(dev)];
! 1172: regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
! 1173: }
! 1174:
! 1175: /*
! 1176: * Wait for transmitter to be not busy.
! 1177: */
! 1178: do {
! 1179: SCC_READ_REG(regs, line, SCC_RR0, value);
! 1180: if (value & ZSRR0_TX_READY)
! 1181: break;
! 1182: DELAY(100);
! 1183: } while (1);
! 1184:
! 1185: /*
! 1186: * Send the char.
! 1187: */
! 1188: SCC_WRITE_DATA(regs, line, c);
! 1189: tc_mb();
! 1190: splx(s);
! 1191:
! 1192: return;
! 1193: }
! 1194:
! 1195: /*
! 1196: * Enable/disable polling mode
! 1197: */
! 1198: void
! 1199: sccPollc(dev, on)
! 1200: dev_t dev;
! 1201: int on;
! 1202: {
! 1203: }
! 1204:
! 1205: #ifdef SCC_DEBUG
! 1206: void
! 1207: rr(msg, regs)
! 1208: char *msg;
! 1209: scc_regmap_t *regs;
! 1210: {
! 1211: u_char value;
! 1212: int r0, r1, r2, r3, r10, r15;
! 1213:
! 1214: printf("%s: register: %lx\n", msg, regs);
! 1215: #define L(reg, r) { \
! 1216: SCC_READ_REG(regs, SCC_CHANNEL_A, reg, value); \
! 1217: r = value; \
! 1218: }
! 1219: L(SCC_RR0, r0);
! 1220: L(SCC_RR1, r1);
! 1221: L(ZSRR_IVEC, r2);
! 1222: L(ZSRR_IPEND, r3);
! 1223: L(SCC_RR10, r10);
! 1224: L(SCC_RR15, r15);
! 1225: printf("A: 0: %x 1: %x 2(vec): %x 3: %x 10: %x 15: %x\n",
! 1226: r0, r1, r2, r3, r10, r15);
! 1227: #undef L
! 1228: #define L(reg, r) { \
! 1229: SCC_READ_REG(regs, SCC_CHANNEL_B, reg, value); \
! 1230: r = value; \
! 1231: }
! 1232: L(SCC_RR0, r0);
! 1233: L(SCC_RR1, r1);
! 1234: L(ZSRR_IVEC, r2);
! 1235: L(SCC_RR10, r10);
! 1236: L(SCC_RR15, r15);
! 1237: printf("B: 0: %x 1: %x 2(state): %x 10: %x 15: %x\n",
! 1238: r0, r1, r2, r10, r15);
! 1239: }
! 1240: #endif /* SCC_DEBUG */
CVSweb