static void
ewskbd_zsc_stint(struct zs_chanstate *cs, int force)
{

	zs_write_csr(cs, ZSWR0_RESET_STATUS);
	cs->cs_softreq = 1;
}
Esempio n. 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);
		}
	}
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
/*
 * 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;
	}
}
Esempio n. 6
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;
}
Esempio n. 7
0
/*
 * 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;
		}
	}
}
Esempio n. 8
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]);
	}
}
/*
 * 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;
}
Esempio n. 10
0
/*
 * 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]);
}