Subject: Changes for the sun3 zs driver
To: None <glass@sun-lamp.cs.berkeley.edu>
From: Gordon W. Ross <gwr@jericho.mc.com>
List: port-sun3
Date: 03/14/1994 12:23:45
The main problems were:
(1) incorrect return value from ZS_READ
(2) missing call to isr_soft_clear()

Note that the changes to zs.c are relative to arch/sparc/dev/zs.c
because that was what I started with (sorry Adam).

*** arch/sun3/dev/zsvar.h.orig	Wed Feb 23 03:29:05 1994
--- arch/sun3/dev/zsvar.h	Mon Mar 14 01:49:52 1994
***************
*** 43,48 ****
--- 43,49 ----
   *
   * from: Header: zsvar.h,v 1.7 92/11/26 01:28:04 torek Exp  (LBL)
   * $Id: zsvar.h,v 1.1 1994/02/23 08:29:05 glass Exp $
+  * gwr: fixed zs_read and zs_write
   */
  
  /*
***************
*** 142,146 ****
   * On the SparcStation the 1.6 microsecond recovery time is
   * handled in hardware.
   */
! #define	ZS_READ(c, r)		((c)->zc_csr = (r), zsdelay(5), (c)->zc_csr, zsdelay(5))
! #define	ZS_WRITE(c, r, v)	((c)->zc_csr = (r), zsdelay(5), (c)->zc_csr = (v), zsdelay(5))
--- 143,147 ----
   * On the SparcStation the 1.6 microsecond recovery time is
   * handled in hardware.
   */
! #define	ZS_READ(c, r)		zs_read(c, r)
! #define	ZS_WRITE(c, r, v)	zs_write(c, r, v)

