static void ewskbd_zsc_stint(struct zs_chanstate *cs, int force) { zs_write_csr(cs, ZSWR0_RESET_STATUS); cs->cs_softreq = 1; }
/* * Polled input char. */ int zs_getc(void *arg) { struct zs_chanstate *cs = arg; int s, c; uint8_t rr0, stat; s = splhigh(); top: /* Wait for a character to arrive. */ do { rr0 = *cs->cs_reg_csr; ZS_DELAY(); } while ((rr0 & ZSRR0_RX_READY) == 0); /* Read error register. */ stat = zs_read_reg(cs, 1) & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE); if (stat) { zs_write_csr(cs, ZSM_RESET_ERR); goto top; } /* Read character. */ c = *cs->cs_reg_data; ZS_DELAY(); splx(s); return (c); }
/* * drain on-chip fifo */ void zs_iflush(struct zs_chanstate *cs) { uint8_t c, rr0, rr1; int i; /* * Count how many times we loop. Some systems, such as some * Apple PowerBooks, claim to have SCC's which they really don't. */ for (i = 0; i < 32; i++) { /* Is there input available? */ rr0 = zs_read_csr(cs); if ((rr0 & ZSRR0_RX_READY) == 0) break; /* * First read the status, because reading the data * destroys the status of this char. */ rr1 = zs_read_reg(cs, 1); c = zs_read_data(cs); if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { /* Clear the receive error. */ zs_write_csr(cs, ZSWR0_RESET_ERRORS); } } }
void zsclock_stint(struct zs_chanstate *cs, int force) { u_char rr0; rr0 = zs_read_csr(cs); cs->cs_rr0 = rr0; /* * Retrigger the interrupt as a soft interrupt, because we need * a trap frame for hardclock(). */ ienab_bis(IE_L10); zs_write_csr(cs, ZSWR0_RESET_STATUS); }
/* * Status Change interrupt. * Called at splzs(). */ void zstty_stint(struct zs_chanstate *cs, int force) { struct zstty_softc *zst = cs->cs_private; struct tty *tp = zst->zst_tty; uint8_t rr0, delta; rr0 = zs_read_csr(cs); zs_write_csr(cs, ZSWR0_RESET_STATUS); /* * Check here for console break, so that we can abort * even when interrupts are locking up the machine. */ if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) && ISSET(rr0, ZSRR0_BREAK) && DB_CONSOLE) zs_abort(cs); if (!force) delta = rr0 ^ cs->cs_rr0; else delta = cs->cs_rr0_mask; ttytstamp(tp, cs->cs_rr0 & ZSRR0_CTS, rr0 & ZSRR0_CTS, cs->cs_rr0 & ZSRR0_DCD, rr0 & ZSRR0_DCD); cs->cs_rr0 = rr0; if (ISSET(delta, cs->cs_rr0_mask)) { SET(cs->cs_rr0_delta, delta); /* * Stop output immediately if we lose the output * flow control signal or carrier detect. */ if (ISSET(~rr0, cs->cs_rr0_mask)) { zst->zst_tbc = 0; zst->zst_heldtbc = 0; } zst->zst_st_check = 1; cs->cs_softreq = 1; } }
void zskbd_rxint(struct zs_chanstate *cs) { struct zskbd_softc *sc = cs->cs_private; struct zskbd_devconfig *dc = sc->sc_dc; uint8_t c, r; /* clear errors */ r = zs_read_reg(cs, 1); if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) zs_write_csr(cs, ZSWR0_RESET_ERRORS); /* read byte and append to our queue */ c = zs_read_data(cs); dc->rxq[dc->rxq_tail] = c; dc->rxq_tail = (dc->rxq_tail + 1) & ~ZSKBD_RXQ_LEN; cs->cs_softreq = 1; }
/* * Transmitter Ready interrupt. * Called at splzs(). */ void zstty_txint(struct zs_chanstate *cs) { struct zstty_softc *zst = cs->cs_private; int rr0; zs_write_csr(cs, ZSWR0_RESET_TXINT); /* * If we've delayed a parameter change, do it now, and restart * output. */ if (cs->cs_heldchange) { zs_loadchannelregs(cs); cs->cs_heldchange = 0; zst->zst_tbc = zst->zst_heldtbc; zst->zst_heldtbc = 0; } while (zst->zst_tbc > 0) { rr0 = zs_read_csr(cs); if ((rr0 & ZSRR0_TX_READY) == 0) break; zs_write_data(cs, *zst->zst_tba); zst->zst_tbc--; zst->zst_tba++; } if (zst->zst_tbc == 0) { if (zst->zst_tx_busy) { zst->zst_tx_busy = 0; zst->zst_tx_done = 1; cs->cs_softreq = 1; } } }
/* * Receiver Ready interrupt. * Called at splzs(). */ void zstty_rxint(struct zs_chanstate *cs) { struct zstty_softc *zst = cs->cs_private; uint8_t *put, *end; u_int cc; uint8_t rr0, rr1, c; end = zst->zst_ebuf; put = zst->zst_rbput; cc = zst->zst_rbavail; while (cc > 0) { /* * First read the status, because reading the received char * destroys the status of this char. */ rr1 = zs_read_reg(cs, 1); c = zs_read_data(cs); if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { /* Clear the receive error. */ zs_write_csr(cs, ZSWR0_RESET_ERRORS); } put[0] = c; put[1] = rr1; put += 2; if (put >= end) put = zst->zst_rbuf; cc--; rr0 = zs_read_csr(cs); if (!ISSET(rr0, ZSRR0_RX_READY)) break; } /* * Current string of incoming characters ended because * no more data was available or we ran out of space. * Schedule a receive event if any data was received. * If we're out of space, turn off receive interrupts. */ zst->zst_rbput = put; zst->zst_rbavail = cc; if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { zst->zst_rx_ready = 1; cs->cs_softreq = 1; } /* * See if we are in danger of overflowing a buffer. If * so, use hardware flow control to ease the pressure. */ if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) && cc < zst->zst_r_hiwat) { SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); zs_hwiflow(zst); } /* * If we're out of space, disable receive interrupts * until the queue has drained a bit. */ if (!cc) { SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); CLR(cs->cs_preg[1], ZSWR1_RIE); cs->cs_creg[1] = cs->cs_preg[1]; zs_write_reg(cs, 1, cs->cs_creg[1]); } }
/* * ZS hardware interrupt. Scan all ZS channels. NB: we know here that * channels are kept in (A,B) pairs. * * Do just a little, then get out; set a software interrupt if more * work is needed. * * We deliberately ignore the vectoring Zilog gives us, and match up * only the number of `reset interrupt under service' operations, not * the order. */ int zsc_intr_hard(void *arg) { struct zsc_softc *zsc = arg; struct zs_chanstate *cs0, *cs1; int handled; uint8_t rr3; handled = 0; /* First look at channel A. */ cs0 = zsc->zsc_cs[0]; cs1 = zsc->zsc_cs[1]; /* * We have to clear interrupt first to avoid a race condition, * but it will be done in each MD handler. */ for (;;) { /* Lock both channels */ mutex_spin_enter(&cs1->cs_lock); mutex_spin_enter(&cs0->cs_lock); /* Note: only channel A has an RR3 */ rr3 = zs_read_reg(cs0, 3); if ((rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT | ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) == 0) { mutex_spin_exit(&cs0->cs_lock); mutex_spin_exit(&cs1->cs_lock); break; } handled = 1; /* First look at channel A. */ if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) zs_write_csr(cs0, ZSWR0_CLR_INTR); if (rr3 & ZSRR3_IP_A_RX) (*cs0->cs_ops->zsop_rxint)(cs0); if (rr3 & ZSRR3_IP_A_STAT) (*cs0->cs_ops->zsop_stint)(cs0, 0); if (rr3 & ZSRR3_IP_A_TX) (*cs0->cs_ops->zsop_txint)(cs0); /* Done with channel A */ mutex_spin_exit(&cs0->cs_lock); /* Now look at channel B. */ if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) zs_write_csr(cs1, ZSWR0_CLR_INTR); if (rr3 & ZSRR3_IP_B_RX) (*cs1->cs_ops->zsop_rxint)(cs1); if (rr3 & ZSRR3_IP_B_STAT) (*cs1->cs_ops->zsop_stint)(cs1, 0); if (rr3 & ZSRR3_IP_B_TX) (*cs1->cs_ops->zsop_txint)(cs1); mutex_spin_exit(&cs1->cs_lock); } /* Note: caller will check cs_x->cs_softreq and DTRT. */ return handled; }
/* * Write the given register set to the given zs channel in the proper order. * The channel must not be transmitting at the time. The receiver will * be disabled for the time it takes to write all the registers. * Call this with interrupts disabled. */ void zs_loadchannelregs(struct zs_chanstate *cs) { uint8_t *reg, v; zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */ #if 1 /* * XXX: Is this really a good idea? * XXX: Should go elsewhere! -gwr */ zs_iflush(cs); /* XXX */ #endif if (cs->cs_ctl_chan != NULL) v = ((cs->cs_ctl_chan->cs_creg[5] & (ZSWR5_RTS | ZSWR5_DTR)) != (cs->cs_ctl_chan->cs_preg[5] & (ZSWR5_RTS | ZSWR5_DTR))); else v = 0; if (memcmp((void *)cs->cs_preg, (void *)cs->cs_creg, 16) == 0 && !v) return; /* only change if values are different */ /* Copy "pending" regs to "current" */ memcpy((void *)cs->cs_creg, (void *)cs->cs_preg, 16); reg = cs->cs_creg; /* current regs */ /* disable interrupts */ zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK); /* baud clock divisor, stop bits, parity */ zs_write_reg(cs, 4, reg[4]); /* misc. TX/RX control bits */ zs_write_reg(cs, 10, reg[10]); /* char size, enable (RX/TX) */ zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); /* synchronous mode stuff */ zs_write_reg(cs, 6, reg[6]); zs_write_reg(cs, 7, reg[7]); #if 0 /* * Registers 2 and 9 are special because they are * actually common to both channels, but must be * programmed through channel A. The "zsc" attach * function takes care of setting these registers * and they should not be touched thereafter. */ /* interrupt vector */ zs_write_reg(cs, 2, reg[2]); /* master interrupt control */ zs_write_reg(cs, 9, reg[9]); #endif /* Shut down the BRG */ zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA); #ifdef ZS_MD_SETCLK /* Let the MD code setup any external clock. */ ZS_MD_SETCLK(cs); #endif /* ZS_MD_SETCLK */ /* clock mode control */ zs_write_reg(cs, 11, reg[11]); /* baud rate (lo/hi) */ zs_write_reg(cs, 12, reg[12]); zs_write_reg(cs, 13, reg[13]); /* Misc. control bits */ zs_write_reg(cs, 14, reg[14]); /* which lines cause status interrupts */ zs_write_reg(cs, 15, reg[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_csr(cs, ZSM_RESET_STINT); zs_write_csr(cs, ZSM_RESET_STINT); /* char size, enable (RX/TX)*/ zs_write_reg(cs, 3, reg[3]); zs_write_reg(cs, 5, reg[5]); /* Write the status bits on the alternate channel also. */ if (cs->cs_ctl_chan != NULL) { v = cs->cs_ctl_chan->cs_preg[5]; cs->cs_ctl_chan->cs_creg[5] = v; zs_write_reg(cs->cs_ctl_chan, 5, v); } /* interrupt enables: RX, TX, STATUS */ zs_write_reg(cs, 1, reg[1]); }