Beispiel #1
0
void
zstty_stsoft(struct zstty_softc *zst, struct tty *tp)
{
	struct zs_chanstate *cs = zst->zst_cs;
	uint8_t rr0, delta;
	int s;

	s = splzs();
	rr0 = cs->cs_rr0;
	delta = cs->cs_rr0_delta;
	cs->cs_rr0_delta = 0;
	splx(s);

	if (ISSET(delta, cs->cs_rr0_dcd)) {
		/*
		 * Inform the tty layer that carrier detect changed.
		 */
		(void)(*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD));
	}

	if (ISSET(delta, cs->cs_rr0_cts)) {
		/* Block or unblock output according to flow control. */
		if (ISSET(rr0, cs->cs_rr0_cts)) {
			zst->zst_tx_stopped = 0;
			(*linesw[tp->t_line].l_start)(tp);
		} else {
			zst->zst_tx_stopped = 1;
		}
	}
}
Beispiel #2
0
/*
 * Try to block or unblock input using hardware flow-control.
 * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
 * if this function returns non-zero, the TS_TBLOCK flag will
 * be set or cleared according to the "block" arg passed.
 */
int
zshwiflow(struct tty *tp, int block)
{
	struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
	struct zs_chanstate *cs = zst->zst_cs;
	int s;

	if (cs->cs_wr5_rts == 0)
		return (0);

	s = splzs();
	if (block) {
		if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
			SET(zst->zst_rx_flags, RX_TTY_BLOCKED);
			zs_hwiflow(zst);
		}
	} else {
		if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
			CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
			zst->zst_rx_ready = 1;
			cs->cs_softreq = 1;
		}
		if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
			CLR(zst->zst_rx_flags, RX_TTY_BLOCKED);
			zs_hwiflow(zst);
		}
	}
	splx(s);
	return (1);
}
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;
	}
}
static int
ewskbd_zsc_init(struct zs_chanstate *cs)
{
	int s;

	s = splzs();

	zs_write_reg(cs, 9, ZSWR9_B_RESET);
	DELAY(100);
	zs_write_reg(cs, 9, ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR);

	cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE;
	cs->cs_preg[2] = 0;
	cs->cs_preg[3] = ZSWR3_RX_8 | ZSWR3_RX_ENABLE;
	cs->cs_preg[4] = ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_PARENB;
	cs->cs_preg[5] = ZSWR5_TX_8 | ZSWR5_RTS | ZSWR5_TX_ENABLE;
	cs->cs_preg[6] = 0;
	cs->cs_preg[7] = 0;
	cs->cs_preg[8] = 0;
	cs->cs_preg[9] = ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR;
	cs->cs_preg[10] = 0;
	cs->cs_preg[11] = ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD |
	    ZSWR11_TRXC_OUT_ENA | ZSWR11_TRXC_BAUD;
	/* reg[11] and reg[12] are set by zs_set_speed() with cs_brg_clk */
	zs_set_speed(cs, EWSKBD_BAUD);
	cs->cs_preg[14] = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA;
	cs->cs_preg[15] = 0;

	zs_loadchannelregs(cs);

	splx(s);

	return 0;
}
void
zskbd_wskbd_set_leds(void *cookie, int leds)
{
	struct zs_chanstate *cs = cookie;
	int 	s;
	uint8_t	a_on, a_off, b_on, b_off;

	a_on = a_off = b_on = b_off = 0;

	if (leds & WSKBD_LED_CAPS)
		a_on |=  ZSKBD_CTRL_A_CAPSLK;
	else
		a_off |= ZSKBD_CTRL_A_CAPSLK;

	if (leds & WSKBD_LED_NUM)
		a_on |=  ZSKBD_CTRL_A_NUMLK;
	else
		a_off |= ZSKBD_CTRL_A_NUMLK;

	if (leds & WSKBD_LED_SCROLL)
		b_on |=  ZSKBD_CTRL_B_SCRLK;
	else
		b_off |= ZSKBD_CTRL_B_SCRLK;

	s = splzs();
	zskbd_ctrl(cs, a_on, a_off, b_on, b_off);
	splx(s);
}
void
zskbd_wskbd_set_keyclick(void *cookie, int on)
{
	struct zs_chanstate    *cs = cookie;
	int			s;

	if (on) {
		if (!zskbd_wskbd_get_keyclick(cookie)) {
			s = splzs();
			zskbd_ctrl(cs, 0, ZSKBD_CTRL_A_NOCLICK, 0, 0);
			splx(s);
		}
	} else {
		if (zskbd_wskbd_get_keyclick(cookie)) {
			s = splzs();
			zskbd_ctrl(cs, ZSKBD_CTRL_A_NOCLICK, 0, 0, 0);
			splx(s);
		}
	}
}
Beispiel #7
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);
}
Beispiel #8
0
void
zstty_txsoft(struct zstty_softc *zst, struct tty *tp)
{
	int s;

	CLR(tp->t_state, TS_BUSY);
	if (ISSET(tp->t_state, TS_FLUSH))
		CLR(tp->t_state, TS_FLUSH);
	else {
		s = splzs();
		ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf));
		splx(s);
	}
	(*linesw[tp->t_line].l_start)(tp);
}
Beispiel #9
0
void
zs_shutdown(struct zstty_softc *zst)
{
	struct zs_chanstate *cs = zst->zst_cs;
	struct tty *tp = zst->zst_tty;
	int s;

	s = splzs();

	/* If we were asserting flow control, then deassert it. */
	SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
	zs_hwiflow(zst);

	/* Clear any break condition set with TIOCSBRK. */
	zs_break(cs, 0);

	/* Turn off PPS capture on last close. */
	zst->zst_ppsmask = 0;

	/*
	 * Hang up if necessary.  Wait a bit, so the other side has time to
	 * notice even if we immediately open the port again.
	 */
	if (ISSET(tp->t_cflag, HUPCL) || ISSET(tp->t_state, TS_WOPEN)) {
		zs_modem(zst, 0);
		/* hold low for 1 second */
		(void)tsleep(cs, TTIPRI, ttclos, hz);
	}

	/* Turn off interrupts if not the console. */
	if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
		CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE);
		cs->cs_creg[1] = cs->cs_preg[1];
		zs_write_reg(cs, 1, cs->cs_creg[1]);
	}

	/* Call the power management hook. */
	if (cs->disable) {
#ifdef DIAGNOSTIC
		if (!cs->enabled)
			panic("%s: not enabled?", __func__);
#endif
		(*cs->disable)(zst->zst_cs);
	}

	splx(s);
}
Beispiel #10
0
/*
 * Stop output, e.g., for ^S or output flush.
 */
int
zsstop(struct tty *tp, int flag)
{
	struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
	int s;

	s = splzs();
	if (ISSET(tp->t_state, TS_BUSY)) {
		/* Stop transmitting at the next chunk. */
		zst->zst_tbc = 0;
		zst->zst_heldtbc = 0;
		if (!ISSET(tp->t_state, TS_TTSTOP))
			SET(tp->t_state, TS_FLUSH);
	}
	splx(s);
	return 0;
}
Beispiel #11
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);
}
Beispiel #12
0
/*
 * Polled output char.
 */
void
zs_putc(void *arg, int c)
{
	register volatile struct zschan *zc = arg;
	register int s, rr0;

	s = splzs();
	/* Wait for transmitter to become ready. */
	do {
		rr0 = zc->zc_csr;
		ZS_DELAY();
	} while ((rr0 & ZSRR0_TX_READY) == 0);

	zc->zc_data = c;
	wbflush();
	ZS_DELAY();
	splx(s);
}
Beispiel #13
0
int
zs_getc(void *arg)
{
	register volatile struct zschan *zc = arg;
	register int s, c, rr0;

	s = splzs();
	/* Wait for a character to arrive. */
	do {
		rr0 = zc->zc_csr;
		ZS_DELAY();
	} while ((rr0 & ZSRR0_RX_READY) == 0);

	c = zc->zc_data;
	ZS_DELAY();
	splx(s);

	return (c);
}
Beispiel #14
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);
}
Beispiel #15
0
void
zstty_diag(void *arg)
{
	struct zstty_softc *zst = arg;
	int overflows, floods;
	int s;

	s = splzs();
	overflows = zst->zst_overflows;
	zst->zst_overflows = 0;
	floods = zst->zst_floods;
	zst->zst_floods = 0;
	zst->zst_errors = 0;
	splx(s);

	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
	    zst->zst_dev.dv_xname,
	    overflows, overflows == 1 ? "" : "s",
	    floods, floods == 1 ? "" : "s");
}
Beispiel #16
0
void
zscninit(struct consdev *cn)
{
	volatile struct zschan *cnchan = (volatile void *)IIOV(ZSCN_PHYSADDR);
	int s;

	memset(&zscn_cs, 0, sizeof(struct zs_chanstate));
	zscn_cs.cs_reg_csr = &cnchan->zc_csr;
	zscn_cs.cs_reg_data = &cnchan->zc_data;
	zscn_cs.cs_channel = 0;
	zscn_cs.cs_brg_clk = PCLK / 16;
	memcpy(zscn_cs.cs_preg, zs_init_reg, 16);
	zscn_cs.cs_preg[4] = ZSWR4_CLK_X16 | ZSWR4_ONESB; /* XXX */
	zscn_cs.cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
	zs_set_speed(&zscn_cs, ZSCN_SPEED);
	s = splzs();
	zs_write_reg(&zscn_cs, 9, 0);
	zs_write_reg(&zscn_cs, 9, ZSWR9_HARD_RESET);
	zs_loadchannelregs(&zscn_cs);
	splx(s);
	conschan = cnchan;
}
Beispiel #17
0
int
zs_set_modes(struct zs_chanstate *cs, int cflag)
{
	int s;

	/*
	 * Output hardware flow control on the chip is horrendous:
	 * if carrier detect drops, the receiver is disabled, and if
	 * CTS drops, the transmitter is stoped IN MID CHARACTER!
	 * Therefore, NEVER set the HFC bit, and instead use the
	 * status interrupt to detect CTS changes.
	 */
	s = splzs();
#if 0	/* XXX - See below. */
	if (cflag & CLOCAL) {
		cs->cs_rr0_dcd = 0;
		cs->cs_preg[15] &= ~ZSWR15_DCD_IE;
	} else {
		/* XXX - Need to notice DCD change here... */
		cs->cs_rr0_dcd = ZSRR0_DCD;
		cs->cs_preg[15] |= ZSWR15_DCD_IE;
	}
#endif	/* XXX */
	if (cflag & CRTSCTS) {
		cs->cs_wr5_dtr = ZSWR5_DTR;
		cs->cs_wr5_rts = ZSWR5_RTS;
		cs->cs_rr0_cts = ZSRR0_CTS;
		cs->cs_preg[15] |= ZSWR15_CTS_IE;
	} else {
		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
		cs->cs_wr5_rts = 0;
		cs->cs_rr0_cts = 0;
		cs->cs_preg[15] &= ~ZSWR15_CTS_IE;
	}
	splx(s);

	/* Caller will stuff the pending registers. */
	return (0);
}
static void
ewskbd_zsc_softint(struct zs_chanstate *cs)
{
	struct ewskbd_softc *sc;
	struct ewskbd_devconfig *dc;

	sc = cs->cs_private;
	dc = sc->sc_dc;

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

		dc->state &= ~TX_READY;

		s = splzs();
		zs_write_data(cs, dc->txq[dc->txq_head]);
		splx(s);

		dc->txq_head = EWSKBD_NEXTTXQ(dc->txq_head);
	}

	/* don't bother if nobody is listening */
	if (!dc->enabled) {
		dc->rxq_head = dc->rxq_tail;
		return;
	}

	/* handle incoming keystrokes/config */
	while (dc->rxq_head != dc->rxq_tail) {
		uint8_t key = dc->rxq[dc->rxq_head];

		/* toss wskbd a bone */
		ewskbd_wskbd_input(cs, key);

		dc->rxq_head = EWSKBD_NEXTRXQ(dc->rxq_head);
	}
}
Beispiel #19
0
int
zs_set_modes(struct zs_chanstate *cs, int cflag	/* bits per second */)
{
	int s;

	/*
	 * Output hardware flow control on the chip is horrendous:
	 * if carrier detect drops, the receiver is disabled, and if
	 * CTS drops, the transmitter is stoped IN MID CHARACTER!
	 * Therefore, NEVER set the HFC bit, and instead use the
	 * status interrupt to detect CTS changes.
	 */
	s = splzs();
	cs->cs_rr0_pps = 0;
	if ((cflag & (CLOCAL | MDMBUF)) != 0) {
		cs->cs_rr0_dcd = 0;
		if ((cflag & MDMBUF) == 0)
			cs->cs_rr0_pps = ZSRR0_DCD;
	} else
		cs->cs_rr0_dcd = ZSRR0_DCD;
	if ((cflag & CRTSCTS) != 0) {
		cs->cs_wr5_dtr = ZSWR5_DTR;
		cs->cs_wr5_rts = ZSWR5_RTS;
		cs->cs_rr0_cts = ZSRR0_CTS;
	} else if ((cflag & MDMBUF) != 0) {
		cs->cs_wr5_dtr = 0;
		cs->cs_wr5_rts = ZSWR5_DTR;
		cs->cs_rr0_cts = ZSRR0_DCD;
	} else {
		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
		cs->cs_wr5_rts = 0;
		cs->cs_rr0_cts = 0;
	}
	splx(s);

	/* Caller will stuff the pending registers. */
	return (0);
}
static void
ewskbd_wskbd_set_leds(void *cookie, int leds)
{
	struct zs_chanstate *cs;
	struct ewskbd_softc *sc;
	int s;
	uint8_t	cmd;

	cs = cookie;
	sc = cs->cs_private;
	cmd = 0;

	if (leds & WSKBD_LED_CAPS)
		cmd |= EWSKBD_CAPSLOCK;

	sc->sc_dc->leds = cmd;

	cmd |= EWSKBD_SETLEDS;

	s = splzs();
	ewskbd_zsc_send(cs, &cmd, 1);
	splx(s);
}
Beispiel #21
0
int
zsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
	struct zs_chanstate *cs = zst->zst_cs;
	struct tty *tp = zst->zst_tty;
	int error;
	int s;

	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

	error = ttioctl(tp, cmd, data, flag, p);
	if (error >= 0)
		return (error);

#ifdef	ZS_MD_IOCTL
	error = ZS_MD_IOCTL;
	if (error >= 0)
		return (error);
#endif	/* ZS_MD_IOCTL */

	error = 0;

	s = splzs();

	switch (cmd) {
	case TIOCSBRK:
		zs_break(cs, 1);
		break;

	case TIOCCBRK:
		zs_break(cs, 0);
		break;

	case TIOCGFLAGS:
		*(int *)data = zst->zst_swflags;
		break;

	case TIOCSFLAGS:
		error = suser(p, 0);
		if (error)
			break;
		zst->zst_swflags = *(int *)data;
		if (ISSET(zst->zst_hwflags, ZS_HWFLAG_NO_DCD))
			SET(zst->zst_swflags, TIOCFLAG_SOFTCAR);
		break;

	case TIOCSDTR:
		zs_modem(zst, 1);
		break;

	case TIOCCDTR:
		zs_modem(zst, 0);
		break;

	case TIOCMSET:
	case TIOCMBIS:
	case TIOCMBIC:
		tiocm_to_zs(zst, cmd, *(int *)data);
		break;

	case TIOCMGET:
		*(int *)data = zs_to_tiocm(zst);
		break;

	default:
		error = ENOTTY;
		break;
	}

	splx(s);

	return (error);
}
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);
}
Beispiel #23
0
/*
 * Attach a found zs.
 */
