예제 #1
0
void
zskbd_softint(struct zs_chanstate *cs)
{
	struct zskbd_softc *sc = cs->cs_private;
	struct zskbd_devconfig *dc = sc->sc_dc;
	int rr0;

	/* handle pending transmissions */
	if (dc->txq_head != dc->txq_tail) {
		int s;

		s = splzs();
		while (dc->txq_head != dc->txq_tail) {
			rr0 = zs_read_csr(cs);
			if ((rr0 & ZSRR0_TX_READY) == 0)
				break;
			zs_write_data(cs, dc->txq[dc->txq_head]);
			dc->txq_head = (dc->txq_head + 1) & ~ZSKBD_TXQ_LEN;
		}
		splx(s);
	}

	/* handle incoming keystrokes/config */
	while (dc->rxq_head != dc->rxq_tail) {
		zskbd_process(cs, dc->rxq[dc->rxq_head]);
		dc->rxq_head = (dc->rxq_head + 1) & ~ZSKBD_RXQ_LEN;
	}
}
예제 #2
0
/*
 * 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);
		}
	}
}
예제 #3
0
/*
 * Polled output char.
 */
static void
zs_putc(int c)
{
	int s, rr0;

	s = splzs();
	/* Wait for transmitter to become ready. */
	do {
		rr0 = zs_read_csr(&zscn_cs);
	} while ((rr0 & ZSRR0_TX_READY) == 0);

	zs_write_data(&zscn_cs, c);
	splx(s);
}
예제 #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);
}
예제 #5
0
/*
 * Start or restart transmission.
 */
void
zsstart(struct tty *tp)
{
	struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
	struct zs_chanstate *cs = zst->zst_cs;
	u_char *tba;
	int tbc, rr0;
	int s;

	s = spltty();
	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
		goto out;
	if (zst->zst_tx_stopped)
		goto out;

	ttwakeupwr(tp);
	if (tp->t_outq.c_cc == 0)
		goto out;

	/* Grab the first contiguous region of buffer space. */
	tba = tp->t_outq.c_cf;
	tbc = ndqb(&tp->t_outq, 0);

#if IPL_ZS != IPL_TTY
	(void)splzs();
#endif

	zst->zst_tba = tba;
	zst->zst_tbc = tbc;
	SET(tp->t_state, TS_BUSY);
	zst->zst_tx_busy = 1;

	do {
		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++;
	} while (zst->zst_tbc > 0);

out:
	splx(s);
}
예제 #6
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;
	}
}
예제 #7
0
/* expects to be in splzs() */
int
zskbd_send(struct zs_chanstate *cs, uint8_t *c, u_int len)
{
	struct zskbd_softc     *sc = cs->cs_private;
	struct zskbd_devconfig *dc = sc->sc_dc;
	u_int i;
	int rr0;

	while (len != 0) {
		rr0 = zs_read_csr(cs);
		if ((rr0 & ZSRR0_TX_READY) == 0) {
			/*
			 * poll until whole transmission complete during
			 * autoconf
			 */
			if (cold) {
				for (i = 1000; i != 0; i--) {
					if ((rr0 & ZSRR0_TX_READY) != 0)
						break;
					delay(100);
				}
				if (i == 0)
					return EIO;
			} else
				break;
		}
		zs_write_data(cs, *c++);
		len--;
	}

	/*
	 * Enqueue any remaining bytes.
	 */
	while (len != 0) {
		dc->txq[dc->txq_tail] = *c++;
		dc->txq_tail = (dc->txq_tail + 1) & ~ZSKBD_TXQ_LEN;
		len--;
		cs->cs_softreq = 1;
	}

	return 0;
}
예제 #8
0
/*
 * Polled input char.
 */
static int
zs_getc(void)
{
	int s, c, rr0;

	s = splzs();
	/* Wait for a character to arrive. */
	do {
		rr0 = zs_read_csr(&zscn_cs);
	} while ((rr0 & ZSRR0_RX_READY) == 0);

	c = zs_read_data(&zscn_cs);
	splx(s);

	/*
	 * This is used by the kd driver to read scan codes,
	 * so don't translate '\r' ==> '\n' here...
	 */
	return (c);
}
예제 #9
0
/*
 * MD functions for setting the baud rate and control modes.
 */
int
zs_set_speed(struct zs_chanstate *cs, int bps)
{
	int tconst, real_bps;

#if 0
	while (!(zs_read_csr(cs) & ZSRR0_TX_READY))
		{/*nop*/}
#endif
	/* Wait for transmit buffer to empty */
	if (bps == 0) {
		return (0);
	}

#ifdef	DIAGNOSTIC
	if (cs->cs_brg_clk == 0)
		panic("zs_set_speed");
#endif

	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
	if (tconst < 0)
		return (EINVAL);

	/* Convert back to make sure we can do it. */
	real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);

	/* XXX - Allow some tolerance here? */
#if 0
	if (real_bps != bps)
		return (EINVAL);
#endif

	cs->cs_preg[12] = tconst;
	cs->cs_preg[13] = tconst >> 8;

	/* Caller will stuff the pending registers. */
	return (0);
}
예제 #10
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;
		}
	}
}
예제 #11
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;
}
예제 #12
0
void
zskbd_attach(struct device *parent, struct device *self, void *aux)
{
	struct zskbd_softc	       *sc = (struct zskbd_softc *)self;
	struct zsc_softc      	       *zsc = (struct zsc_softc *)parent;
	struct zsc_attach_args	       *args = aux;
	struct zs_chanstate	       *cs;
	struct wskbddev_attach_args	wskaa;
	int				s, channel, rc;
	uint8_t				key;

	printf(": ");

	/* Establish ourself with the MD z8530 driver */
	channel = args->channel;
	cs = zsc->zsc_cs[channel];
	cs->cs_ops = &zskbd_zsops;
	cs->cs_private = sc;

	sc->sc_dc = malloc(sizeof(struct zskbd_devconfig), M_DEVBUF,
	    M_WAITOK | M_ZERO);

	s = splzs();
	zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET);
	cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE;
	cs->cs_preg[4] = (cs->cs_preg[4] & ZSWR4_CLK_MASK) |
			 (ZSWR4_ONESB | ZSWR4_PARENB);	/* 1 stop, odd parity */
	cs->cs_preg[15] &= ~ZSWR15_ENABLE_ENHANCED;
	zs_set_speed(cs, ZSKBD_BAUD);
	zs_loadchannelregs(cs);

	/*
	 * Empty the keyboard input buffer (if the keyboard is the console
	 * input device and the user invoked UKC, the `enter key up' event
	 * will still be pending in the buffer).
	 */
	while ((zs_read_csr(cs) & ZSRR0_RX_READY) != 0)
		(void)zs_read_data(cs);

	/*
	 * Ask the keyboard for its DIP switch settings. This will also let
	 * us know whether the keyboard is connected.
	 */
	sc->sc_dc->expected = 2;
	zskbd_ctrl(cs, ZSKBD_CTRL_A_RCB, 0, 0, 0);
	while (sc->sc_dc->expected != 0) {
		rc = zskbd_poll(cs, &key);
		if (rc != 0) {
			if (rc == ENXIO && sc->sc_dc->expected == 2) {
				printf("no keyboard");
				/*
				 * Attach wskbd nevertheless, in case the
				 * keyboard is plugged late.
				 */
				sc->sc_dc->expected = 0;
				goto dip;
			} else {
				printf("i/o error\n");
				return;
			}
		}

		zskbd_process(cs, key);
	}

	printf("dip switches %02x", sc->sc_dc->dip);
dip:

	/*
	 * Disable key click by default. Note that if the keyboard is not
	 * currently connected, the bit will nevertheless stick and will
	 * disable the click as soon as a keyboard led needs to be lit.
	 */
	zskbd_ctrl(cs, ZSKBD_CTRL_A_NOCLICK, 0, 0, 0);

	splx(s);

	printf("\n");

	if (zskbd_is_console)
		sc->sc_dc->enabled = 1;

	/* attach wskbd */
	wskaa.console =		zskbd_is_console;
	wskaa.keymap =		&sgikbd_wskbd_keymapdata;
	wskaa.accessops =	&zskbd_wskbd_accessops;
	wskaa.accesscookie =	cs;
	sc->sc_dc->wskbddev =	config_found(self, &wskaa, wskbddevprint);
}
예제 #13
0
/*
 * Open a zs serial (tty) port.
 */
int
zsopen(dev_t dev, int flags, int mode, struct proc *p)
{
	struct zstty_softc *zst;
	struct zs_chanstate *cs;
	struct tty *tp;
	int s;
#if IPL_ZS != IPL_TTY
	int s2;
#endif
	int error;

	zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
	if (zst == NULL)
		return (ENXIO);

	tp = zst->zst_tty;
	cs = zst->zst_cs;

	/* If KGDB took the line, then tp==NULL */
	if (tp == NULL)
		return (EBUSY);

	if (ISSET(tp->t_state, TS_ISOPEN) &&
	    ISSET(tp->t_state, TS_XCLUDE) &&
	    suser(p, 0) != 0)
		return (EBUSY);

	s = spltty();

	/*
	 * Do the following iff this is a first open.
	 */
	if (!ISSET(tp->t_state, TS_ISOPEN)) {
		struct termios t;

		tp->t_dev = dev;

		/* Call the power management hook. */
		if (cs->enable) {
			if ((*cs->enable)(cs)) {
				splx(s);
				printf("%s: device enable failed\n",
				    zst->zst_dev.dv_xname);
				return (EIO);
			}
		}

		/*
		 * Initialize the termios status to the defaults.  Add in the
		 * sticky bits from TIOCSFLAGS.
		 */
		t.c_ispeed = 0;
		t.c_ospeed = cs->cs_defspeed;
		t.c_cflag = cs->cs_defcflag;
		if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL))
			SET(t.c_cflag, CLOCAL);
		if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS))
			SET(t.c_cflag, CRTSCTS);
		if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF))
			SET(t.c_cflag, MDMBUF);