*** arch/sparc/dev/zs.c	Mon Feb 14 05:19:40 1994
--- arch/sun3/dev/zs.c	Mon Mar 14 02:51:24 1994
***************
*** 42,48 ****
   *	@(#)zs.c	8.1 (Berkeley) 7/19/93
   *
   * from: Header: zs.c,v 1.30 93/07/19 23:44:42 torek Exp 
!  * $Id: zs.c,v 1.4 1994/02/14 09:37:13 deraadt Exp $
   */
  
  /*
--- 42,49 ----
   *	@(#)zs.c	8.1 (Berkeley) 7/19/93
   *
   * from: Header: zs.c,v 1.30 93/07/19 23:44:42 torek Exp 
!  * from: Id: sparc/dev/zs.c,v 1.3 1993/10/13 02:36:44 deraadt Exp 
!  * gwr: merged some of Adam's changes and fixed some bugs.
   */
  
  /*
***************
*** 55,60 ****
--- 56,62 ----
   */
  #define	NZS	2		/* XXX */
  
+ #include <sys/systm.h>
  #include <sys/param.h>
  #include <sys/proc.h>
  #include <sys/device.h>
***************
*** 65,105 ****
  #include <sys/time.h>
  #include <sys/kernel.h>
  #include <sys/syslog.h>
  
  #include <machine/autoconf.h>
  #include <machine/cpu.h>
  
! #include <sparc/sparc/vaddrs.h>
! #include <sparc/sparc/auxreg.h>
  
- #include <sparc/dev/kbd.h>
- #include <sparc/dev/zsreg.h>
- #include <sparc/dev/zsvar.h>
- 
  #ifdef KGDB
  #include <machine/remote-sl.h>
  #endif
  
  #define	ZSMAJOR	12		/* XXX */
  
  #define	ZS_KBD		2	/* XXX */
  #define	ZS_MOUSE	3	/* XXX */
  
! /* the magic number below was stolen from the Sprite source. */
! #define PCLK	(19660800/4)	/* PCLK pin input clock rate */
  
  /*
!  * Select software interrupt bit based on TTY ipl.
   */
! #if PIL_TTY == 1
! # define IE_ZSSOFT IE_L1
! #elif PIL_TTY == 4
! # define IE_ZSSOFT IE_L4
! #elif PIL_TTY == 6
! # define IE_ZSSOFT IE_L6
! #else
! # error "no suitable software interrupt bit"
! #endif
  
  /*
   * Software state per found chip.  This would be called `zs_softc',
--- 67,102 ----
  #include <sys/time.h>
  #include <sys/kernel.h>
  #include <sys/syslog.h>
+ #include <sys/conf.h>
  
  #include <machine/autoconf.h>
  #include <machine/cpu.h>
+ #include <machine/obio.h>
  
! #include "cons.h"
! #include "kbd.h"
! #include "zsreg.h"
! #include "zsvar.h"
  
  #ifdef KGDB
  #include <machine/remote-sl.h>
  #endif
  
+ /* #define DEBUG 1 */
+ 
  #define	ZSMAJOR	12		/* XXX */
  
  #define	ZS_KBD		2	/* XXX */
  #define	ZS_MOUSE	3	/* XXX */
  
! /* The Sun3 provides a 4.9152 MHz clock to the ZS chips. */
! #define PCLK	(9600 * 512)	/* PCLK pin input clock rate */
  
  /*
!  * Select software interrupt levels.
   */
! #define ZSSOFT_PRI	2	/* XXX - Want TTY_PRI */
! #define ZSHARD_PRI	6	/* Wired on the CPU board... */
  
  /*
   * Software state per found chip.  This would be called `zs_softc',
***************
*** 120,133 ****
      { NULL, "zs", zsmatch, zsattach, DV_TTY, sizeof(struct zsinfo) };
  
  /* Interrupt handlers. */
! static int	zshard(void *);
! static struct intrhand levelhard = { zshard };
! static int	zssoft(void *);
! static struct intrhand levelsoft = { zssoft };
  
  struct zs_chanstate *zslist;
  
  /* Routines called from other code. */
  static void	zsiopen(struct tty *);
  static void	zsiclose(struct tty *);
  static void	zsstart(struct tty *);
--- 117,130 ----
      { NULL, "zs", zsmatch, zsattach, DV_TTY, sizeof(struct zsinfo) };
  
  /* Interrupt handlers. */
! static int	zshard(int);
! static int	zssoft(int);
  
  struct zs_chanstate *zslist;
  
  /* Routines called from other code. */
+ int zsopen(dev_t, int, int, struct proc *);
+ int zsclose(dev_t, int, int, struct proc *);
  static void	zsiopen(struct tty *);
  static void	zsiclose(struct tty *);
  static void	zsstart(struct tty *);
***************
*** 139,144 ****
--- 136,144 ----
  static void	zs_reset(volatile struct zschan *, int, int);
  static void	zs_modem(struct zs_chanstate *, int);
  static void	zs_loadchannelregs(volatile struct zschan *, u_char *);
+ static void zs_delay(void);
+ static u_char zs_read(volatile struct zschan *, u_char);
+ static u_char zs_write(volatile struct zschan *, u_char, u_char);
  
  /* Console stuff. */
  static struct tty *zs_ctty;	/* console `struct tty *' */
***************
*** 154,161 ****
  static void zs_checkkgdb(int, struct zs_chanstate *, struct tty *);
  #endif
  
! extern volatile struct zsdevice *findzs(int);
! static volatile struct zsdevice *zsaddr[NZS];	/* XXX, but saves work */
  
  /*
   * Console keyboard L1-A processing is done in the hardware interrupt code,
--- 154,160 ----
  static void zs_checkkgdb(int, struct zs_chanstate *, struct tty *);
  #endif
  
! static volatile struct zsdevice *zsaddr[NZS];
  
  /*
   * Console keyboard L1-A processing is done in the hardware interrupt code,
***************
*** 179,187 ****
  static int
  zsmatch(struct device *parent, struct cfdata *cf, void *aux)
  {
! 	struct romaux *ra = aux;
  
! 	return (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit);
  }
  
  /*
--- 178,189 ----
  static int
  zsmatch(struct device *parent, struct cfdata *cf, void *aux)
  {
! 	struct obio_cf_loc *obio_loc;
! 	caddr_t zs_addr;
  
! 	obio_loc = (struct obio_cf_loc *) CFDATA_LOC(cf);
! 	zs_addr = (caddr_t) obio_loc->obio_addr;
! 	return !obio_probe_byte(zs_addr);
  }
  
  /*
***************
*** 193,224 ****
  static void
  zsattach(struct device *parent, struct device *dev, void *aux)
  {
  	register int zs = dev->dv_unit, unit;
  	register struct zsinfo *zi;
  	register struct zs_chanstate *cs;
  	register volatile struct zsdevice *addr;
  	register struct tty *tp, *ctp;
! 	register struct romaux *ra = aux;
! 	int pri, softcar;
! 	static int didintr, prevpri;
  
! 	if ((addr = zsaddr[zs]) == NULL)
! 		addr = zsaddr[zs] = findzs(zs);
! 	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");
  	zi = (struct zsinfo *)dev;
  	zi->zi_zs = addr;
  	unit = zs * 2;
--- 195,223 ----
  static void
  zsattach(struct device *parent, struct device *dev, void *aux)
  {
+ 	struct obio_cf_loc *obio_loc = OBIO_LOC(dev);
  	register int zs = dev->dv_unit, unit;
  	register struct zsinfo *zi;
  	register struct zs_chanstate *cs;
  	register volatile struct zsdevice *addr;
  	register struct tty *tp, *ctp;
! 	int softcar;
! 	static int didintr;
! 	caddr_t obio_addr;
  
! 	obio_addr = (caddr_t)obio_loc->obio_addr;
! 	obio_print(obio_addr, ZSSOFT_PRI);
! 	printf(" hwpri %d\n", ZSHARD_PRI);
! 
! 	addr = (struct zsdevice *)
! 		obio_alloc(obio_addr, OBIO_ZS_SIZE, OBIO_WRITE);
! 
  	if (!didintr) {
  		didintr = 1;
! 		isr_add(ZSSOFT_PRI, zssoft, 0);
! 		isr_add(ZSHARD_PRI, zshard, 0);
! 	}
! 
  	zi = (struct zsinfo *)dev;
  	zi->zi_zs = addr;
  	unit = zs * 2;
***************
*** 231,244 ****
  		zs_tty[unit+1] = ttymalloc();
  
  	if (unit == 0) {
- 		/* Get software carrier flags from options node in OPENPROM. */
- 		extern int optionsnode;
- 
  		softcar = 0;
- 		if (*getpropstring(optionsnode, "ttya-ignore-cd") == 't')
- 			softcar |= 1;
- 		if (*getpropstring(optionsnode, "ttyb-ignore-cd") == 't')
- 			softcar |= 2;
  	} else
  		softcar = dev->dv_cfdata->cf_flags;
  