static void
zs_attach(device_t parent, device_t self, void *aux)
{
	struct zsc_softc *zsc = device_private(self);
	struct intio_attach_args *ia = aux;
	struct zsc_attach_args zsc_args;
	volatile struct zschan *zc;
	struct zs_chanstate *cs;
	int r, s, zs_unit, channel;

	zsc->zsc_dev = self;
	aprint_normal("\n");

	zs_unit = device_unit(self);
	zsc->zsc_addr = (void *)ia->ia_addr;

	ia->ia_size = 8;
	r = intio_map_allocate_region(parent, ia, INTIO_MAP_ALLOCATE);
#ifdef DIAGNOSTIC
	if (r)
		panic("zs: intio IO map corruption");
#endif

	/*
	 * Initialize software state for each channel.
	 */
	for (channel = 0; channel < 2; channel++) {
		device_t child;

		zsc_args.channel = channel;
		zsc_args.hwflags = 0;
		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;

		if (channel == 0)
			zc = (volatile void *)IIOV(&zsc->zsc_addr->zs_chan_a);
		else
			zc = (volatile void *)IIOV(&zsc->zsc_addr->zs_chan_b);
		cs->cs_reg_csr  = &zc->zc_csr;
		cs->cs_reg_data = &zc->zc_data;

		zs_init_reg[2] = ia->ia_intr;
		memcpy(cs->cs_creg, zs_init_reg, 16);
		memcpy(cs->cs_preg, zs_init_reg, 16);

		if (zc == conschan) {
			zsc_args.hwflags |= ZS_HWFLAG_CONSOLE;
			cs->cs_defspeed = zs_get_speed(cs);
			cs->cs_defcflag = zscn_def_cflag;
		} else {
			cs->cs_defspeed = 9600;
			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) {
			s = splzs();
			zs_write_reg(cs, 9, 0);
			splx(s);
		}

		/*
		 * Look for a child driver for this channel.
		 * The child attach will setup the hardware.
		 */
		child = config_found(self, (void *)&zsc_args, zs_print);
#if ZSTTY > 0
		if (zc == conschan &&
		    ((child && strcmp(device_xname(child), "zstty0")) ||
		     child == NULL)) /* XXX */
			panic("%s: console device mismatch", __func__);
#endif
		if (child == NULL) {
			/* No sub-driver.  Just reset it. */
			uint8_t reset = (channel == 0) ?
				ZSWR9_A_RESET : ZSWR9_B_RESET;
			s = splzs();
			zs_write_reg(cs,  9, reset);
			splx(s);
		}
	}

	/*
	 * Now safe to install interrupt handlers.
	 */
	if (intio_intr_establish(ia->ia_intr, "zs", zshard, zsc))
		panic("%s: interrupt vector busy", __func__);
	zsc->zsc_softintr_cookie = softint_establish(SOFTINT_SERIAL,
	    (void (*)(void *))zsc_intr_soft, zsc);
	/* XXX; evcnt_attach() ? */

	/*
	 * Set the master interrupt enable and interrupt vector.
	 * (common to both channels, do it on A)
	 */
	cs = zsc->zsc_cs[0];
	s = splzs();
	/* interrupt vector */
	zs_write_reg(cs, 2, ia->ia_intr);
	/* master interrupt control (enable) */
	zs_write_reg(cs, 9, zs_init_reg[9]);
	splx(s);
}
Beispiel #24
0
/*
 * Set ZS tty parameters from termios.
 * XXX - Should just copy the whole termios after
 * making sure all the changes could be done.
 */
