diff -uF^[a-zA-Z_][a-z A-Z0-9_]*(.*[^;]$ arch/alpha/tc/scc.c.orig arch/alpha/tc/scc.c --- arch/alpha/tc/scc.c.orig Wed Sep 3 23:41:34 1997 +++ arch/alpha/tc/scc.c Tue Mar 10 23:07:43 1998 @@ -228,6 +228,9 @@ static void rr __P((char *, scc_regmap_t static void scc_modem_intr __P((dev_t)); static void sccreset __P((struct scc_softc *)); +static void scc_txintr __P((struct scc_softc *, int, scc_regmap_t *)); +static void scc_rxintr __P((struct scc_softc *, int, scc_regmap_t *, int)); +static void scc_stintr __P((struct scc_softc *, int, scc_regmap_t *, int)); int sccintr __P((void *)); void scc_alphaintr __P((int)); @@ -969,144 +972,185 @@ cold_sccparam(tp, t, sc) } -/* - * Check for interrupts from all devices. - */ -int -sccintr(xxxsc) - void *xxxsc; +/* transmission done interrupts */ +static void +scc_txintr(sc, chan, regs) + struct scc_softc *sc; + int chan; + scc_regmap_t *regs; { - register struct scc_softc *sc = (struct scc_softc *)xxxsc; - register int unit = (long)sc->sc_dv.dv_unit; - register scc_regmap_t *regs; - register struct tty *tp; - register struct pdma *dp; - register int cc, chan, rr1, rr2, rr3; - int overrun = 0; - - rr1 = 0; /* shut up gcc -Wall */ - regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr; - unit <<= 1; - for (;;) { - SCC_READ_REG(regs, SCC_CHANNEL_B, ZSRR_IVEC, rr2); - rr2 = SCC_RR2_STATUS(rr2); - /* are we done yet ? */ - if (rr2 == 6) { /* strange, distinguished value */ - SCC_READ_REG(regs, SCC_CHANNEL_A, ZSRR_IPEND, rr3); - if (rr3 == 0) - return 1; - } + register struct tty *tp = sc->scc_tty[chan]; + register struct pdma *dp = &sc->scc_pdma[chan]; + register int cc; - SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, ZSWR0_CLR_INTR); - if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) { - chan = (rr2 == SCC_RR2_A_XMIT_DONE) ? - SCC_CHANNEL_A : SCC_CHANNEL_B; - tp = sc->scc_tty[chan]; - dp = &sc->scc_pdma[chan]; - if (dp->p_mem < dp->p_end) { - SCC_WRITE_DATA(regs, chan, *dp->p_mem++); + tp = sc->scc_tty[chan]; + dp = &sc->scc_pdma[chan]; + if (dp->p_mem < dp->p_end) { + SCC_WRITE_DATA(regs, chan, *dp->p_mem++); #ifdef pmax /* Alpha handles the 1.6 msec settle time in hardware */ - DELAY(2); + DELAY(2); #endif + tc_mb(); + } else { + tp->t_state &= ~TS_BUSY; + if (tp->t_state & TS_FLUSH) + tp->t_state &= ~TS_FLUSH; + else { + ndflush(&tp->t_outq, dp->p_mem - + (caddr_t) tp->t_outq.c_cf); + dp->p_end = dp->p_mem = tp->t_outq.c_cf; + } + if (tp->t_line) + (*linesw[tp->t_line].l_start)(tp); + else + sccstart(tp); + if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) { + SCC_READ_REG(regs, chan, SCC_RR15, cc); + cc &= ~ZSWR15_TXUEOM_IE; + SCC_WRITE_REG(regs, chan, SCC_WR15, cc); + cc = sc->scc_wreg[chan].wr1 & ~ZSWR1_TIE; + SCC_WRITE_REG(regs, chan, SCC_WR1, cc); + sc->scc_wreg[chan].wr1 = cc; tc_mb(); - } else { - tp->t_state &= ~TS_BUSY; - if (tp->t_state & TS_FLUSH) - tp->t_state &= ~TS_FLUSH; - else { - ndflush(&tp->t_outq, dp->p_mem - - (caddr_t) tp->t_outq.c_cf); - dp->p_end = dp->p_mem = tp->t_outq.c_cf; - } - if (tp->t_line) - (*linesw[tp->t_line].l_start)(tp); - else - sccstart(tp); - if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) { - SCC_READ_REG(regs, chan, SCC_RR15, cc); - cc &= ~ZSWR15_TXUEOM_IE; - SCC_WRITE_REG(regs, chan, SCC_WR15, cc); - cc = sc->scc_wreg[chan].wr1 & ~ZSWR1_TIE; - SCC_WRITE_REG(regs, chan, SCC_WR1, cc); - sc->scc_wreg[chan].wr1 = cc; - tc_mb(); - } } - } else if (rr2 == SCC_RR2_A_RECV_DONE || - rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL || + } +} + +/* receive interrupts */ +static void +scc_rxintr(sc, chan, regs, unit) + struct scc_softc *sc; + int chan; + scc_regmap_t *regs; + int unit; +{ + register struct tty *tp = sc->scc_tty[chan]; + int cc, rr1 = 0, rr2 = 0; /* XXX */ + + SCC_READ_DATA(regs, chan, cc); + if (rr2 == SCC_RR2_A_RECV_SPECIAL || rr2 == SCC_RR2_B_RECV_SPECIAL) { - if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL) - chan = SCC_CHANNEL_A; - else - chan = SCC_CHANNEL_B; - tp = sc->scc_tty[chan]; - SCC_READ_DATA(regs, chan, cc); - if (rr2 == SCC_RR2_A_RECV_SPECIAL || - rr2 == SCC_RR2_B_RECV_SPECIAL) { - SCC_READ_REG(regs, chan, SCC_RR1, rr1); - SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_ERRORS); - if ((rr1 & ZSRR1_DO) && overrun == 0) { - log(LOG_WARNING, "scc%d,%d: silo overflow\n", - unit >> 1, chan); - overrun = 1; - } + SCC_READ_REG(regs, chan, SCC_RR1, rr1); + SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_ERRORS); + if (rr1 & ZSRR1_DO) { + log(LOG_WARNING, "scc%d,%d: silo overflow\n", + unit >> 1, chan); } + } - /* - * Keyboard needs special treatment. - */ - if (tp == scctty(makedev(SCCDEV, SCCKBD_PORT)) /* && cn_tab.cn_screen */) { + /* + * Keyboard needs special treatment. + */ + if (tp == scctty(makedev(SCCDEV, SCCKBD_PORT)) /* && cn_tab.cn_screen */) { #ifdef KADB - if (cc == LK_DO) { - spl0(); - kdbpanic(); - return; - } + if (cc == LK_DO) { + spl0(); + kdbpanic(); + return; /* XXXXXXXXXXX ??? true return */ + } #endif #ifdef DEBUG - debugChar = cc; + debugChar = cc; #endif - if (sccDivertXInput) { - (*sccDivertXInput)(cc); - continue; - } + if (sccDivertXInput) { + (*sccDivertXInput)(cc); + return; + } #ifdef TK_NOTYET - if ((cc = kbdMapChar(cc)) < 0) - continue; + if ((cc = kbdMapChar(cc)) < 0) + return; #endif - /* - * Now for mousey - */ - } else if (tp == scctty(makedev(SCCDEV, SCCMOUSE_PORT)) && - sccMouseButtons) { + /* + * Now for mousey + */ + } else if (tp == scctty(makedev(SCCDEV, SCCMOUSE_PORT)) && + sccMouseButtons) { #ifdef HAVE_RCONS - /*XXX*/ - mouseInput(cc); + /*XXX*/ + mouseInput(cc); #endif - continue; - } - if (!(tp->t_state & TS_ISOPEN)) { - wakeup((caddr_t)&tp->t_rawq); + return; + } + if (!(tp->t_state & TS_ISOPEN)) { + wakeup((caddr_t)&tp->t_rawq); #ifdef PORTSELECTOR - if (!(tp->t_state & TS_WOPEN)) + if (!(tp->t_state & TS_WOPEN)) #endif - continue; - } - if (rr2 == SCC_RR2_A_RECV_SPECIAL || - rr2 == SCC_RR2_B_RECV_SPECIAL) { - if (rr1 & ZSRR1_PE) - cc |= TTY_PE; - if (rr1 & ZSRR1_FE) - cc |= TTY_FE; - } - (*linesw[tp->t_line].l_rint)(cc, tp); - } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) { - chan = (rr2 == SCC_RR2_A_EXT_STATUS) ? - SCC_CHANNEL_A : SCC_CHANNEL_B; - SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_STATUS); - scc_modem_intr(unit | chan); - } + return; + } + if (rr2 == SCC_RR2_A_RECV_SPECIAL || + rr2 == SCC_RR2_B_RECV_SPECIAL) { + if (rr1 & ZSRR1_PE) + cc |= TTY_PE; + if (rr1 & ZSRR1_FE) + cc |= TTY_FE; + } + (*linesw[tp->t_line].l_rint)(cc, tp); +} + +/* status interrupts */ +static void +scc_stintr(sc, chan, regs, unit) + struct scc_softc *sc; + int chan; + scc_regmap_t *regs; + int unit; +{ + + SCC_WRITE_REG(regs, chan, SCC_RR0, ZSWR0_RESET_STATUS); + scc_modem_intr(unit | chan); +} + +/* + * Check for interrupts from all devices. + */ +int +sccintr(xxxsc) + void *xxxsc; +{ + register struct scc_softc *sc = (struct scc_softc *)xxxsc; + register int unit = (long)sc->sc_dv.dv_unit; + register scc_regmap_t *regs; + register int rr3; + + regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr; + unit <<= 1; + + /* Note: only channel A has an RR3 */ + SCC_READ_REG(regs, SCC_CHANNEL_A, ZSRR_IPEND, rr3); + + /* + * Clear interrupt first to avoid a race condition. + * If a new interrupt condition happens while we are + * servicing this one, we will get another interrupt + * shortly. We can NOT just sit here in a loop, or + * we will cause horrible latency for other devices + * on this interrupt level (i.e. sun3x floppy disk). + */ + + /* First look at channel A. */ + if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) { + SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, ZSWR0_CLR_INTR); + if (rr3 & ZSRR3_IP_A_RX) + scc_rxintr(sc, SCC_CHANNEL_A, regs, unit); + if (rr3 & ZSRR3_IP_A_STAT) + scc_stintr(sc, SCC_CHANNEL_A, regs, unit); + if (rr3 & ZSRR3_IP_A_TX) + scc_txintr(sc, SCC_CHANNEL_A, regs); } + + /* Now look at channel B. */ + if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) { + SCC_WRITE_REG(regs, SCC_CHANNEL_B, SCC_RR0, ZSWR0_CLR_INTR); + if (rr3 & ZSRR3_IP_B_RX) + scc_rxintr(sc, SCC_CHANNEL_B, regs, unit); + if (rr3 & ZSRR3_IP_B_STAT) + scc_stintr(sc, SCC_CHANNEL_B, regs, unit); + if (rr3 & ZSRR3_IP_B_TX) + scc_txintr(sc, SCC_CHANNEL_B, regs); + } + + return 1; } void