/* * Compute the current baud rate given a ZS channel. */ int zs_get_speed(struct zs_chanstate *cs) { int tconst; tconst = zs_read_reg(cs, 12); tconst |= zs_read_reg(cs, 13) << 8; return TCONST_TO_BPS(cs->cs_brg_clk, tconst); }
/* * 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 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; }
/* expects to be in splzs() */ int zskbd_poll(struct zs_chanstate *cs, uint8_t *key) { u_int i; int rr0, rr1, c; for (i = 1000; i != 0; i--) { rr0 = zs_read_csr(cs); if ((rr0 & ZSRR0_RX_READY) != 0) break; delay(100); } if (i == 0) return ENXIO; rr1 = zs_read_reg(cs, 1); c = zs_read_data(cs); if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) return EIO; *key = (uint8_t)c; return 0; }
/* * 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]); } }
/* * Attach a found zs. * * Match slave number to zs unit number, so that misconfiguration will * not set up the keyboard as ttya, etc. */ void zs_ap_attach(device_t parent, device_t self, void *aux) { struct zsc_softc *zsc = device_private(self); struct apbus_attach_args *apa = aux; struct zsc_attach_args zsc_args; volatile struct zschan *zc; struct zs_chanstate *cs; int s, zs_unit, channel; volatile u_int *txBfifo = (void *)(apa->apa_hwbase + PORTB_XPORT); volatile u_int *rxBfifo = (void *)(apa->apa_hwbase + PORTB_RPORT); volatile u_int *txAfifo = (void *)(apa->apa_hwbase + PORTA_XPORT); volatile u_int *rxAfifo = (void *)(apa->apa_hwbase + PORTA_RPORT); volatile u_int *portBctl = (void *)(apa->apa_hwbase + PORTB_OFFSET); volatile u_int *portActl = (void *)(apa->apa_hwbase + PORTA_OFFSET); volatile u_int *esccregs = (void *)(apa->apa_hwbase + ESCC_REG); zsc->zsc_dev = self; zs_unit = device_unit(self); zsaddr[zs_unit] = (void *)apa->apa_hwbase; aprint_normal(" slot%d addr 0x%lx\n", apa->apa_slotno, apa->apa_hwbase); txAfifo[DMA_MODE_REG] = rxAfifo[DMA_MODE_REG] = DMA_EXTRDY; txBfifo[DMA_MODE_REG] = rxBfifo[DMA_MODE_REG] = DMA_EXTRDY; /* assert DTR */ /* XXX */ portBctl[PORT_CTL] = portActl[PORT_CTL] = PORTCTL_DTR; /* select RS-232C (ch1 only) */ portActl[PORT_SEL] = PORTSEL_RS232C; /* enable SCC interrupts */ esccregs[ESCCREG_INTMASK] = INTMASK_SCC; zs_delay = zs_ap_delay; /* * Initialize software state for each channel. */ for (channel = 0; channel < 2; channel++) { zsc_args.channel = channel; zsc_args.hwflags = zs_hwflags[zs_unit][channel]; cs = &zsc->zsc_cs_store[channel]; zsc->zsc_cs[channel] = cs; zs_lock_init(cs); cs->cs_channel = channel; cs->cs_private = NULL; cs->cs_ops = &zsops_null; cs->cs_brg_clk = PCLK / 16; zc = zs_get_chan_addr(zs_unit, channel); cs->cs_reg_csr = &zc->zc_csr; cs->cs_reg_data = &zc->zc_data; memcpy(cs->cs_creg, zs_init_reg, 16); memcpy(cs->cs_preg, zs_init_reg, 16); /* XXX: Get these from the EEPROM instead? */ /* XXX: See the mvme167 code. Better. */ if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) cs->cs_defspeed = zs_get_speed(cs); else cs->cs_defspeed = zs_defspeed; cs->cs_defcflag = zs_def_cflag; /* Make these correspond to cs_defcflag (-crtscts) */ cs->cs_rr0_dcd = ZSRR0_DCD; cs->cs_rr0_cts = 0; cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; cs->cs_wr5_rts = 0; /* * Clear the master interrupt enable. * The INTENA is common to both channels, * so just do it on the A channel. */ if (channel == 0) { zs_write_reg(cs, 9, 0); } /* * Look for a child driver for this channel. * The child attach will setup the hardware. */ if (!config_found(self, (void *)&zsc_args, zs_print)) { /* No sub-driver. Just reset it. */ uint8_t reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; s = splhigh(); zs_write_reg(cs, 9, reset); splx(s); } } /* * Now safe to install interrupt handlers. */ zsc->zsc_si = softint_establish(SOFTINT_SERIAL, (void (*)(void *))zsc_intr_soft, zsc); apbus_intr_establish(1, /* interrupt level ( 0 or 1 ) */ NEWS5000_INT1_SCC, 0, /* priority */ zshard_ap, zsc, apa->apa_name, apa->apa_ctlnum); /* XXX; evcnt_attach() ? */ #if 0 { u_int x; /* determine SCC/ESCC type */ x = zs_read_reg(cs, 15); zs_write_reg(cs, 15, x | ZSWR15_ENABLE_ENHANCED); if (zs_read_reg(cs, 15) & ZSWR15_ENABLE_ENHANCED) { /* ESCC Z85230 */ zs_write_reg(cs, 7, ZSWR7P_EXTEND_READ | ZSWR7P_TX_FIFO); } } #endif /* * Set the master interrupt enable and interrupt vector. * (common to both channels, do it on A) */ cs = zsc->zsc_cs[0]; s = splhigh(); /* interrupt vector */ zs_write_reg(cs, 2, zs_init_reg[2]); /* master interrupt control (enable) */ zs_write_reg(cs, 9, zs_init_reg[9]); splx(s); }
/* * 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; }