int
zsparam(struct tty *tp, struct termios *t)
{
	struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
	struct zs_chanstate *cs = zst->zst_cs;
	int ospeed;
	tcflag_t cflag;
	uint8_t tmp3, tmp4, tmp5;
	int s, error;

	ospeed = t->c_ospeed;
	cflag = t->c_cflag;

	/* Check requested parameters. */
	if (ospeed < 0)
		return (EINVAL);
	if (t->c_ispeed && t->c_ispeed != ospeed)
		return (EINVAL);

	/*
	 * For the console, always force CLOCAL and !HUPCL, so that the port
	 * is always active.
	 */
	if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) ||
	    ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
		SET(cflag, CLOCAL);
		CLR(cflag, HUPCL);
	}

	/*
	 * Only whack the UART when params change.
	 * Some callers need to clear tp->t_ospeed
	 * to make sure initialization gets done.
	 */
	if (tp->t_ospeed == ospeed &&
	    tp->t_cflag == cflag)
		return (0);

	/*
	 * Call MD functions to deal with changed
	 * clock modes or H/W flow control modes.
	 * The BRG divisor is set now. (reg 12,13)
	 */
	error = zs_set_speed(cs, ospeed);
	if (error)
		return (error);
	error = zs_set_modes(cs, cflag);
	if (error)
		return (error);

	/*
	 * Block interrupts so that state will not
	 * be altered until we are done setting it up.
	 *
	 * Initial values in cs_preg are set before
	 * our attach routine is called.  The master
	 * interrupt enable is handled by zsc.c
	 *
	 */
	s = splzs();

	/*
	 * Recalculate which status ints to enable.
	 */
	zs_maskintr(zst);

	/* Recompute character size bits. */
	tmp3 = cs->cs_preg[3];
	tmp5 = cs->cs_preg[5];
	CLR(tmp3, ZSWR3_RXSIZE);
	CLR(tmp5, ZSWR5_TXSIZE);
	switch (ISSET(cflag, CSIZE)) {
	case CS5:
		SET(tmp3, ZSWR3_RX_5);
		SET(tmp5, ZSWR5_TX_5);
		break;
	case CS6:
		SET(tmp3, ZSWR3_RX_6);
		SET(tmp5, ZSWR5_TX_6);
		break;
	case CS7:
		SET(tmp3, ZSWR3_RX_7);
		SET(tmp5, ZSWR5_TX_7);
		break;
	case CS8:
		SET(tmp3, ZSWR3_RX_8);
		SET(tmp5, ZSWR5_TX_8);
		break;
	}
	cs->cs_preg[3] = tmp3;
	cs->cs_preg[5] = tmp5;

	/*
	 * Recompute the stop bits and parity bits.  Note that
	 * zs_set_speed() may have set clock selection bits etc.
	 * in wr4, so those must preserved.
	 */
	tmp4 = cs->cs_preg[4];
	CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK);
	if (ISSET(cflag, CSTOPB))
		SET(tmp4, ZSWR4_TWOSB);
	else
		SET(tmp4, ZSWR4_ONESB);
	if (!ISSET(cflag, PARODD))
		SET(tmp4, ZSWR4_EVENP);
	if (ISSET(cflag, PARENB))
		SET(tmp4, ZSWR4_PARENB);
	cs->cs_preg[4] = tmp4;

	/* And copy to tty. */
	tp->t_ispeed = 0;
	tp->t_ospeed = ospeed;
	tp->t_cflag = cflag;

	/*
	 * If nothing is being transmitted, set up new current values,
	 * else mark them as pending.
	 */
	if (!cs->cs_heldchange) {
		if (zst->zst_tx_busy) {
			zst->zst_heldtbc = zst->zst_tbc;
			zst->zst_tbc = 0;
			cs->cs_heldchange = 1;
		} else
			zs_loadchannelregs(cs);
	}

	/*
	 * If hardware flow control is disabled, turn off the buffer water
	 * marks and unblock any soft flow control state.  Otherwise, enable
	 * the water marks.
	 */
	if (!ISSET(cflag, CHWFLOW)) {
		zst->zst_r_hiwat = 0;
		zst->zst_r_lowat = 0;
		if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
			CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
			zst->zst_rx_ready = 1;
			cs->cs_softreq = 1;
		}
		if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
			CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
			zs_hwiflow(zst);
		}
	} else {
		zst->zst_r_hiwat = zstty_rbuf_hiwat;
		zst->zst_r_lowat = zstty_rbuf_lowat;
	}

	/*
	 * Force a recheck of the hardware carrier and flow control status,
	 * since we may have changed which bits we're looking at.
	 */
	zstty_stint(cs, 1);

	splx(s);

	/*
	 * If hardware flow control is disabled, unblock any hard flow control
	 * state.
	 */
	if (!ISSET(cflag, CHWFLOW)) {
		if (zst->zst_tx_stopped) {
			zst->zst_tx_stopped = 0;
			zsstart(tp);
		}
	}

	zstty_softint(cs);

	return (0);
}
Beispiel #25
0
void
zstty_rxsoft(struct zstty_softc *zst, struct tty *tp)
{
	struct zs_chanstate *cs = zst->zst_cs;
	int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint;
	uint8_t *get, *end;
	u_int cc, scc;
	uint8_t rr1;
	int code;
	int s;

	end = zst->zst_ebuf;
	get = zst->zst_rbget;
	scc = cc = zstty_rbuf_size - zst->zst_rbavail;

	if (cc == zstty_rbuf_size) {
		zst->zst_floods++;
		if (zst->zst_errors++ == 0)
			timeout_add_sec(&zst->zst_diag_ch, 60);
	}

	/* If not yet open, drop the entire buffer content here */
	if (!ISSET(tp->t_state, TS_ISOPEN)) {
		get += cc << 1;
		if (get >= end)
			get -= zstty_rbuf_size << 1;
		cc = 0;
	}
	while (cc) {
		code = get[0];
		rr1 = get[1];
		if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) {
			if (ISSET(rr1, ZSRR1_DO)) {
				zst->zst_overflows++;
				if (zst->zst_errors++ == 0)
					timeout_add_sec(&zst->zst_diag_ch, 60);
			}
			if (ISSET(rr1, ZSRR1_FE))
				SET(code, TTY_FE);
			if (ISSET(rr1, ZSRR1_PE))
				SET(code, TTY_PE);
		}
		if ((*rint)(code, tp) == -1) {
			/*
			 * The line discipline's buffer is out of space.
			 */
			if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
				/*
				 * We're either not using flow control, or the
				 * line discipline didn't tell us to block for
				 * some reason.  Either way, we have no way to
				 * know when there's more space available, so
				 * just drop the rest of the data.
				 */
				get += cc << 1;
				if (get >= end)
					get -= zstty_rbuf_size << 1;
				cc = 0;
			} else {
				/*
				 * Don't schedule any more receive processing
				 * until the line discipline tells us there's
				 * space available (through comhwiflow()).
				 * Leave the rest of the data in the input
				 * buffer.
				 */
				SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
			}
			break;
		}
		get += 2;
		if (get >= end)
			get = zst->zst_rbuf;
		cc--;
	}

	if (cc != scc) {
		zst->zst_rbget = get;
		s = splzs();
		cc = zst->zst_rbavail += scc - cc;
		/* Buffers should be ok again, release possible block. */
		if (cc >= zst->zst_r_lowat) {
			if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) {
				CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
				SET(cs->cs_preg[1], ZSWR1_RIE);
				cs->cs_creg[1] = cs->cs_preg[1];
				zs_write_reg(cs, 1, cs->cs_creg[1]);
			}
			if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) {
				CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED);
				zs_hwiflow(zst);
			}
		}
		splx(s);
	}
}
Beispiel #26
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);
}
Beispiel #27
0
void
zstty_attach(struct device *parent, struct device *self, void *aux)
{
	struct zsc_softc *zsc = (struct zsc_softc *)parent;
	struct zstty_softc *zst = (struct zstty_softc *)self;
	struct cfdata *cf = self->dv_cfdata;
	struct zsc_attach_args *args = aux;
	struct zs_chanstate *cs;
	struct tty *tp;
	int channel, s, tty_unit;
	dev_t dev;
	const char *i, *o;
	int dtr_on;
	int resetbit;

	timeout_set(&zst->zst_diag_ch, zstty_diag, zst);

	tty_unit = zst->zst_dev.dv_unit;
	channel = args->channel;
	cs = zsc->zsc_cs[channel];
	cs->cs_private = zst;
	cs->cs_ops = &zsops_tty;

	zst->zst_cs = cs;
	zst->zst_swflags = cf->cf_flags;	/* softcar, etc. */
	zst->zst_hwflags = args->hwflags;
	dev = makedev(zs_major, tty_unit);

	if (zst->zst_swflags)
		printf(" flags 0x%x", zst->zst_swflags);

	if (ISSET(zst->zst_hwflags, ZS_HWFLAG_NO_DCD))
		SET(zst->zst_swflags, TIOCFLAG_SOFTCAR);

	/*
	 * Check whether we serve as a console device.
	 * XXX - split console input/output channels aren't
	 *	 supported yet on /dev/console
	 */
	i = o = NULL;
	if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) {
		i = " input";
		if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) {
			args->consdev->cn_dev = dev;
			cn_tab->cn_pollc = args->consdev->cn_pollc;
			cn_tab->cn_getc = args->consdev->cn_getc;
		}
		cn_tab->cn_dev = dev;
	}
	if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) {
		o = " output";
		if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) {
			cn_tab->cn_putc = args->consdev->cn_putc;
		}
		cn_tab->cn_dev = dev;
	}
	if (i != NULL || o != NULL) {
		printf(": console%s", i ? (o ? "" : i) : o);
	}