--- 230,236 ----
***************
*** 248,256 ****
  	zslist = cs;
  
  	cs->cs_unit = unit;
! 	cs->cs_speed = zs_getspeed(&addr->zs_chan[CHAN_A]);
  	cs->cs_softcar = softcar & 1;
! 	cs->cs_zc = &addr->zs_chan[CHAN_A];
  	tp->t_dev = makedev(ZSMAJOR, unit);
  	tp->t_oproc = zsstart;
  	tp->t_param = zsparam;
--- 240,255 ----
  	zslist = cs;
  
  	cs->cs_unit = unit;
! 	cs->cs_zc =	&addr->zs_chan[CHAN_A];
! 	cs->cs_speed = zs_getspeed(cs->cs_zc);
! #ifdef	DEBUG
! 	printf("zs%d speed %d ",  cs->cs_unit, cs->cs_speed);
! #endif
  	cs->cs_softcar = softcar & 1;
! #if 0
! 	/* XXX - Drop carrier here? -gwr */
! 	zs_modem(cs, cs->cs_softcar ? 1 : 0);
! #endif
  	tp->t_dev = makedev(ZSMAJOR, unit);
  	tp->t_oproc = zsstart;
  	tp->t_param = zsparam;
***************
*** 274,283 ****
  	unit++;
  	cs++;
  	tp = zs_tty[unit];
  	cs->cs_unit = unit;
- 	cs->cs_speed = zs_getspeed(&addr->zs_chan[CHAN_B]);
- 	cs->cs_softcar = softcar & 2;
  	cs->cs_zc = &addr->zs_chan[CHAN_B];
  	tp->t_dev = makedev(ZSMAJOR, unit);
  	tp->t_oproc = zsstart;
  	tp->t_param = zsparam;
--- 273,290 ----
  	unit++;
  	cs++;
  	tp = zs_tty[unit];
+ 
  	cs->cs_unit = unit;
  	cs->cs_zc = &addr->zs_chan[CHAN_B];
+ 	cs->cs_speed = zs_getspeed(cs->cs_zc);
+ #ifdef	DEBUG
+ 	printf("zs%d speed %d\n", cs->cs_unit, cs->cs_speed);
+ #endif
+ 	cs->cs_softcar = softcar & 2;
+ #if 0
+ 	/* XXX - Drop carrier here? -gwr */
+ 	zs_modem(cs, cs->cs_softcar ? 1 : 0);
+ #endif
  	tp->t_dev = makedev(ZSMAJOR, unit);
  	tp->t_oproc = zsstart;
  	tp->t_param = zsparam;
