register volatile struct zschan *zc = zs_conschan; register int s;
volatile struct zschan *zc = zs_conschan; int s;
static struct tty *zs_checkcons __P((struct zs_softc *, int,    struct zs_chanstate *));#ifdef KGDB/* KGDB stuff.  Must reboot to change zs_kgdbunit. */extern int kgdb_dev, kgdb_rate;static int zs_kgdb_savedspeed;static void zs_checkkgdb __P((int, struct zs_chanstate *, struct tty *));void zskgdb __P((int));static int zs_kgdb_getc __P((void *));static void zs_kgdb_putc __P((void *, int));#endifstatic int zsrint __P((struct zs_chanstate *, volatile struct zschan *));static int zsxint __P((struct zs_chanstate *, volatile struct zschan *));static int zssint __P((struct zs_chanstate *, volatile struct zschan *));void zsabort __P((int));static void zsoverrun __P((int, long *, char *));static volatile struct zsdevice *zsaddr[NZS];	/* XXX, but saves work *//* * Console keyboard L1-A processing is done in the hardware interrupt code, * so we need to duplicate some of the console keyboard decode state.  (We * must not use the regular state as the hardware code keeps ahead of the * software state: the software state tracks the most recent ring input but * the hardware state tracks the most recent ZSCC input.)  See also kbd.h. */static struct conk_state {	/* console keyboard state */	char	conk_id;	/* true => ID coming up (console only) */	char	conk_l1;	/* true => L1 pressed (console only) */} zsconk_state;int zshardscope;int zsshortcuts;		/* number of "shortcut" software interrupts */#ifdef SUN4static u_int zs_read __P((volatile struct zschan *, u_int reg));static u_int zs_write __P((volatile struct zschan *, u_int, u_int));static u_intzs_read(zc, reg)	volatile struct zschan *zc;	u_int reg;{	u_char val;	zc->zc_csr = reg;	ZS_DELAY();	val = zc->zc_csr;	ZS_DELAY();	return val;}static u_intzs_write(zc, reg, val)	volatile struct zschan *zc;	u_int reg, val;{	zc->zc_csr = reg;	ZS_DELAY();	zc->zc_csr = val;	ZS_DELAY();	return val;}#endif /* SUN4 *//* * Match slave number to zs unit number, so that misconfiguration will * not set up the keyboard as ttya, etc. */static intzsmatch(parent, vcf, aux)	struct device *parent;	void *vcf, *aux;{	struct cfdata *cf = vcf;	struct confargs *ca = aux;	struct romaux *ra = &ca->ca_ra;	if (strcmp(cf->cf_driver->cd_name, ra->ra_name))		return (0);	if ((ca->ca_bustype == BUS_MAIN && !CPU_ISSUN4) ||	    (ca->ca_bustype == BUS_OBIO && CPU_ISSUN4M))		return (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit);	ra->ra_len = NBPG;	return (probeget(ra->ra_vaddr, 1) != -1);}/* * Attach a found zs. * * USE ROM PROPERTIES port-a-ignore-cd AND port-b-ignore-cd FOR * SOFT CARRIER, AND keyboard PROPERTY FOR KEYBOARD/MOUSE? */static voidzsattach(parent, dev, aux)	struct device *parent;	struct device *dev;	void *aux;{	register int zs = dev->dv_unit, unit;	register struct zs_softc *sc;	register struct zs_chanstate *cs;	register volatile struct zsdevice *addr;	register struct tty *tp, *ctp;	register struct confargs *ca = aux;	register struct romaux *ra = &ca->ca_ra;	int pri;	static int didintr, prevpri;	int ringsize;	if ((addr = zsaddr[zs]) == NULL)		addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs);	if (ca->ca_bustype==BUS_MAIN)		if ((void *)addr != ra->ra_vaddr)			panic("zsattach");	if (ra->ra_nintr != 1) {		printf(": expected 1 interrupt, got %d\n", ra->ra_nintr);		return;	}	pri = ra->ra_intr[0].int_pri;	printf(" pri %d, softpri %d\n", pri, PIL_TTY);	if (!didintr) {		didintr = 1;		prevpri = pri;		intr_establish(pri, &levelhard);		intr_establish(PIL_TTY, &levelsoft);	} else if (pri != prevpri)		panic("broken zs interrupt scheme");	sc = (struct zs_softc *)dev;	evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);	sc->sc_zs = addr;	unit = zs * 2;	cs = sc->sc_cs;	/* link into interrupt list with order (A,B) (B=A+1) */	cs[0].cs_next = &cs[1];	cs[0].cs_sc = sc;	cs[1].cs_next = zslist;	cs[1].cs_sc = sc;	zslist = cs;	cs->cs_unit = unit;	cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_A]);	cs->cs_zc = &addr->zs_chan[ZS_CHAN_A];	if ((ctp = zs_checkcons(sc, unit, cs)) != NULL)		tp = ctp;	else {		tp = ttymalloc();		tp->t_dev = makedev(ZSMAJOR, unit);		tp->t_oproc = zsstart;		tp->t_param = zsparam;	}	cs->cs_ttyp = tp;#ifdef KGDB	if (ctp == NULL)		zs_checkkgdb(unit, cs, tp);#endif	if (unit == ZS_KBD) {		/*		 * Keyboard: tell /dev/kbd driver how to talk to us.		 */		tp->t_ispeed = tp->t_ospeed = cs->cs_speed;		tp->t_cflag = CS8;#if	NKBD > 0		kbd_serial(tp, zsiopen, zsiclose);#endif		cs->cs_conk = 1;		/* do L1-A processing */		ringsize = 128;	} else {		if (tp != ctp)			tty_attach(tp);		ringsize = 4096;		if (unit == zs_consout)			zs_conscs = cs;	}	cs->cs_ringmask = ringsize - 1;	cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf),			      M_DEVBUF, M_NOWAIT);	unit++;	cs++;	cs->cs_unit = unit;	cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_B]);	cs->cs_zc = &addr->zs_chan[ZS_CHAN_B];	if ((ctp = zs_checkcons(sc, unit, cs)) != NULL)		tp = ctp;	else {		tp = ttymalloc();		tp->t_dev = makedev(ZSMAJOR, unit);		tp->t_oproc = zsstart;		tp->t_param = zsparam;	}	cs->cs_ttyp = tp;#ifdef KGDB	if (ctp == NULL)		zs_checkkgdb(unit, cs, tp);#endif	if (unit == ZS_MOUSE) {		/*		 * Mouse: tell /dev/mouse driver how to talk to us.		 */		tp->t_ispeed = tp->t_ospeed = B1200;		tp->t_cflag = CS8;		ms_serial(tp, zsiopen, zsiclose);		ringsize = 128;	} else {		if (tp != ctp)			tty_attach(tp);		ringsize = 4096;		if (unit == zs_consout)			zs_conscs = cs;	}	cs->cs_ringmask = ringsize - 1;	cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf),			      M_DEVBUF, M_NOWAIT);}#ifdef KGDB/* * Put a channel in a known state.  Interrupts may be left disabled * or enabled, as desired. */static voidzs_reset(zc, inten, speed)	volatile struct zschan *zc;	int inten, speed;{	int tconst;	static u_char reg[16] = {		0,		0,		0,		ZSWR3_RX_8 | ZSWR3_RX_ENABLE,		ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,		ZSWR5_TX_8 | ZSWR5_TX_ENABLE,		0,		0,		0,		0,		ZSWR10_NRZ,		ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,		0,		0,		ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA,		ZSWR15_BREAK_IE | ZSWR15_DCD_IE,	};	reg[9] = inten ? ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR : ZSWR9_NO_VECTOR;	tconst = BPS_TO_TCONST(PCLK / 16, speed);	reg[12] = tconst;	reg[13] = tconst >> 8;	zs_loadchannelregs(zc, reg);}#endif/* * Declare the given tty (which is in fact &cons) as a console input * or output.  This happens before the zs chip is attached; the hookup * is finished later, in zs_setcons() below. * * This is used only for ports a and b.  The console keyboard is decoded * independently (we always send unit-2 input to /dev/kbd, which will * direct it to /dev/console if appropriate). */voidzsconsole(tp, unit, out, fnstop)	register struct tty *tp;	register int unit;	int out;	int (**fnstop) __P((struct tty *, int));{	int zs;	volatile struct zsdevice *addr;	if (unit >= ZS_KBD)		panic("zsconsole");	if (out) {		zs_consout = unit;		zs = unit >> 1;		if ((addr = zsaddr[zs]) == NULL)			addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs);		zs_conschan = (unit & 1) == 0 ? &addr->zs_chan[ZS_CHAN_A] :		    &addr->zs_chan[ZS_CHAN_B];		v_putc = zscnputc;	} else		zs_consin = unit;	if (fnstop)		*fnstop = &zsstop;	zs_ctty = tp;}/* * Polled console output putchar. */static voidzscnputc(c)	int c;{	register volatile struct zschan *zc = zs_conschan;	register int s;	if (c == '\n')		zscnputc('\r');	/*	 * Must block output interrupts (i.e., raise to >= splzs) without	 * lowering current ipl.  Need a better way.	 */	s = splhigh();	if (CPU_ISSUN4C && s <= (12 << 8)) /* XXX */		(void) splzs();	while ((zc->zc_csr & ZSRR0_TX_READY) == 0)		ZS_DELAY();	/*	 * If transmitter was busy doing regular tty I/O (ZSWR1_TIE on),	 * defer our output until the transmit interrupt runs. We still	 * sync with TX_READY so we can get by with a single-char "queue".	 */	if (zs_conscs != NULL && (zs_conscs->cs_creg[1] & ZSWR1_TIE)) {		/*		 * If previous not yet done, send it now; zsxint()		 * will field the interrupt for our char, but doesn't		 * care. We're running at sufficiently high spl for		 * this to work.		 */		if (zs_conscs->cs_deferred_cc != 0)			zc->zc_data = zs_conscs->cs_deferred_cc;		zs_conscs->cs_deferred_cc = c;		splx(s);		return;	}	zc->zc_data = c;	delay(2);	splx(s);}/* * Set up the given unit as console input, output, both, or neither, as * needed.  Return console tty if it is to receive console input. */static struct tty *zs_checkcons(sc, unit, cs)	struct zs_softc *sc;	int unit;	struct zs_chanstate *cs;{	register struct tty *tp;	char *i, *o;	if ((tp = zs_ctty) == NULL) /* XXX */		return (0);	i = zs_consin == unit ? "input" : NULL;	o = zs_consout == unit ? "output" : NULL;	if (i == NULL && o == NULL)		return (0);	/* rewire the minor device (gack) */	tp->t_dev = makedev(major(tp->t_dev), unit);	/*	 * Rewire input and/or output.  Note that baud rate reflects	 * input settings, not output settings, but we can do no better	 * if the console is split across two ports.	 *	 * XXX	split consoles don't work anyway -- this needs to be	 *	thrown away and redone	 */	if (i) {		tp->t_param = zsparam;		tp->t_ispeed = tp->t_ospeed = cs->cs_speed;		tp->t_cflag = CS8;		ttsetwater(tp);	}	if (o) {		tp->t_oproc = zsstart;	}	printf("%s%c: console %s\n",	    sc->sc_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o);	cs->cs_consio = 1;	cs->cs_brkabort = 1;	return (tp);}