Example #1
0
/*
 * 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);
}
Example #2
0
/*
 * 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);
		}
	}
}
Example #4
0
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;
}
Example #5
0
/* 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;
}
Example #6
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;
}