📄 scc.c
字号:
} if (ospeed == 0) { (void) sccmctl(tp->t_dev, 0, DMSET); /* hang up line */ return (0); } /* reset line */ if (line == SCC_CHANNEL_A) value = SCC_WR9_RESET_CHA_A; else value = SCC_WR9_RESET_CHA_B; SCC_WRITE_REG(regs, line, SCC_WR9, value); DELAY(25); /* stop bits, normally 1 */ value = sc->scc_wreg[line].wr4 & 0xf0; if (cflag & CSTOPB) value |= SCC_WR4_2_STOP; else value |= SCC_WR4_1_STOP; if ((cflag & PARODD) == 0) value |= SCC_WR4_EVEN_PARITY; if (cflag & PARENB) value |= SCC_WR4_PARITY_ENABLE; /* set it now, remember it must be first after reset */ sc->scc_wreg[line].wr4 = value; SCC_WRITE_REG(regs, line, SCC_WR4, value); /* vector again */ SCC_WRITE_REG(regs, line, SCC_WR2, 0xf0); /* clear break, keep rts dtr */ wvalue = sc->scc_wreg[line].wr5 & (SCC_WR5_DTR|SCC_WR5_RTS); switch (cflag & CSIZE) { case CS5: value = SCC_WR3_RX_5_BITS; wvalue |= SCC_WR5_TX_5_BITS; break; case CS6: value = SCC_WR3_RX_6_BITS; wvalue |= SCC_WR5_TX_6_BITS; break; case CS7: value = SCC_WR3_RX_7_BITS; wvalue |= SCC_WR5_TX_7_BITS; break; case CS8: default: value = SCC_WR3_RX_8_BITS; wvalue |= SCC_WR5_TX_8_BITS; }; sc->scc_wreg[line].wr3 = value; SCC_WRITE_REG(regs, line, SCC_WR3, value); sc->scc_wreg[line].wr5 = wvalue; SCC_WRITE_REG(regs, line, SCC_WR5, wvalue); SCC_WRITE_REG(regs, line, SCC_WR6, 0); SCC_WRITE_REG(regs, line, SCC_WR7, 0); SCC_WRITE_REG(regs, line, SCC_WR9, SCC_WR9_VIS); SCC_WRITE_REG(regs, line, SCC_WR10, 0); value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR | SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR; SCC_WRITE_REG(regs, line, SCC_WR11, value); SCC_SET_TIMING_BASE(regs, line, ospeed); value = sc->scc_wreg[line].wr14; SCC_WRITE_REG(regs, line, SCC_WR14, value); value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE; SCC_WRITE_REG(regs, line, SCC_WR15, value); /* and now the enables */ value = sc->scc_wreg[line].wr3 | SCC_WR3_RX_ENABLE; SCC_WRITE_REG(regs, line, SCC_WR3, value); value = sc->scc_wreg[line].wr5 | SCC_WR5_TX_ENABLE; sc->scc_wreg[line].wr5 = value; SCC_WRITE_REG(regs, line, SCC_WR5, value); /* master inter enable */ value = SCC_WR9_MASTER_IE | SCC_WR9_VIS; SCC_WRITE_REG(regs, line, SCC_WR9, value); SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1); MachEmptyWriteBuffer(); return (0);}/* * Check for interrupts from all devices. */voidsccintr(unit) register int unit;{ register scc_regmap_t *regs; register struct tty *tp; register struct pdma *dp; register struct scc_softc *sc; register int cc, chan, rr1, rr2, rr3; int overrun = 0; sc = &scc_softc[unit]; regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr; unit <<= 1; for (;;) { SCC_READ_REG(regs, SCC_CHANNEL_B, SCC_RR2, rr2); rr2 = SCC_RR2_STATUS(rr2); /* are we done yet ? */ if (rr2 == 6) { /* strange, distinguished value */ SCC_READ_REG(regs, SCC_CHANNEL_A, SCC_RR3, rr3); if (rr3 == 0) return; } SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); 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 = &scc_tty[unit | chan]; dp = &sc->scc_pdma[chan]; if (dp->p_mem < dp->p_end) { SCC_WRITE_DATA(regs, chan, *dp->p_mem++); MachEmptyWriteBuffer(); } 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-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 &= ~SCC_WR15_TX_UNDERRUN_IE; SCC_WRITE_REG(regs, chan, SCC_WR15, cc); cc = sc->scc_wreg[chan].wr1 & ~SCC_WR1_TX_IE; SCC_WRITE_REG(regs, chan, SCC_WR1, cc); sc->scc_wreg[chan].wr1 = cc; MachEmptyWriteBuffer(); } } } else if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_B_RECV_DONE || 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 = &scc_tty[unit | 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, SCC_RESET_ERROR); if ((rr1 & SCC_RR1_RX_OVERRUN) && overrun == 0) { log(LOG_WARNING, "scc%d,%d: silo overflow\n", unit >> 1, chan); overrun = 1; } } /* * Keyboard needs special treatment. */ if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {#ifdef KADB if (cc == LK_DO) { spl0(); kdbpanic(); return; }#endif#ifdef DEBUG debugChar = cc;#endif if (sccDivertXInput) { (*sccDivertXInput)(cc); continue; } if ((cc = kbdMapChar(cc)) < 0) continue; /* * Now for mousey */ } else if (tp == &scc_tty[SCCMOUSE_PORT] && sccMouseButtons) { register MouseReport *mrp; static MouseReport currentRep; mrp = ¤tRep; mrp->byteCount++; if (cc & MOUSE_START_FRAME) { /* * The first mouse report byte (button state). */ mrp->state = cc; if (mrp->byteCount > 1) mrp->byteCount = 1; } else if (mrp->byteCount == 2) { /* * The second mouse report byte (delta x). */ mrp->dx = cc; } else if (mrp->byteCount == 3) { /* * The final mouse report byte (delta y). */ mrp->dy = cc; mrp->byteCount = 0; if (mrp->dx != 0 || mrp->dy != 0) { /* * If the mouse moved, * post a motion event. */ (*sccMouseEvent)(mrp); } (*sccMouseButtons)(mrp); } continue; } if (!(tp->t_state & TS_ISOPEN)) { wakeup((caddr_t)&tp->t_rawq);#ifdef PORTSELECTOR if (!(tp->t_state & TS_WOPEN))#endif continue; } if (rr2 == SCC_RR2_A_RECV_SPECIAL || rr2 == SCC_RR2_B_RECV_SPECIAL) { if (rr1 & SCC_RR1_PARITY_ERR) cc |= TTY_PE; if (rr1 & SCC_RR1_FRAME_ERR) 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, SCC_RESET_EXT_IP); scc_modem_intr(unit | chan); } }}voidsccstart(tp) register struct tty *tp;{ register struct pdma *dp; register scc_regmap_t *regs; register struct scc_softc *sc; register int cc, chan; u_char temp; int s, sendone; sc = &scc_softc[SCCUNIT(tp->t_dev)]; dp = &sc->scc_pdma[SCCLINE(tp->t_dev)]; regs = (scc_regmap_t *)dp->p_addr; s = spltty(); if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) goto out; if (tp->t_outq.c_cc <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_outq); } selwakeup(&tp->t_wsel); } if (tp->t_outq.c_cc == 0) goto out; /* handle console specially */ if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) { while (tp->t_outq.c_cc > 0) { cc = getc(&tp->t_outq) & 0x7f; cnputc(cc); } /* * After we flush the output queue we may need to wake * up the process that made the output. */ if (tp->t_outq.c_cc <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_outq); } selwakeup(&tp->t_wsel); } goto out; } if (tp->t_flags & (RAW|LITOUT)) cc = ndqb(&tp->t_outq, 0); else { cc = ndqb(&tp->t_outq, 0200); if (cc == 0) { cc = getc(&tp->t_outq); timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6); tp->t_state |= TS_TIMEOUT; goto out; } } tp->t_state |= TS_BUSY; dp->p_end = dp->p_mem = tp->t_outq.c_cf; dp->p_end += cc; /* * Enable transmission and send the first char, as required. */ chan = SCCLINE(tp->t_dev); SCC_READ_REG(regs, chan, SCC_RR0, temp); sendone = (temp & SCC_RR0_TX_EMPTY); SCC_READ_REG(regs, chan, SCC_RR15, temp); temp |= SCC_WR15_TX_UNDERRUN_IE; SCC_WRITE_REG(regs, chan, SCC_WR15, temp); temp = sc->scc_wreg[chan].wr1 | SCC_WR1_TX_IE; SCC_WRITE_REG(regs, chan, SCC_WR1, temp); sc->scc_wreg[chan].wr1 = temp; if (sendone) {#ifdef DIAGNOSTIC if (cc == 0) panic("sccstart: No chars");#endif SCC_WRITE_DATA(regs, chan, *dp->p_mem++); } MachEmptyWriteBuffer();out: splx(s);}/* * Stop output on a line. *//*ARGSUSED*/sccstop(tp, flag) register struct tty *tp;{ register struct pdma *dp; register struct scc_softc *sc; register int s; sc = &scc_softc[SCCUNIT(tp->t_dev)]; dp = &sc->scc_pdma[SCCLINE(tp->t_dev)]; s = spltty(); if (tp->t_state & TS_BUSY) { dp->p_end = dp->p_mem; if (!(tp->t_state & TS_TTSTOP)) tp->t_state |= TS_FLUSH; } splx(s);}sccmctl(dev, bits, how) dev_t dev; int bits, how;{ register struct scc_softc *sc; register scc_regmap_t *regs; register int line, mbits; register u_char value; int s; sc = &scc_softc[SCCUNIT(dev)]; line = SCCLINE(dev); regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr; s = spltty(); /* * only channel B has modem control, however the DTR and RTS * pins on the comm port are wired to the DTR and RTS A channel * signals. */ mbits = DML_DTR | DML_DSR | DML_CAR; if (line == SCC_CHANNEL_B) { if (sc->scc_wreg[SCC_CHANNEL_A].wr5 & SCC_WR5_DTR) mbits = DML_DTR | DML_DSR; else mbits = 0; SCC_READ_REG_ZERO(regs, SCC_CHANNEL_B, value); if (value & SCC_RR0_DCD) mbits |= DML_CAR; } switch (how) { case DMSET: mbits = bits; break; case DMBIS: mbits |= bits; break; case DMBIC: mbits &= ~bits; break; case DMGET: (void) splx(s); return (mbits); } if (line == SCC_CHANNEL_B) { if (mbits & DML_DTR) sc->scc_wreg[SCC_CHANNEL_A].wr5 |= SCC_WR5_DTR; else sc->scc_wreg[SCC_CHANNEL_A].wr5 &= ~SCC_WR5_DTR; SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR5, sc->scc_wreg[SCC_CHANNEL_A].wr5); } if ((mbits & DML_DTR) && (sc->scc_softCAR & (1 << line))) scc_tty[minor(dev)].t_state |= TS_CARR_ON; (void) splx(s); return (mbits);}/* * Check for carrier transition. */static voidscc_modem_intr(dev) dev_t dev;{ register scc_regmap_t *regs; register struct scc_softc *sc; register struct tty *tp; register int car, chan; register u_char value; int s; sc = &scc_softc[SCCUNIT(dev)]; tp = &scc_tty[minor(dev)]; chan = SCCLINE(dev); regs = (scc_regmap_t *)sc->scc_pdma[chan].p_addr; if (chan == SCC_CHANNEL_A) return; s = spltty(); if (sc->scc_softCAR & (1 << chan)) car = 1; else { SCC_READ_REG_ZERO(regs, chan, value); car = value & SCC_RR0_DCD; } if (car) { /* carrier present */ if (!(tp->t_state & TS_CARR_ON)) (void)(*linesw[tp->t_line].l_modem)(tp, 1); } else if (tp->t_state & TS_CARR_ON) (void)(*linesw[tp->t_line].l_modem)(tp, 0); splx(s);}/* * Get a char off the appropriate line via. a busy wait loop. */intsccGetc(dev) dev_t dev;{ register scc_regmap_t *regs; register int c, line; register u_char value; int s; line = SCCLINE(dev); regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr; if (!regs) return (0); s = spltty(); for (;;) { SCC_READ_REG(regs, line, SCC_RR0, value); if (value & SCC_RR0_RX_AVAIL) { SCC_READ_REG(regs, line, SCC_RR1, value); SCC_READ_DATA(regs, line, c); if (value & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) { SCC_WRITE_REG(regs, line, SCC_WR0, SCC_RESET_ERROR); SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0, SCC_RESET_HIGHEST_IUS); } else { SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0, SCC_RESET_HIGHEST_IUS); splx(s); return (c & 0xff); } } else DELAY(10); }}/* * Send a char on a port, via a busy wait loop. */voidsccPutc(dev, c) dev_t dev; int c;{ register scc_regmap_t *regs; register int line; register u_char value; int s; s = spltty(); line = SCCLINE(dev); regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr; /* * Wait for transmitter to be not busy. */ do { SCC_READ_REG(regs, line, SCC_RR0, value); if (value & SCC_RR0_TX_EMPTY) break; DELAY(100); } while (1); /* * Send the char. */ SCC_WRITE_DATA(regs, line, c); MachEmptyWriteBuffer(); splx(s);}#endif /* NSCC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -