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