static void zsttystart(struct tty *tp) { struct zstty_softc *sc; uint8_t c; sc = tp->t_dev->si_drv1; if ((tp->t_state & TS_TBLOCK) != 0) /* XXX clear RTS */; else /* XXX set RTS */; if ((tp->t_state & (TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) != 0) { ttwwakeup(tp); return; } if (tp->t_outq.c_cc <= tp->t_olowat) { if ((tp->t_state & TS_SO_OLOWAT) != 0) { tp->t_state &= ~TS_SO_OLOWAT; wakeup(TSA_OLOWAT(tp)); } selwakeup(&tp->t_wsel); if (tp->t_outq.c_cc == 0) { if ((tp->t_state & (TS_BUSY | TS_SO_OCOMPLETE)) == TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) { tp->t_state &= ~TS_SO_OCOMPLETE; wakeup(TSA_OCOMPLETE(tp)); } return; } } sc->sc_ocnt = q_to_b(&tp->t_outq, sc->sc_obuf, sizeof(sc->sc_obuf)); if (sc->sc_ocnt == 0) return; c = sc->sc_obuf[0]; sc->sc_oget = sc->sc_obuf + 1; sc->sc_ocnt--; tp->t_state |= TS_BUSY; sc->sc_tx_busy = 1; /* * Enable transmit interrupts if necessary and send the first * character to start up the transmitter. */ if ((sc->sc_preg[1] & ZSWR1_TIE) == 0) { sc->sc_preg[1] |= ZSWR1_TIE; sc->sc_creg[1] = sc->sc_preg[1]; ZS_WRITE_REG(sc, 1, sc->sc_creg[1]); } ZS_WRITE(sc, sc->sc_data, c); ttwwakeup(tp); }
static void zstty_cnputc(struct zstty_softc *sc, int c) { zstty_cnopen(sc); while ((ZS_READ(sc, sc->sc_csr) & ZSRR0_TX_READY) == 0) ; ZS_WRITE(sc, sc->sc_data, c); zstty_cnclose(sc); }
static void zstty_flush(struct zstty_softc *sc) { uint8_t rr0; uint8_t rr1; uint8_t c; for (;;) { rr0 = ZS_READ(sc, sc->sc_csr); if ((rr0 & ZSRR0_RX_READY) == 0) break; rr1 = ZS_READ_REG(sc, 1); c = ZS_READ(sc, sc->sc_data); if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) ZS_WRITE(sc, sc->sc_data, ZSWR0_RESET_ERRORS); } }
static void zstty_load_regs(struct zstty_softc *sc) { /* * If the transmitter may be active, just hold the change and do it * in the tx interrupt handler. Changing the registers while tx is * active may hang the chip. */ if (sc->sc_tx_busy != 0) { sc->sc_preg_held = 1; return; } /* If the regs are the same do nothing. */ if (bcmp(sc->sc_preg, sc->sc_creg, 16) == 0) return; bcopy(sc->sc_preg, sc->sc_creg, 16); /* XXX: reset error condition */ ZS_WRITE(sc, sc->sc_csr, ZSM_RESET_ERR); /* disable interrupts */ ZS_WRITE_REG(sc, 1, sc->sc_creg[1] & ~ZSWR1_IMASK); /* baud clock divisor, stop bits, parity */ ZS_WRITE_REG(sc, 4, sc->sc_creg[4]); /* misc. TX/RX control bits */ ZS_WRITE_REG(sc, 10, sc->sc_creg[10]); /* char size, enable (RX/TX) */ ZS_WRITE_REG(sc, 3, sc->sc_creg[3] & ~ZSWR3_RX_ENABLE); ZS_WRITE_REG(sc, 5, sc->sc_creg[5] & ~ZSWR5_TX_ENABLE); /* Shut down the BRG */ ZS_WRITE_REG(sc, 14, sc->sc_creg[14] & ~ZSWR14_BAUD_ENA); /* clock mode control */ ZS_WRITE_REG(sc, 11, sc->sc_creg[11]); /* baud rate (lo/hi) */ ZS_WRITE_REG(sc, 12, sc->sc_creg[12]); ZS_WRITE_REG(sc, 13, sc->sc_creg[13]); /* Misc. control bits */ ZS_WRITE_REG(sc, 14, sc->sc_creg[14]); /* which lines cause status interrupts */ ZS_WRITE_REG(sc, 15, sc->sc_creg[15]); /* * Zilog docs recommend resetting external status twice at this * point. Mainly as the status bits are latched, and the first * interrupt clear might unlatch them to new values, generating * a second interrupt request. */ ZS_WRITE(sc, sc->sc_csr, ZSM_RESET_STINT); ZS_WRITE(sc, sc->sc_csr, ZSM_RESET_STINT); /* char size, enable (RX/TX)*/ ZS_WRITE_REG(sc, 3, sc->sc_creg[3]); ZS_WRITE_REG(sc, 5, sc->sc_creg[5]); /* interrupt enables: RX, TX, STATUS */ ZS_WRITE_REG(sc, 1, sc->sc_creg[1]); }
/* * Note that the rr3 value is shifted so the channel a status bits are in the * channel b bit positions, which makes the bit positions uniform for both * channels. */ static int zstty_intr(struct zstty_softc *sc, uint8_t rr3) { int needsoft; uint8_t rr0; uint8_t rr1; uint8_t c; int brk; ZSTTY_LOCK(sc); ZS_WRITE(sc, sc->sc_csr, ZSWR0_CLR_INTR); brk = 0; needsoft = 0; if ((rr3 & ZSRR3_IP_B_RX) != 0) { needsoft = 1; do { /* * First read the status, because reading the received * char destroys the status of this char. */ rr1 = ZS_READ_REG(sc, 1); c = ZS_READ(sc, sc->sc_data); if ((rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) != 0) ZS_WRITE(sc, sc->sc_csr, ZSWR0_RESET_ERRORS); #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER) if (sc->sc_console != 0) brk = db_alt_break(c, &sc->sc_alt_break_state); #endif *sc->sc_iput++ = c; *sc->sc_iput++ = rr1; if (sc->sc_iput == sc->sc_ibuf + sizeof(sc->sc_ibuf)) sc->sc_iput = sc->sc_ibuf; } while ((ZS_READ(sc, sc->sc_csr) & ZSRR0_RX_READY) != 0); } if ((rr3 & ZSRR3_IP_B_STAT) != 0) { rr0 = ZS_READ(sc, sc->sc_csr); ZS_WRITE(sc, sc->sc_csr, ZSWR0_RESET_STATUS); #if defined(DDB) && defined(BREAK_TO_DEBUGGER) if (sc->sc_console != 0 && (rr0 & ZSRR0_BREAK) != 0) brk = 1; #endif /* XXX do something about flow control */ } if ((rr3 & ZSRR3_IP_B_TX) != 0) { /* * If we've delayed a paramter change, do it now. */ if (sc->sc_preg_held) { sc->sc_preg_held = 0; zstty_load_regs(sc); } if (sc->sc_ocnt > 0) { ZS_WRITE(sc, sc->sc_data, *sc->sc_oget++); sc->sc_ocnt--; } else { /* * Disable transmit completion interrupts if * necessary. */ if ((sc->sc_preg[1] & ZSWR1_TIE) != 0) { sc->sc_preg[1] &= ~ZSWR1_TIE; sc->sc_creg[1] = sc->sc_preg[1]; ZS_WRITE_REG(sc, 1, sc->sc_creg[1]); } sc->sc_tx_done = 1; sc->sc_tx_busy = 0; needsoft = 1; } } ZSTTY_UNLOCK(sc); if (brk != 0) breakpoint(); return (needsoft); }
/* * Attach a found zs. */ static void zsattach(device_t parent, device_t self, void *aux) { struct zs_softc *sc; struct zsdevice *zs; struct zschan *zc; struct zs_chanstate *cs; int channel; sc = device_private(self); sc->sc_dev = self; printf(": serial2 on channel a and modem2 on channel b\n"); zs = (struct zsdevice *)AD_SCC; for (channel = 0; channel < 2; channel++) { cs = &sc->sc_cs_store[channel]; sc->sc_cs[channel] = cs; cs->cs_unit = channel; cs->cs_zc = zc = (channel == 0) ? &zs->zs_chan_a : &zs->zs_chan_b; /* * Get the command register into a known state. */ (void)zc->zc_csr; (void)zc->zc_csr; /* * Do a hardware reset. */ if (channel == 0) { ZS_WRITE(zc, 9, ZSWR9_HARD_RESET); delay(50000); /* enough ? */ ZS_WRITE(zc, 9, 0); } /* * Initialize channel */ zs_loadchannelregs(zc, zs_init_regs); } if (machineid & ATARI_TT) { /* * ininitialise TT-MFP timer C: 307200Hz * timer C and D share one control register: * bits 0-2 control timer D * bits 4-6 control timer C */ int cr = MFP2->mf_tcdcr & 7; MFP2->mf_tcdcr = cr; /* stop timer C */ MFP2->mf_tcdr = 1; /* counter 1 */ cr |= T_Q004 << 4; /* divisor 4 */ MFP2->mf_tcdcr = cr; /* start timer C */ /* * enable scc related interrupts */ SCU->vme_mask |= SCU_SCC; zs_frequencies = zs_freqs_tt; } else if (machineid & ATARI_FALCON) { zs_frequencies = zs_freqs_falcon; } else if (machineid & ATARI_HADES) { zs_frequencies = zs_freqs_hades; } else { zs_frequencies = zs_freqs_generic; } if (intr_establish(36, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Rx chan B)\n"); if (intr_establish(32, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Tx empty chan B)\n"); if (intr_establish(34, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Ext./Status chan B)\n"); if (intr_establish(38, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Special Rx cond. chan B)\n"); if (intr_establish(44, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Rx chan A)\n"); if (intr_establish(40, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Tx empty chan A)\n"); if (intr_establish(42, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Ext./Status chan A)\n"); if (intr_establish(46, USER_VEC, 0, (hw_ifun_t)zshard, sc) == NULL) aprint_error_dev(self, "Can't establish interrupt (Special Rx cond. chan A)\n"); sc->sc_sicookie = softint_establish(SOFTINT_SERIAL, (void (*)(void *))zssoft, sc); }