#ifdef KGDB
	if (zs_check_kgdb(cs, dev)) {
		/*
		 * Allow kgdb to "take over" this port.  Returns true
		 * if this serial port is in-use by kgdb.
		 */
		printf(": kgdb\n");
		/*
		 * This is the kgdb port (exclusive use)
		 * so skip the normal attach code.
		 */
		return;
	}
#endif

#if defined(__sparc__) || defined(__sparc64__)
	if (strcmp(args->type, "keyboard") == 0 ||
	    strcmp(args->type, "mouse") == 0)
		printf(": %s", args->type);
#endif

	printf("\n");

	tp = ttymalloc(0);
	tp->t_dev = dev;
	tp->t_oproc = zsstart;
	tp->t_param = zsparam;
	tp->t_hwiflow = zshwiflow;

	zst->zst_tty = tp;
	zst->zst_rbuf = mallocarray(zstty_rbuf_size, 2, M_DEVBUF, M_WAITOK);
	zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size * 2);
	/* Disable the high water mark. */
	zst->zst_r_hiwat = 0;
	zst->zst_r_lowat = 0;
	zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
	zst->zst_rbavail = zstty_rbuf_size;

	/* if there are no enable/disable functions, assume the device
	   is always enabled */
	if (!cs->enable)
		cs->enabled = 1;

	/*
	 * Hardware init
	 */
	dtr_on = 0;
	resetbit = 0;
	if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
		/* Call zsparam similar to open. */
		struct termios t;

		/* Wait a while for previous console output to complete */
		DELAY(10000);

		/* Setup the "new" parameters in t. */
		t.c_ispeed = 0;
		t.c_ospeed = cs->cs_defspeed;
		t.c_cflag = cs->cs_defcflag;

		s = splzs();

		/*
		 * 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);

		splx(s);

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

		/* Make sure DTR is on now. */
		dtr_on = 1;
	} else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) {
		/* Not the console; may need reset. */
		resetbit = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET;
	}

	s = splzs();
	if (resetbit)
		zs_write_reg(cs, 9, resetbit);
	zs_modem(zst, dtr_on);
	splx(s);
}
Beispiel #28
0
/*
 * Attach a found zs.
 *
 * Match slave number to zs unit number, so that misconfiguration will
 * not set up the keyboard as ttya, etc.
 */