***************
*** 335,340 ****
--- 342,386 ----
  	zs_loadchannelregs(zc, reg);
  }
  
+ 
+ /* This is only called when the EEPROM says the console is ttyA or ttyB */
+ int
+ zscnprobe(struct consdev *cn)
+ {
+ 	int maj, unit = minor(cn->cn_dev);
+ 
+ 	/* locate the major number */
+ 	for (maj = 0; maj < nchrdev; maj++)
+ 		if (cdevsw[maj].d_open == zsopen)
+ 			break;
+ 	if (maj >= nchrdev) {
+ 		cn->cn_pri = CN_DEAD;
+ 		return 0;
+ 	}
+ 
+ 	/* initialize required fields */
+ #if 0 /* XXX - Not yet. */
+ 	cn->cn_dev = makedev(maj, unit);
+ 	cn->cn_pri = CN_REMOTE;
+ #else
+ 	cn->cn_pri = CN_DEAD;
+ 	/* XXX - See below... */
+ #endif
+ 	return (0);
+ }
+ 
+ /* Attach as console.  Also set zs_conschan */
+ int
+ zscninit(struct consdev *cn)
+ {
+ 	int unit = minor(cn->cn_dev);
+ 
+ 	/* XXX - We need a way to find a VA for the device. */
+ 	/* zs_conschan = zsaddr[unit]; */
+ }
+ 
+ 
+ #if 0
  /*
   * 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
***************
*** 371,381 ****
  		*fnstop = &zsstop;
  	zs_ctty = tp;
  }
  
  /*
   * Polled console output putchar.
   */
! static int
  zscnputc(c)
  	int c;
  {
--- 417,448 ----
  		*fnstop = &zsstop;
  	zs_ctty = tp;
  }
+ #endif
  
  /*
+  * Polled console input putchar.
+  */
+ int
+ zscngetc()
+ {
+ 	register volatile struct zschan *zc = zs_conschan;
+ 	register int s, c;
+ 
+ 	if (zc == NULL)
+ 		return (0);
+ 
+ 	s = splhigh();
+ 	while ((zc->zc_csr & ZSRR0_RX_READY) == 0)
+ 		zs_delay();
+ 	c = zc->zc_data;
+ 	splx(s);
+ 	return (c);
+ }
+ 
+ /*
   * Polled console output putchar.
   */
! int
  zscnputc(c)
  	int c;
  {
***************
*** 382,400 ****
  	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();
- #ifdef sun4c		/* XXX */
- 	if (s <= (12 << 8))
- 		(void) splzs();
- #endif
  	while ((zc->zc_csr & ZSRR0_TX_READY) == 0)
! 		continue;
  	zc->zc_data = c;
  	splx(s);
  }
--- 449,462 ----
  	register volatile struct zschan *zc = zs_conschan;
  	register int s;
  
+ 	if (zc == NULL)
+ 		return (0);
+ 
  	if (c == '\n')
  		zscnputc('\r');
  	s = splhigh();
  	while ((zc->zc_csr & ZSRR0_TX_READY) == 0)
! 		zs_delay();
  	zc->zc_data = c;
  	splx(s);
  }
***************
*** 517,526 ****
--- 579,592 ----
  	struct zsinfo *zi;
  	int unit = minor(dev), zs = unit >> 1, error, s;
  
+ #ifdef	DEBUG
+ 	printf("zs_open\n");
+ #endif
  	if (zs >= zscd.cd_ndevs || (zi = zscd.cd_devs[zs]) == NULL ||
  	    unit == ZS_KBD || unit == ZS_MOUSE)
  		return (ENXIO);
  	cs = &zi->zi_cs[unit & 1];
+ 	/* Prevent simultaneous use by console? */
  	if (cs->cs_consio)
  		return (ENXIO);		/* ??? */
  	tp = cs->cs_ttyp;