#if IPL_ZS != IPL_TTY
		s2 = splzs();
#endif

		/*
		 * Turn on receiver and status interrupts.
		 * We defer the actual write of the register to zsparam(),
		 * but we must make sure status interrupts are turned on by
		 * the time zsparam() reads the initial rr0 state.
		 */
		SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE);

		/* Clear PPS capture state on first open. */
		zst->zst_ppsmask = 0;

#if IPL_ZS != IPL_TTY
		splx(s2);
#endif

		/* Make sure zsparam will see changes. */
		tp->t_ospeed = 0;
		(void)zsparam(tp, &t);

		/*
		 * Note: zsparam has done: cflag, ispeed, ospeed
		 * so we just need to do: iflag, oflag, lflag, cc
		 * For "raw" mode, just leave all zeros.
		 */
		if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) {
			tp->t_iflag = TTYDEF_IFLAG;
			tp->t_oflag = TTYDEF_OFLAG;
			tp->t_lflag = TTYDEF_LFLAG;
		} else {
			tp->t_iflag = 0;
			tp->t_oflag = 0;
			tp->t_lflag = 0;
		}
		ttychars(tp);
		ttsetwater(tp);

		if (ZSDIALOUT(dev))
			SET(tp->t_state, TS_CARR_ON);
		else
			CLR(tp->t_state, TS_CARR_ON);

#if IPL_ZS != IPL_TTY
		s2 = splzs();
#endif

		/* Clear the input ring, and unblock. */
		zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
		zst->zst_rbavail = zstty_rbuf_size;
		zs_iflush(cs);
		CLR(zst->zst_rx_flags, RX_ANY_BLOCK);
		zs_hwiflow(zst);

#if IPL_ZS != IPL_TTY
		splx(s2);
#endif
	}

	if (ZSDIALOUT(dev)) {
		if (ISSET(tp->t_state, TS_ISOPEN)) {
			/* someone already is dialed in... */
			splx(s);
			return EBUSY;
		}
		cs->cs_cua = 1;
	}

	error = 0;
	/* wait for carrier if necessary */
	if (ISSET(flags, O_NONBLOCK)) {
		if (!ZSDIALOUT(dev) && cs->cs_cua) {
			/* Opening TTY non-blocking... but the CUA is busy */
			error = EBUSY;
		}
	} else
	  while (cs->cs_cua ||
	    (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON))) {
		int rr0;

		error = 0;
		SET(tp->t_state, TS_WOPEN);

		if (!ZSDIALOUT(dev) && !cs->cs_cua) {
			/*
			 * Turn on DTR.  We must always do this on non-CUA
			 * devices, even if carrier is not present, because
			 * otherwise we'd have to use TIOCSDTR immediately
			 * after setting CLOCAL, which applications do not
			 * expect.  We always assert DTR while the device is
			 * open unless explicitly requested to deassert it.
			 */
#if IPL_ZS != IPL_TTY
			s2 = splzs();
#endif
			zs_modem(zst, 1);
			rr0 = zs_read_csr(cs);
#if IPL_ZS != IPL_TTY
			splx(s2);
#endif

			/* loop, turning on the device, until carrier present */
			if (ISSET(rr0, ZSRR0_DCD) ||
			    ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR))
				SET(tp->t_state, TS_CARR_ON);
		}

		if ((ISSET(tp->t_cflag, CLOCAL) ||
		    ISSET(tp->t_state, TS_CARR_ON)) && !cs->cs_cua)
			break;

		error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
		    ttopen, 0);

		if (!ZSDIALOUT(dev) && cs->cs_cua && error == EINTR) {
			error = 0;
			continue;
		}

		if (error) {
			if (!ISSET(tp->t_state, TS_ISOPEN)) {
#if IPL_ZS != IPL_TTY
				s2 = splzs();
#endif
				zs_modem(zst, 0);
#if IPL_ZS != IPL_TTY
				splx(s2);
#endif
				CLR(tp->t_state, TS_WOPEN);
				ttwakeup(tp);
			}
			if (ZSDIALOUT(dev))
				cs->cs_cua = 0;
			CLR(tp->t_state, TS_WOPEN);
			break;
		}
		if (!ZSDIALOUT(dev) && cs->cs_cua)
			continue;
	}

	splx(s);

	if (error == 0)
		error = ((*linesw[tp->t_line].l_open)(dev, tp, p));
	if (error)
		goto bad;

	return (0);

bad:
	if (!ISSET(tp->t_state, TS_ISOPEN)) {
		/*
		 * We failed to open the device, and nobody else had it opened.
		 * Clean up the state as appropriate.
		 */
		zs_shutdown(zst);
	}

	return (error);
}
예제 #14
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]);
	}
}