void
zsc_attach(struct device *parent, struct device *self, void *aux)
{
	struct zsc_softc *zsc = (void *)self;
	struct confargs *ca = aux;
	struct zsc_attach_args zsc_args;
	volatile struct zschan *zc;
	struct xzs_chanstate *xcs;
	struct zs_chanstate *cs;
	struct zsdevice *zsd;
	int zsc_unit, channel;
	int s, theflags;
	int node, intr[3][3];
	u_int regs[16];

	zsc_unit = zsc->zsc_dev.dv_unit;

	zsd = mapiodev(ca->ca_baseaddr + ca->ca_reg[0], ca->ca_reg[1]);
	node = OF_child(ca->ca_node);	/* ch-a */

	for (channel = 0; channel < 2; channel++) {
		if (OF_getprop(node, "AAPL,interrupts",
			       intr[channel], sizeof(intr[0])) == -1 &&
		    OF_getprop(node, "interrupts",
			       intr[channel], sizeof(intr[0])) == -1) {
			printf(": cannot find interrupt property\n");
			return;
		}

		if (OF_getprop(node, "reg", regs, sizeof(regs)) < 24) {
			printf(": cannot find reg property\n");
			return;
		}
		regs[2] += ca->ca_baseaddr;
		regs[4] += ca->ca_baseaddr;
#ifdef ZS_TXDMA
		zsc->zsc_txdmareg[channel] = mapiodev(regs[2], regs[3]);
		zsc->zsc_txdmacmd[channel] =
			dbdma_alloc(sizeof(dbdma_command_t) * 3);
		memset(zsc->zsc_txdmacmd[channel], 0,
			sizeof(dbdma_command_t) * 3);
		dbdma_reset(zsc->zsc_txdmareg[channel]);
#endif
		node = OF_peer(node);	/* ch-b */
	}

	printf(": irq %d,%d\n", intr[0][0], intr[1][0]);

	/*
	 * Initialize software state for each channel.
	 */
	for (channel = 0; channel < 2; channel++) {
		zsc_args.channel = channel;
		zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
		xcs = &zsc->xzsc_xcs_store[channel];
		cs  = &xcs->xzs_cs;
		zsc->zsc_cs[channel] = cs;

		cs->cs_channel = channel;
		cs->cs_private = NULL;
		cs->cs_ops = &zsops_null;

		zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;

		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);

		/* Current BAUD rate generator clock. */
		/* RTxC is 230400*16, so use 230400 */
		cs->cs_brg_clk = PCLK / 16;
		if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
			cs->cs_defspeed = zs_get_speed(cs);
		else
			cs->cs_defspeed =
			    zs_defspeed[zsc_unit][channel];
		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;
		cs->cs_wr5_rts = 0;

#ifdef __notyet__
		cs->cs_slave_type = ZS_SLAVE_NONE;
#endif

		/* Define BAUD rate stuff. */
		xcs->cs_clocks[0].clk = PCLK;
		xcs->cs_clocks[0].flags = ZSC_RTXBRG | ZSC_RTXDIV;
		xcs->cs_clocks[1].flags =
			ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
		xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
		xcs->cs_clock_count = 3;
		if (channel == 0) {
			theflags = 0; /*mac68k_machine.modem_flags;*/
			/*xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;*/
			/*xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;*/
			xcs->cs_clocks[1].clk = 0;
			xcs->cs_clocks[2].clk = 0;
		} else {
			theflags = 0; /*mac68k_machine.print_flags;*/
			xcs->cs_clocks[1].flags = ZSC_VARIABLE;
			/*
			 * Yes, we aren't defining ANY clock source enables for the
			 * printer's DCD clock in. The hardware won't let us
			 * use it. But a clock will freak out the chip, so we
			 * let you set it, telling us to bar interrupts on the line.
			 */
			/*xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;*/
			/*xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;*/
			xcs->cs_clocks[1].clk = 0;
			xcs->cs_clocks[2].clk = 0;
		}
		if (xcs->cs_clocks[1].clk)
			zsc_args.hwflags |= ZS_HWFLAG_NO_DCD;
		if (xcs->cs_clocks[2].clk)
			zsc_args.hwflags |= ZS_HWFLAG_NO_CTS;

		/* Set defaults in our "extended" chanstate. */
		xcs->cs_csource = 0;
		xcs->cs_psource = 0;
		xcs->cs_cclk_flag = 0;  /* Nothing fancy by default */
		xcs->cs_pclk_flag = 0;

		if (theflags & ZSMAC_RAW) {
			zsc_args.hwflags |= ZS_HWFLAG_RAW;
			printf(" (raw defaults)");
		}

		/*
		 * XXX - This might be better done with a "stub" driver
		 * (to replace zstty) that ignores LocalTalk for now.
		 */
		if (theflags & ZSMAC_LOCALTALK) {
			printf(" shielding from LocalTalk");
			cs->cs_defspeed = 1;
			cs->cs_creg[ZSRR_BAUDLO] = cs->cs_preg[ZSRR_BAUDLO] = 0xff;
			cs->cs_creg[ZSRR_BAUDHI] = cs->cs_preg[ZSRR_BAUDHI] = 0xff;
			zs_write_reg(cs, ZSRR_BAUDLO, 0xff);
			zs_write_reg(cs, ZSRR_BAUDHI, 0xff);
			/*
			 * If we might have LocalTalk, then make sure we have the
			 * Baud rate low-enough to not do any damage.
			 */
		}

		/*
		 * We used to disable chip interrupts here, but we now
		 * do that in zscnprobe, just in case MacOS left the chip on.
		 */
		
		xcs->cs_chip = 0;
		
		/* Stash away a copy of the final H/W flags. */
		xcs->cs_hwflags = zsc_args.hwflags;
		
		/*
		 * Look for a child driver for this channel.
		 * The child attach will setup the hardware.
		 */
		if (!config_found(self, (void *)&zsc_args, zsc_print)) {
			/* No sub-driver.  Just reset it. */
			u_char reset = (channel == 0) ?
				ZSWR9_A_RESET : ZSWR9_B_RESET;
			s = splzs();
			zs_write_reg(cs, 9, reset);
			splx(s);
		}
	}

	/* XXX - Now safe to install interrupt handlers. */
	mac_intr_establish(parent, intr[0][0], IST_LEVEL, IPL_TTY,
	    zshard, NULL, "zs0");
	mac_intr_establish(parent, intr[1][0], IST_LEVEL, IPL_TTY,
	    zshard, NULL, "zs1");