***************
*** 544,549 ****
--- 610,618 ----
  	for (;;) {
  		/* loop, turning on the device, until carrier present */
  		zs_modem(cs, 1);
+ 		/* May never get status intr if carrier already on. -gwr */
+ 		if (cs->cs_zc->zc_csr & ZSRR0_DCD)
+ 			tp->t_state |= TS_CARR_ON;
  		if (cs->cs_softcar)
  			tp->t_state |= TS_CARR_ON;
  		if (flags & O_NONBLOCK || tp->t_cflag & CLOCAL ||
***************
*** 626,632 ****
   */
  /* ARGSUSED */
  int
! zshard(void *intrarg)
  {
  	register struct zs_chanstate *a;
  #define	b (a + 1)
--- 695,701 ----
   */
  /* ARGSUSED */
  int
! zshard(int intrarg)
  {
  	register struct zs_chanstate *a;
  #define	b (a + 1)
***************
*** 635,640 ****
--- 704,712 ----
  	static int zsrint(struct zs_chanstate *, volatile struct zschan *);
  	static int zsxint(struct zs_chanstate *, volatile struct zschan *);
  	static int zssint(struct zs_chanstate *, volatile struct zschan *);
+ #ifdef	DEBUG
+ 	printf("zshard\n");
+ #endif
  
  	for (a = zslist; a != NULL; a = b->cs_next) {
  		rr3 = ZS_READ(a->cs_zc, 3);
***************
*** 677,696 ****
  	}
  #undef b
  	if (intflags & 1) {
! #if sun4c /* XXX -- but this will go away when zshard moves to locore.s */
! 		struct clockframe *p = intrarg;
! 
! 		if ((p->psr & PSR_PIL) < (PIL_TTY << 8)) {
! 			zsshortcuts++;
! 			(void) spltty();
! 			if (zshardscope) {
! 				LED_ON;
! 				LED_OFF;
! 			}
! 			return (zssoft(intrarg));
! 		}
! #endif
! 		ienab_bis(IE_ZSSOFT);
  	}
  	return (intflags & 2);
  }
--- 749,755 ----
  	}
  #undef b
  	if (intflags & 1) {
! 	    isr_soft_request(ZSSOFT_PRI);
  	}
  	return (intflags & 2);
  }
***************
*** 800,806 ****
  {
  
  	printf("stopping on keyboard abort\n");
! 	callrom();
  }
  
  #ifdef KGDB
--- 859,865 ----
  {
  
  	printf("stopping on keyboard abort\n");
! 	sun3_stop();
  }
  
  #ifdef KGDB
***************
*** 834,840 ****
   * ZS software interrupt.  Scan all channels for deferred interrupts.
   */
  int
! zssoft(void *arg)
  {
  	register struct zs_chanstate *cs;
  	register volatile struct zschan *zc;
--- 893,899 ----
   * ZS software interrupt.  Scan all channels for deferred interrupts.
   */
  int
! zssoft(int arg)
  {
  	register struct zs_chanstate *cs;
  	register volatile struct zschan *zc;
***************
*** 842,847 ****
--- 901,912 ----
  	register struct tty *tp;
  	register int get, n, c, cc, unit, s;
  
+ #ifdef	DEBUG
+ 	printf("zssoft\n");
+ #endif
+ 
+ 	isr_soft_clear(ZSSOFT_PRI);
+ 
  	for (cs = zslist; cs != NULL; cs = cs->cs_next) {
  		get = cs->cs_rbget;
  again:
***************
*** 1005,1010 ****
--- 1070,1079 ----
  	cs = &zi->zi_cs[unit & 1];
  	s = spltty();
  
+ #ifdef	DEBUG
+ 	printf("zsstart\n");
+ #endif
+ 
  	/*
  	 * If currently active or delaying, no need to do anything.
  	 */
***************
*** 1237,1242 ****
--- 1306,1349 ----
  	ZS_WRITE(zc, 15, reg[15]);
  	ZS_WRITE(zc, 3, reg[3]);
  	ZS_WRITE(zc, 5, reg[5]);
+ }
+ 
+ /* XXX - Tune this... -gwr */
+ int cpuspeed = 50;
+ 
+ static void
+ zs_delay()
+ {
+ 	int n = cpuspeed;
+ 	while (n--) {
+ 		nullop();		/* foil optimizer */
+ 	}
+ }
+ 
+ static u_char
+ zs_read(zc, reg)
+ 	volatile struct zschan *zc;
+ 	u_char reg;
+ {
+ 	u_char val;
+ 
+ 	zc->zc_csr = reg;
+ 	zs_delay();
+ 	val = zc->zc_csr;
+ 	zs_delay();
+ 	return val;
+ }
+ 
+ static u_char
+ zs_write(zc, reg, val)
+ 	volatile struct zschan *zc;
+ 	u_char reg, val;
+ {
+ 	zc->zc_csr = reg;
+ 	zs_delay();
+ 	zc->zc_csr = val;
+ 	zs_delay();
+ 	return val;
  }
  
  #ifdef KGDB

------------------------------------------------------------------------------