#ifdef ZS_TXDMA
	mac_intr_establish(parent, intr[0][1], IST_LEVEL, IPL_TTY,
	    zs_txdma_int, (void *)0, "zsdma0");
	mac_intr_establish(parent, intr[1][1], IST_LEVEL, IPL_TTY,
	    zs_txdma_int, (void *)1, "zsdma1");
#endif
	zsc->zsc_softintr = softintr_establish(IPL_SOFTTTY, zssoft, zsc);
	if (zsc->zsc_softintr == NULL)
		panic("zsattach: could not establish soft interrupt");

	/*
	 * Set the master interrupt enable and interrupt vector.
	 * (common to both channels, do it on A)
	 */
	cs = zsc->zsc_cs[0];
	s = splzs();
	/* 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);

	/* connect power management for port 0 */
	cs->enable = zs_enable;
	cs->disable = zs_disable;
}
Beispiel #29
0
void
zs_config(struct zsc_softc *zsc, char *base)
{
	struct zsc_attach_args zsc_args;
	struct zs_chanstate *cs;
	int zsc_unit, channel, s;

	zsc_unit = device_unit(zsc->zsc_dev);
	aprint_normal(": Zilog 8530 SCC\n");

	/*
	 * Initialize software state for each channel.
	 */
	for (channel = 0; channel < 2; channel++) {
		zsc_args.channel = channel;
		zsc_args.hwflags = zs_hwflags[zsc_unit][channel];

		/*
		 * If we're the console, copy the channel state, and
		 * adjust the console channel pointer.
		 */
		if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) {
			cs = &zs_conschan_store;
		} else {
			cs = malloc(sizeof(struct zs_chanstate),
				    M_DEVBUF, M_NOWAIT | M_ZERO);
			if(channel==0){
				cs->cs_reg_csr  = base + 7;
				cs->cs_reg_data = base + 15;
			} else {
				cs->cs_reg_csr  = base + 3;
				cs->cs_reg_data = base + 11;
			}
			memcpy(cs->cs_creg, zs_init_reg, 16);
			memcpy(cs->cs_preg, zs_init_reg, 16);
			cs->cs_defspeed = 9600;
		}
		zsc->zsc_cs[channel] = cs;
		zs_lock_init(cs);

		cs->cs_defcflag = CREAD | CS8 | HUPCL;

		/* 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;

		cs->cs_channel = channel;
		cs->cs_private = NULL;
		cs->cs_ops = &zsops_null;
		cs->cs_brg_clk = 4000000 / 16;

		/*
		 * 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(zsc->zsc_dev, (void *)&zsc_args,
		    zsc_print)) {
			/* No sub-driver.  Just reset it. */
			uint8_t reset = (channel == 0) ?
				ZSWR9_A_RESET : ZSWR9_B_RESET;
			s = splzs();
			zs_write_reg(cs,  9, reset);
			splx(s);
		}
	}
}