summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-04-21 22:33:19 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-04-21 22:33:19 +0000
commit67d88b0a9910a68bb666b448d2dac29cb4d3d8c2 (patch)
tree967b89f6e07398a22bd8c76d30179b648776542d /sys/dev/ic
parentba95d3c1d69cdb251d15a12ebf70f50b0ea2019b (diff)
partial sync with netbsd 960418, more to come
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/aic7xxx.c24
-rw-r--r--sys/dev/ic/aic7xxxvar.h6
-rw-r--r--sys/dev/ic/am7990.c57
-rw-r--r--sys/dev/ic/com.c116
-rw-r--r--sys/dev/ic/comvar.h5
-rw-r--r--sys/dev/ic/ncr5380sbc.c23
-rw-r--r--sys/dev/ic/smc90cx6.c1231
-rw-r--r--sys/dev/ic/smc90cx6reg.h99
-rw-r--r--sys/dev/ic/z8530sc.c108
-rw-r--r--sys/dev/ic/z8530sc.h12
-rw-r--r--sys/dev/ic/z8530tty.c253
11 files changed, 1695 insertions, 239 deletions
diff --git a/sys/dev/ic/aic7xxx.c b/sys/dev/ic/aic7xxx.c
index a3bf8e44807..215e059b98d 100644
--- a/sys/dev/ic/aic7xxx.c
+++ b/sys/dev/ic/aic7xxx.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: aic7xxx.c,v 1.3 1996/04/18 23:47:15 niklas Exp $ */
-/* $NetBSD: aic7xxx.c,v 1.3 1996/02/25 22:56:30 cgd Exp $ */
+/* $OpenBSD: aic7xxx.c,v 1.4 1996/04/21 22:21:03 deraadt Exp $ */
+/* $NetBSD: aic7xxx.c,v 1.5 1996/03/29 00:24:58 mycroft Exp $ */
/*
* Generic driver for the aic7xxx based adaptec SCSI controllers
@@ -63,13 +63,12 @@ void ahcminphys __P((struct buf *));
int ahc_poll __P((struct ahc_softc *, struct scsi_xfer *, int));
/* Different debugging levels */
+#ifdef AHC_DEBUG
#define AHC_SHOWMISC 0x0001
#define AHC_SHOWCMDS 0x0002
#define AHC_SHOWSCBS 0x0004
-/*#define AHC_DEBUG /**/
int ahc_debug = AHC_SHOWMISC;
-
-/*#define AHC_MORE_DEBUG /**/
+#endif
#ifdef AHC_MORE_DEBUG
#define DEBUGLEVEL -1
@@ -629,7 +628,6 @@ ahc_scsirate(offset, period, ahc, target)
struct ahc_softc *ahc;
int target;
{
- u_char scsirate;
int i;
for (i = 0; i < ahc_num_syncrates; i++) {
@@ -652,9 +650,15 @@ ahc_scsirate(offset, period, ahc, target)
#endif /* AHC_DEBUG */
}
-ahcprint()
+int
+ahcprint(aux, name)
+ void *aux;
+ char *name;
{
+ if (name != NULL)
+ printf("%s: scsibus ", name);
+ return UNCONF;
}
/*
@@ -768,7 +772,7 @@ ahcintr(ahc)
break;
case NO_IDENT:
panic("%s: No IDENTIFY message from reconnecting "
- "target %d at seqaddr = 0x%lx "
+ "target %d at seqaddr = 0x%x "
"SAVED_TCL == 0x%x\n",
ahc->sc_dev.dv_xname,
(inb(SELID + iobase) >> 4) & 0xf,
@@ -847,7 +851,7 @@ ahcintr(ahc)
*/
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOWMISC)
- printf("Sending SDTR!!\n");
+ printf("Sending SDTR!!\n");
#endif
outb(HA_RETURN_1 + iobase, SEND_SDTR);
}
@@ -1018,7 +1022,6 @@ ahcintr(ahc)
if (xs->error == XS_NOERROR &&
scb->flags != SCB_CHKSENSE) {
- u_char flags;
u_char head;
u_char tail;
struct ahc_dma_seg *sg = scb->ahc_dma;
@@ -1389,7 +1392,6 @@ ahc_init(ahc)
ahc->sc_dev.dv_xname, sizeof(struct ahc_scb), SCB_DOWN_SIZE,
sizeof(struct ahc_dma_seg));
#endif /* AHC_DEBUG */
- /*printf("%s: reading board settings\n", ahc->sc_dev.dv_xname);/**/
/* Save the IRQ type before we do a chip reset */
diff --git a/sys/dev/ic/aic7xxxvar.h b/sys/dev/ic/aic7xxxvar.h
index 48e902a398c..82022e8ab35 100644
--- a/sys/dev/ic/aic7xxxvar.h
+++ b/sys/dev/ic/aic7xxxvar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: aic7xxxvar.h,v 1.2 1996/04/18 23:47:16 niklas Exp $ */
-/* $NetBSD: aic7xxxvar.h,v 1.2 1996/03/14 02:30:30 cgd Exp $ */
+/* $OpenBSD: aic7xxxvar.h,v 1.3 1996/04/21 22:21:12 deraadt Exp $ */
+/* $NetBSD: aic7xxxvar.h,v 1.3 1996/03/29 00:25:02 mycroft Exp $ */
/*
* Interface to the generic driver for the aic7xxx based adaptec
@@ -27,8 +27,6 @@
#ifndef _AIC7XXX_H_
#define _AIC7XXX_H_
-/*#include "ahc.h" /* for NAHC from config */
-
#define AHC_NSEG 256 /* number of dma segments supported */
#define AHC_SCB_MAX 16 /*
diff --git a/sys/dev/ic/am7990.c b/sys/dev/ic/am7990.c
index 87c5712eba2..b050dd728db 100644
--- a/sys/dev/ic/am7990.c
+++ b/sys/dev/ic/am7990.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: am7990.c,v 1.4 1996/04/18 23:47:17 niklas Exp $ */
-/* $NetBSD: am7990.c,v 1.11 1996/03/14 19:05:07 christos Exp $ */
+/* $OpenBSD: am7990.c,v 1.5 1996/04/21 22:21:15 deraadt Exp $ */
+/* $NetBSD: am7990.c,v 1.16 1996/04/09 15:21:59 pk Exp $ */
/*-
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
@@ -74,6 +74,10 @@ void xmit_print __P((struct le_softc *, int));
#define ifp (&sc->sc_arpcom.ac_if)
+#ifndef ETHER_CMP
+#define ETHER_CMP(a, b) bcmp((a), (b), ETHER_ADDR_LEN)
+#endif
+
void
leconfig(sc)
struct le_softc *sc;
@@ -123,8 +127,8 @@ leconfig(sc)
panic("leconfig: weird memory size");
}
- printf(": address %s\n%s: %d receive buffers, %d transmit buffers\n",
- ether_sprintf(sc->sc_arpcom.ac_enaddr),
+ printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
+ printf("%s: %d receive buffers, %d transmit buffers\n",
sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
mem = 0;
@@ -420,8 +424,7 @@ leread(sc, boff, len)
*/
if ((ifp->if_flags & IFF_PROMISC) != 0 &&
(eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
- bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
- sizeof(eh->ether_dhost)) != 0) {
+ ETHER_CMP(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) {
m_freem(m);
return;
}
@@ -430,10 +433,15 @@ leread(sc, boff, len)
#endif
#ifdef LANCE_REVC_BUG
- if (bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
- sizeof(eh->ether_dhost)) != 0 &&
- bcmp(eh->ether_dhost, etherbroadcastaddr,
- sizeof(eh->ether_dhost)) != 0) {
+ /*
+ * The old LANCE (Rev. C) chips have a bug which causes
+ * garbage to be inserted in front of the received packet.
+ * The work-around is to ignore packets with an invalid
+ * destination address (garbage will usually not match).
+ * Of course, this precludes multicast support...
+ */
+ if (ETHER_CMP(eh->ether_dhost, sc->sc_arpcom.ac_enaddr) &&
+ ETHER_CMP(eh->ether_dhost, etherbroadcastaddr)) {
m_freem(m);
return;
}
@@ -483,7 +491,7 @@ lerint(sc)
printf("%s: receive buffer error\n",
sc->sc_dev.dv_xname);
ifp->if_ierrors++;
- } else if (rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP) !=
+ } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
(LE_R1_STP | LE_R1_ENP)) {
printf("%s: dropping chained buffer\n",
sc->sc_dev.dv_xname);
@@ -503,8 +511,12 @@ lerint(sc)
#ifdef LEDEBUG
if (sc->sc_debug)
- printf("sc->sc_last_rd = %x, rmd = %x\n",
- sc->sc_last_rd, rmd);
+ printf("sc->sc_last_rd = %x, rmd: "
+ "ladr %04x, hadr %02x, flags %02x, "
+ "bcnt %04x, mcnt %04x\n",
+ sc->sc_last_rd,
+ rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
+ rmd.rmd2, rmd.rmd3);
#endif
if (++bix == sc->sc_nrbuf)
@@ -529,7 +541,11 @@ letint(sc)
#ifdef LEDEBUG
if (sc->sc_debug)
- printf("trans tmd = %x\n", tmd);
+ printf("trans tmd: "
+ "ladr %04x, hadr %02x, flags %02x, "
+ "bcnt %04x, mcnt %04x\n",
+ tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
+ tmd.tmd2, tmd.tmd3);
#endif
(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
@@ -877,9 +893,10 @@ recv_print(sc, no)
rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
if (len >= sizeof(eh)) {
(*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
- printf("%s: dst %s", ether_sprintf(eh.ether_dhost));
+ printf("%s: dst %s", sc->sc_dev.dv_xname,
+ ether_sprintf(eh.ether_dhost));
printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
- ntohs(eh.ether_type));
+ ntohs(eh.ether_type));
}
}
@@ -902,7 +919,8 @@ xmit_print(sc, no)
tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
if (len >= sizeof(eh)) {
(*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
- printf("%s: dst %s", ether_sprintf(eh.ether_dhost));
+ printf("%s: dst %s", sc->sc_dev.dv_xname,
+ ether_sprintf(eh.ether_dhost));
printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
ntohs(eh.ether_type));
}
@@ -938,8 +956,7 @@ lesetladrf(ac, af)
af[0] = af[1] = af[2] = af[3] = 0x0000;
ETHER_FIRST_MULTI(step, ac, enm);
while (enm != NULL) {
- if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
- sizeof(enm->enm_addrlo)) != 0) {
+ if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
/*
* We must listen to a range of multicast addresses.
* For now, just accept all multicasts, rather than
@@ -1058,7 +1075,6 @@ copytobuf_gap2(sc, fromv, boff, len)
volatile caddr_t buf = sc->sc_mem;
register caddr_t from = fromv;
register volatile u_int16_t *bptr;
- register int xfer;
if (boff & 0x1) {
/* handle unaligned first byte */
@@ -1088,7 +1104,6 @@ copyfrombuf_gap2(sc, tov, boff, len)
register caddr_t to = tov;
register volatile u_int16_t *bptr;
register u_int16_t tmp;
- register int xfer;
if (boff & 0x1) {
/* handle unaligned first byte */
diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c
index d34ba82a096..77dd24748f4 100644
--- a/sys/dev/ic/com.c
+++ b/sys/dev/ic/com.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: com.c,v 1.10 1996/04/18 23:47:32 niklas Exp $ */
-/* $NetBSD: com.c,v 1.75 1996/03/10 09:01:24 cgd Exp $ */
+/* $OpenBSD: com.c,v 1.11 1996/04/21 22:23:15 deraadt Exp $ */
+/* $NetBSD: com.c,v 1.79 1996/04/15 18:54:31 cgd Exp $ */
/*-
* Copyright (c) 1993, 1994, 1995, 1996
@@ -57,7 +57,11 @@
#include <sys/types.h>
#include <sys/device.h>
-#include <machine/cpu.h>
+#ifdef i386 /* XXX */
+#include <machine/cpu.h> /* XXX */
+#else /* XXX */
+#include <machine/intr.h>
+#endif /* XXX */
#include <machine/bus.h>
#include <dev/isa/isavar.h>
@@ -69,6 +73,8 @@
#endif
#define com_lcr com_cfcr
+#include "com.h"
+
#define COM_IBUFSIZE (2 * 512)
#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4)
@@ -109,11 +115,9 @@ struct com_softc {
u_char sc_ibufs[2][COM_IBUFSIZE];
};
-int comprobe __P((struct device *, void *, void *));
#ifdef COM_HAYESP
int comprobeHAYESP __P((bus_io_handle_t hayespioh, struct com_softc *sc));
#endif
-void comattach __P((struct device *, struct device *, void *));
int comopen __P((dev_t, int, int, struct proc *));
int comclose __P((dev_t, int, int, struct proc *));
void comdiag __P((void *));
@@ -122,11 +126,30 @@ void compoll __P((void *));
int comparam __P((struct tty *, struct termios *));
void comstart __P((struct tty *));
-int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int));
+/*
+ * XXX the following two cfattach structs should be different, and possibly
+ * XXX elsewhere.
+ */
+int comprobe __P((struct device *, void *, void *));
+void comattach __P((struct device *, struct device *, void *));
+
+#if NCOM_ISA
+struct cfattach com_isa_ca = {
+ sizeof(struct com_softc), comprobe, comattach
+};
+#endif
-struct cfdriver comcd = {
- NULL, "com", comprobe, comattach, DV_TTY, sizeof(struct com_softc)
+#if NCOM_COMMULTI
+struct cfattach com_commulti_ca = {
+ sizeof(struct com_softc), comprobe, comattach
};
+#endif
+
+struct cfdriver com_cd = {
+ NULL, "com", DV_TTY
+};
+
+int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int));
#ifdef COMCONSOLE
int comdefaultrate = CONSPEED; /* XXX why set default? */
@@ -138,6 +161,7 @@ int comconsinit;
int comconsattached;
bus_chipset_tag_t comconsbc;
bus_io_handle_t comconsioh;
+tcflag_t comconscflag = TTYDEF_CFLAG;
int commajor;
int comsopen = 0;
@@ -157,7 +181,7 @@ extern int kgdb_debug_init;
#define CLR(t, f) (t) &= ~(f)
#define ISSET(t, f) ((t) & (f))
-#include "pcmciabus.h"
+/*#include "pcmciabus.h"*/
#if NPCMCIABUS >0
/* additional setup needed for pcmcia devices */
#include <dev/pcmcia/pcmciabus.h>
@@ -327,13 +351,22 @@ comprobe(parent, match, aux)
int iobase, needioh;
int rv = 1;
+ /*
+ * XXX should be broken out into functions for isa probe and
+ * XXX for commulti probe, with a helper function that contains
+ * XXX most of the interesting stuff.
+ */
+#if NCOM_ISA
if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
struct isa_attach_args *ia = aux;
bc = ia->ia_bc;
iobase = ia->ia_iobase;
needioh = 1;
- } else {
+ } else
+#endif
+#if NCOM_COMMULTI
+ if (1) {
struct commulti_attach_args *ca = aux;
if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ca->ca_slave)
@@ -343,7 +376,9 @@ comprobe(parent, match, aux)
iobase = ca->ca_iobase;
ioh = ca->ca_ioh;
needioh = 0;
- }
+ } else
+#endif
+ return(0); /* This cannot happen */
/* if it's in use as console, it's there. */
if (iobase == comconsaddr && !comconsattached)
@@ -358,12 +393,14 @@ comprobe(parent, match, aux)
bus_io_unmap(bc, ioh, COM_NPORTS);
out:
+#if NCOM_ISA
if (rv && !strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
struct isa_attach_args *ia = aux;
ia->ia_iosize = COM_NPORTS;
ia->ia_msize = 0;
}
+#endif
return (rv);
}
@@ -383,8 +420,14 @@ comattach(parent, self, aux)
int *hayespp;
#endif
+ /*
+ * XXX should be broken out into functions for isa attach and
+ * XXX for commulti attach, with a helper function that contains
+ * XXX most of the interesting stuff.
+ */
sc->sc_hwflags = 0;
sc->sc_swflags = 0;
+#if NCOM_ISA
if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
struct isa_attach_args *ia = aux;
@@ -399,7 +442,10 @@ comattach(parent, self, aux)
} else
ioh = comconsioh;
irq = ia->ia_irq;
- } else {
+ } else
+#endif
+#if NCOM_COMMULTI
+ if (1) {
struct commulti_attach_args *ca = aux;
/*
@@ -412,7 +458,9 @@ comattach(parent, self, aux)
if (ca->ca_noien)
sc->sc_hwflags |= COM_HW_NOIEN;
- }
+ } else
+#endif
+ panic("comattach: impossible");
sc->sc_bc = bc;
sc->sc_ioh = ioh;
@@ -473,9 +521,18 @@ comattach(parent, self, aux)
bus_io_write_1(bc, ioh, com_ier, 0);
bus_io_write_1(bc, ioh, com_mcr, 0);
- if (irq != IRQUNK)
- sc->sc_ih = isa_intr_establish(irq, IST_EDGE, IPL_TTY,
- comintr, sc, sc->sc_dev.dv_xname);
+ if (irq != IRQUNK) {
+#if NCOM_ISA
+ if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) {
+ struct isa_attach_args *ia = aux;
+
+ sc->sc_ih = isa_intr_establish(ia->ia_ic, irq,
+ IST_EDGE, IPL_TTY, comintr, sc,
+ sc->sc_dev.dv_xname);
+ } else
+#endif
+ panic("comattach: IRQ but can't have one");
+ }
#ifdef KGDB
if (kgdb_dev == makedev(commajor, unit)) {
@@ -516,9 +573,9 @@ comopen(dev, flag, mode, p)
int s;
int error = 0;
- if (unit >= comcd.cd_ndevs)
+ if (unit >= com_cd.cd_ndevs)
return ENXIO;
- sc = comcd.cd_devs[unit];
+ sc = com_cd.cd_devs[unit];
if (!sc)
return ENXIO;
@@ -535,7 +592,10 @@ comopen(dev, flag, mode, p)
ttychars(tp);
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
- tp->t_cflag = TTYDEF_CFLAG;
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ tp->t_cflag = comconscflag;
+ else
+ tp->t_cflag = TTYDEF_CFLAG;
if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
SET(tp->t_cflag, CLOCAL);
if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
@@ -644,7 +704,7 @@ comclose(dev, flag, mode, p)
struct proc *p;
{
int unit = COMUNIT(dev);
- struct com_softc *sc = comcd.cd_devs[unit];
+ struct com_softc *sc = com_cd.cd_devs[unit];
struct tty *tp = sc->sc_tty;
bus_chipset_tag_t bc = sc->sc_bc;
bus_io_handle_t ioh = sc->sc_ioh;
@@ -684,7 +744,7 @@ comread(dev, uio, flag)
struct uio *uio;
int flag;
{
- struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
struct tty *tp = sc->sc_tty;
return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
@@ -696,7 +756,7 @@ comwrite(dev, uio, flag)
struct uio *uio;
int flag;
{
- struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
struct tty *tp = sc->sc_tty;
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
@@ -706,7 +766,7 @@ struct tty *
comtty(dev)
dev_t dev;
{
- struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
struct tty *tp = sc->sc_tty;
return (tp);
@@ -734,7 +794,7 @@ comioctl(dev, cmd, data, flag, p)
struct proc *p;
{
int unit = COMUNIT(dev);
- struct com_softc *sc = comcd.cd_devs[unit];
+ struct com_softc *sc = com_cd.cd_devs[unit];
struct tty *tp = sc->sc_tty;
bus_chipset_tag_t bc = sc->sc_bc;
bus_io_handle_t ioh = sc->sc_ioh;
@@ -846,7 +906,7 @@ comparam(tp, t)
struct tty *tp;
struct termios *t;
{
- struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)];
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)];
bus_chipset_tag_t bc = sc->sc_bc;
bus_io_handle_t ioh = sc->sc_ioh;
int ospeed = comspeed(t->c_ospeed);
@@ -985,7 +1045,7 @@ void
comstart(tp)
struct tty *tp;
{
- struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)];
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)];
bus_chipset_tag_t bc = sc->sc_bc;
bus_io_handle_t ioh = sc->sc_ioh;
int s;
@@ -1106,8 +1166,8 @@ compoll(arg)
comevents = 0;
splx(s);
- for (unit = 0; unit < comcd.cd_ndevs; unit++) {
- sc = comcd.cd_devs[unit];
+ for (unit = 0; unit < com_cd.cd_ndevs; unit++) {
+ sc = com_cd.cd_devs[unit];
if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf)
continue;
diff --git a/sys/dev/ic/comvar.h b/sys/dev/ic/comvar.h
index 9b412b06936..c3f8068caec 100644
--- a/sys/dev/ic/comvar.h
+++ b/sys/dev/ic/comvar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: comvar.h,v 1.1 1996/04/19 16:08:34 niklas Exp $ */
-/* $NetBSD: comvar.h,v 1.3 1996/03/10 09:01:26 cgd Exp $ */
+/* $OpenBSD: comvar.h,v 1.2 1996/04/21 22:23:20 deraadt Exp $ */
+/* $NetBSD: comvar.h,v 1.4 1996/04/15 18:54:35 cgd Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -46,3 +46,4 @@ extern int comconsaddr;
extern int comconsattached;
extern bus_chipset_tag_t comconsbc;
extern bus_io_handle_t comconsioh;
+extern tcflag_t comconscflag;
diff --git a/sys/dev/ic/ncr5380sbc.c b/sys/dev/ic/ncr5380sbc.c
index 2fe5e7db748..a7e356d4bac 100644
--- a/sys/dev/ic/ncr5380sbc.c
+++ b/sys/dev/ic/ncr5380sbc.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ncr5380sbc.c,v 1.4 1996/04/18 23:47:19 niklas Exp $ */
-/* $NetBSD: ncr5380sbc.c,v 1.8 1996/03/07 15:00:17 christos Exp $ */
+/* $OpenBSD: ncr5380sbc.c,v 1.5 1996/04/21 22:21:21 deraadt Exp $ */
+/* $NetBSD: ncr5380sbc.c,v 1.9 1996/03/18 23:09:02 gwr Exp $ */
/*
* Copyright (c) 1995 David Jones, Gordon W. Ross
@@ -2330,8 +2330,25 @@ do_actions:
if (act_flags & ACT_DISCONNECT) {
/*
* The device has dropped BSY (or will soon).
- * Return and let ncr5380_sched() do its thing.
+ * We have to wait here for BSY to drop, otherwise
+ * the next command may decide we need a bus reset.
*/
+ timo = ncr5380_wait_nrq_timo; /* XXX */
+ for (;;) {
+ if (!SCI_BUSY(sc))
+ goto busfree;
+ if (--timo <= 0)
+ break;
+ delay(2);
+ }
+ /* Device is sitting on the bus! */
+ printf("%s: SCSI job did not finish, resetting...\n",
+ sc->sc_dev.dv_xname);
+ ncr5380_reset_scsibus(sc);
+ busfree:
+ NCR_TRACE("machine: discon, waited %d\n",
+ ncr5380_wait_nrq_timo - timo);
+
*sc->sci_icmd = 0;
*sc->sci_mode = 0;
*sc->sci_tcmd = PHASE_INVALID;
diff --git a/sys/dev/ic/smc90cx6.c b/sys/dev/ic/smc90cx6.c
new file mode 100644
index 00000000000..afa12df2b80
--- /dev/null
+++ b/sys/dev/ic/smc90cx6.c
@@ -0,0 +1,1231 @@
+/* $NetBSD: smc90cx6.c,v 1.16 1996/03/20 13:28:50 is Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Ignatios Souvatzis
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ignatios Souvatzis
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for the Commodore Busines Machines ARCnet card.
+ */
+
+#define BAHASMCOPY /**/
+#define BAHSOFTCOPY /**/
+#define BAHRETRANSMIT /**/
+/* #define BAHTIMINGS */
+/* #define BAH_DEBUG 3 */
+
+/* zeroth version of M68060 support */
+
+#if defined(M68060) && defined(BAHASMCOPY)
+#undef BAHASMCOPY
+#endif
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/if_arc.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+#include <machine/mtpr.h>
+
+#include <amiga/amiga/device.h>
+#include <amiga/amiga/isr.h>
+#include <amiga/dev/zbusvar.h>
+#include <amiga/dev/if_bahreg.h>
+
+/* these should be elsewhere */
+
+#define ARC_MIN_LEN 1
+#define ARC_MIN_FORBID_LEN 254
+#define ARC_MAX_FORBID_LEN 256
+#define ARC_MAX_LEN 508
+#define ARC_ADDR_LEN 1
+
+/* for watchdog timer. This should be more than enough. */
+#define ARCTIMEOUT (5*IFNET_SLOWHZ)
+
+/*
+ * This currently uses 2 bufs for tx, 2 for rx
+ *
+ * New rx protocol:
+ *
+ * rx has a fillcount variable. If fillcount > (NRXBUF-1),
+ * rx can be switched off from rx hard int.
+ * Else rx is restarted on the other receiver.
+ * rx soft int counts down. if it is == (NRXBUF-1), it restarts
+ * the receiver.
+ * To ensure packet ordering (we need that for 1201 later), we have a counter
+ * which is incremented modulo 256 on each receive and a per buffer
+ * variable, which is set to the counter on filling. The soft int can
+ * compare both values to determine the older packet.
+ *
+ * Transmit direction:
+ *
+ * bah_start checks tx_fillcount
+ * case 2: return
+ *
+ * else fill tx_act ^ 1 && inc tx_fillcount
+ *
+ * check tx_fillcount again.
+ * case 2: set IFF_OACTIVE to stop arc_output from filling us.
+ * case 1: start tx
+ *
+ * tint clears IFF_OCATIVE, decrements and checks tx_fillcount
+ * case 1: start tx on tx_act ^ 1, softcall bah_start
+ * case 0: softcall bah_start
+ *
+ * #define fill(i) get mbuf && copy mbuf to chip(i)
+ */
+
+#ifdef BAHTIMINGS
+/*
+ * ARCnet stats; per interface.
+ */
+struct bah_stats {
+ u_long mincopyin;
+ u_long maxcopyin; /* divided by byte count */
+ u_long mincopyout;
+ u_long maxcopyout;
+ u_long minsend;
+ u_long maxsend;
+ u_long lasttxstart_mics;
+ struct timeval lasttxstart_tv;
+};
+
+#error BAHTIMINGS CODE IS BROKEN; use of clkread() is bogus
+#endif
+
+/*
+ * Arcnet software status per interface
+ */
+struct bah_softc {
+ struct device sc_dev;
+ struct arccom sc_arccom; /* Common arcnet structures */
+ struct isr sc_isr;
+ struct a2060 *sc_base;
+ u_long sc_recontime; /* seconds only, I'm lazy */
+ u_long sc_reconcount; /* for the above */
+ u_long sc_reconcount_excessive; /* for the above */
+#define ARC_EXCESSIVE_RECONS 20
+#define ARC_EXCESSIVE_RECONS_REWARN 400
+ u_char sc_intmask;
+ u_char sc_rx_act; /* 2..3 */
+ u_char sc_tx_act; /* 0..1 */
+ u_char sc_rx_fillcount;
+ u_char sc_tx_fillcount;
+ u_char sc_broadcast[2]; /* is it a broadcast packet? */
+ u_char sc_retransmits[2]; /* unused at the moment */
+#ifdef BAHTIMINGS
+ struct bah_stats sc_stats;
+#endif
+};
+
+int bah_zbus_match __P((struct device *, void *, void *));
+void bah_zbus_attach __P((struct device *, struct device *, void *));
+void bah_init __P((struct bah_softc *));
+void bah_reset __P((struct bah_softc *));
+void bah_stop __P((struct bah_softc *));
+void bah_start __P((struct ifnet *));
+int bahintr __P((struct bah_softc *sc));
+int bah_ioctl __P((struct ifnet *, unsigned long, caddr_t));
+void bah_watchdog __P((int));
+void movepout __P((u_char *from, u_char __volatile *to, int len));
+void movepin __P((u_char __volatile *from, u_char *to, int len));
+void bah_srint __P((void *vsc, void *dummy));
+void callstart __P((void *vsc, void *dummy));
+
+#ifdef BAHTIMINGS
+int clkread();
+#endif
+
+struct cfattach bah_zbus_ca = {
+ sizeof(struct bah_softc), bah_zbus_match, bah_zbus_attach
+};
+
+struct cfdriver bah_cd = {
+ NULL, "bah", DV_IFNET
+};
+
+int
+bah_zbus_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct zbus_args *zap = aux;
+
+ if ((zap->manid == 514 || zap->manid == 1053) && zap->prodid == 9)
+ return (1);
+
+ return (0);
+}
+
+void
+bah_zbus_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct bah_softc *sc = (void *)self;
+ struct zbus_args *zap = aux;
+ struct ifnet *ifp = &sc->sc_arccom.ac_if;
+ int s, linkaddress;
+
+#if (defined(BAH_DEBUG) && (BAH_DEBUG > 2))
+ printf("\n%s: attach(0x%x, 0x%x, 0x%x)\n",
+ sc->sc_dev.dv_xname, parent, self, aux);
+#endif
+ s = splhigh();
+ sc->sc_base = zap->va;
+
+ /*
+ * read the arcnet address from the board
+ */
+
+ sc->sc_base->kick1 = 0x0;
+ sc->sc_base->kick2 = 0x0;
+ DELAY(200);
+
+ sc->sc_base->kick1 = 0xFF;
+ sc->sc_base->kick2 = 0xFF;
+ do {
+ DELAY(200);
+ } while (!(sc->sc_base->status & ARC_POR));
+
+ linkaddress = sc->sc_base->dipswitches;
+
+#ifdef BAHTIMINGS
+ printf(": link addr 0x%02x(%ld), with timer\n",
+ linkaddress, linkaddress);
+#else
+ printf(": link addr 0x%02x(%ld)\n", linkaddress, linkaddress);
+#endif
+
+ sc->sc_arccom.ac_anaddr = linkaddress;
+
+ /* clear the int mask... */
+
+ sc->sc_base->status = sc->sc_intmask = 0;
+
+ sc->sc_base->command = ARC_CONF(CONF_LONG);
+ sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG);
+ sc->sc_recontime = sc->sc_reconcount = 0;
+
+ /* and reenable kernel int level */
+ splx(s);
+
+ /*
+ * set interface to stopped condition (reset)
+ */
+ bah_stop(sc);
+
+ ifp->if_unit = sc->sc_dev.dv_unit;
+ ifp->if_name = bah_cd.cd_name;
+ ifp->if_output = arc_output;
+ ifp->if_start = bah_start;
+ ifp->if_ioctl = bah_ioctl;
+ ifp->if_timer = 0;
+ ifp->if_watchdog = bah_watchdog;
+
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX |
+ IFF_NOTRAILERS | IFF_NOARP;
+
+ ifp->if_mtu = ARCMTU;
+
+ if_attach(ifp);
+ arc_ifattach(ifp);
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_ARCNET, ARC_HDRLEN);
+#endif
+ /* under heavy load we need four of them: */
+ alloc_sicallback();
+ alloc_sicallback();
+ alloc_sicallback();
+ alloc_sicallback();
+
+ sc->sc_isr.isr_intr = bahintr;
+ sc->sc_isr.isr_arg = sc;
+ sc->sc_isr.isr_ipl = 2;
+ add_isr(&sc->sc_isr);
+}
+
+/*
+ * Initialize device
+ *
+ */
+void
+bah_init(sc)
+ struct bah_softc *sc;
+{
+ struct ifnet *ifp;
+ int s;
+
+ ifp = &sc->sc_arccom.ac_if;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ s = splnet();
+ ifp->if_flags |= IFF_RUNNING;
+ bah_reset(sc);
+ bah_start(ifp);
+ splx(s);
+ }
+}
+
+/*
+ * Reset the interface...
+ *
+ * this assumes that it is called inside a critical section...
+ *
+ */
+void
+bah_reset(sc)
+ struct bah_softc *sc;
+{
+ struct ifnet *ifp;
+ int linkaddress;
+
+ ifp = &sc->sc_arccom.ac_if;
+
+#ifdef BAH_DEBUG
+ printf("%s: reset\n", sc->sc_dev.dv_xname);
+#endif
+ /* stop hardware in case it still runs */
+
+ sc->sc_base->kick1 = 0;
+ sc->sc_base->kick2 = 0;
+ DELAY(200);
+
+ /* and restart it */
+ sc->sc_base->kick1 = 0xFF;
+ sc->sc_base->kick2 = 0xFF;
+
+ do {
+ DELAY(200);
+ } while (!(sc->sc_base->status & ARC_POR));
+
+ linkaddress = sc->sc_base->dipswitches;
+
+#if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
+ printf("bah%ld: reset: card reset, link addr = 0x%02x (%ld)\n",
+ ifp->if_unit, linkaddress, linkaddress);
+#endif
+ sc->sc_arccom.ac_anaddr = linkaddress;
+
+ /* tell the routing level about the (possibly changed) link address */
+ arc_ifattach(ifp);
+
+ /* POR is NMI, but we need it below: */
+ sc->sc_intmask = ARC_RECON|ARC_POR;
+ sc->sc_base->status = sc->sc_intmask;
+ sc->sc_base->command = ARC_CONF(CONF_LONG);
+
+#ifdef BAH_DEBUG
+ printf("%s: reset: chip configured, status=0x%02x\n",
+ sc->sc_dev.dv_xname, sc->sc_base->status);
+#endif
+
+ sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG);
+
+#ifdef BAH_DEBUG
+ printf("%s: reset: bits cleared, status=0x%02x\n",
+ sc->sc_dev.dv_xname, sc->sc_base->status);
+#endif
+
+ sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
+
+ /* start receiver */
+
+ sc->sc_intmask |= ARC_RI;
+ sc->sc_rx_fillcount = 0;
+ sc->sc_rx_act = 2;
+
+ sc->sc_base->command = ARC_RXBC(2);
+ sc->sc_base->status = sc->sc_intmask;
+
+#ifdef BAH_DEBUG
+ printf("%s: reset: started receiver, status=0x%02x\n",
+ sc->sc_dev.dv_xname, sc->sc_base->status);
+#endif
+
+ /* and init transmitter status */
+ sc->sc_tx_act = 0;
+ sc->sc_tx_fillcount = 0;
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+#ifdef BAHTIMINGS
+ bzero((caddr_t)&(sc->sc_stats), sizeof(sc->sc_stats));
+ sc->sc_stats.mincopyin =
+ sc->sc_stats.mincopyout =
+ sc->sc_stats.minsend = ULONG_MAX;
+#endif
+
+ bah_start(ifp);
+}
+
+/*
+ * Take interface offline
+ */
+void
+bah_stop(sc)
+ struct bah_softc *sc;
+{
+ /* Stop the interrupts */
+ sc->sc_base->status = 0;
+
+ /* Stop the interface */
+ sc->sc_base->kick1 = 0;
+ sc->sc_base->kick2 = 0;
+
+ /* Stop watchdog timer */
+ sc->sc_arccom.ac_if.if_timer = 0;
+
+#ifdef BAHTIMINGS
+ log(LOG_DEBUG,"%s: to board: %6lu .. %6lu ns/byte\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_stats.mincopyout, sc->sc_stats.maxcopyout);
+
+ log(LOG_DEBUG,"%s: from board: %6lu .. %6lu ns/byte\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_stats.mincopyin, sc->sc_stats.maxcopyin);
+
+ log(LOG_DEBUG,"%s: send time: %6lu .. %6lu mics/byte\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_stats.minsend, sc->sc_stats.maxsend);
+
+ sc->sc_stats.minsend =
+ sc->sc_stats.mincopyout =
+ sc->sc_stats.mincopyin = ULONG_MAX;
+ sc->sc_stats.maxsend =
+ sc->sc_stats.maxcopyout =
+ sc->sc_stats.maxcopyin = 0;
+#endif
+}
+
+__inline void
+movepout(from, to, len)
+ u_char *from;
+ __volatile u_char *to;
+ int len;
+{
+#ifdef BAHASMCOPY
+ u_short shortd;
+ u_long longd, longd1, longd2, longd3, longd4;
+
+ if ((len > 3) && ((long)from) & 3) {
+ switch (((long)from) & 3) {
+ case 3:
+ *to = *from++;
+ to += 2; --len;
+ break;
+ case 1:
+ *to = *from++;
+ to += 2; --len;
+ case 2:
+ shortd = *((u_short *)from)++;
+ asm("movepw %0,%1@(0)" : : "d"(shortd), "a"(to));
+ to += 4; len -= 2;
+ break;
+ default:
+ }
+
+ while (len >= 32) {
+ longd1 = *((u_long *)from)++;
+ longd2 = *((u_long *)from)++;
+ longd3 = *((u_long *)from)++;
+ longd4 = *((u_long *)from)++;
+ asm("movepl %0,%1@(0)" : : "d"(longd1), "a"(to));
+ asm("movepl %0,%1@(8)" : : "d"(longd2), "a"(to));
+ asm("movepl %0,%1@(16)" : : "d"(longd3), "a"(to));
+ asm("movepl %0,%1@(24)" : : "d"(longd4), "a"(to));
+
+ longd1 = *((u_long *)from)++;
+ longd2 = *((u_long *)from)++;
+ longd3 = *((u_long *)from)++;
+ longd4 = *((u_long *)from)++;
+ asm("movepl %0,%1@(32)" : : "d"(longd1), "a"(to));
+ asm("movepl %0,%1@(40)" : : "d"(longd2), "a"(to));
+ asm("movepl %0,%1@(48)" : : "d"(longd3), "a"(to));
+ asm("movepl %0,%1@(56)" : : "d"(longd4), "a"(to));
+
+ to += 64; len -= 32;
+ }
+ while (len > 0) {
+ longd = *((u_long *)from)++;
+ asm("movepl %0,%1@(0)" : : "d"(longd), "a"(to));
+ to += 8; len -= 4;
+ }
+ }
+#endif
+ while (len > 0) {
+ *to = *from++;
+ to += 2;
+ --len;
+ }
+}
+
+/*
+ * Start output on interface. Get another datagram to send
+ * off the interface queue, and copy it to the
+ * interface becore starting the output
+ *
+ * this assumes that it is called inside a critical section...
+ * XXX hm... does it still?
+ *
+ */
+void
+bah_start(ifp)
+ struct ifnet *ifp;
+{
+ struct bah_softc *sc;
+ struct mbuf *m,*mp;
+ __volatile u_char *bah_ram_ptr;
+ int len, tlen, offset, s, buffer;
+#ifdef BAHTIMINGS
+ u_long copystart, lencopy, perbyte;
+#endif
+
+ sc = bah_cd.cd_devs[ifp->if_unit];
+
+#if defined(BAH_DEBUG) && (BAH_DEBUG > 3)
+ printf("%s: start(0x%x)\n", sc->sc_dev.dv_xname, ifp);
+#endif
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ return;
+
+ s = splnet();
+
+ if (sc->sc_tx_fillcount >= 2) {
+ splx(s);
+ return;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ buffer = sc->sc_tx_act ^ 1;
+
+ splx(s);
+
+ if (m == 0)
+ return;
+
+#if NBPFILTER > 0
+ /*
+ * If bpf is listening on this interface, let it
+ * see the packet before we commit it to the wire
+ *
+ * (can't give the copy in A2060 card RAM to bpf, because
+ * that RAM is just accessed as on every other byte)
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+#ifdef BAH_DEBUG
+ m = m_pullup(m,3); /* gcc does structure padding */
+ printf("%s: start: filling %ld from %ld to %ld type %ld\n",
+ sc->sc_dev.dv_xname, buffer, mtod(m, u_char *)[0],
+ mtod(m, u_char *)[1], mtod(m, u_char *)[2]);
+#else
+ m = m_pullup(m, 2);
+#endif
+ bah_ram_ptr = sc->sc_base->buffers + buffer*512*2;
+
+ /* write the addresses to RAM and throw them away */
+
+ /*
+ * Hardware does this: Yet Another Microsecond Saved.
+ * (btw, timing code says usually 2 microseconds)
+ * bah_ram_ptr[0*2] = mtod(m, u_char *)[0];
+ */
+ bah_ram_ptr[1 * 2] = mtod(m, u_char *)[1];
+ m_adj(m, 2);
+
+ /* get total length left at this point */
+ tlen = m->m_pkthdr.len;
+ if (tlen < ARC_MIN_FORBID_LEN) {
+ offset = 256 - tlen;
+ bah_ram_ptr[2 * 2] = offset;
+ } else {
+ bah_ram_ptr[2 * 2] = 0;
+ if (tlen <= ARC_MAX_FORBID_LEN)
+ offset = 255; /* !!! */
+ else {
+ if (tlen > ARC_MAX_LEN)
+ tlen = ARC_MAX_LEN;
+ offset = 512 - tlen;
+ }
+ bah_ram_ptr[3 * 2] = offset;
+
+ }
+ bah_ram_ptr += offset * 2;
+
+ /* lets loop through the mbuf chain */
+
+ for (mp = m; mp; mp = mp->m_next) {
+ if ((len = mp->m_len)) { /* YAMS */
+#ifdef BAHTIMINGS
+ lencopy = len;
+ copystart = clkread();
+#endif
+ movepout(mtod(mp, caddr_t), bah_ram_ptr, len);
+
+#ifdef BAHTIMINGS
+ perbyte = 1000 * (clkread() - copystart) / lencopy;
+ sc->sc_stats.mincopyout =
+ ulmin(sc->sc_stats.mincopyout, perbyte);
+ sc->sc_stats.maxcopyout =
+ ulmax(sc->sc_stats.maxcopyout, perbyte);
+#endif
+ bah_ram_ptr += len*2;
+ }
+ }
+
+ sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
+ sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5;
+
+ /* actually transmit the packet */
+ s = splnet();
+
+ if (++sc->sc_tx_fillcount > 1) {
+ /*
+ * We are filled up to the rim. No more bufs for the moment,
+ * please.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ } else {
+#ifdef BAH_DEBUG
+ printf("%s: start: starting transmitter on buffer %d\n",
+ sc->sc_dev.dv_xname, buffer);
+#endif
+ /* Transmitter was off, start it */
+ sc->sc_tx_act = buffer;
+
+ /*
+ * We still can accept another buf, so don't:
+ * ifp->if_flags |= IFF_OACTIVE;
+ */
+ sc->sc_intmask |= ARC_TA;
+ sc->sc_base->command = ARC_TX(buffer);
+ sc->sc_base->status = sc->sc_intmask;
+
+ sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT;
+#ifdef BAHTIMINGS
+ bcopy((caddr_t)&time,
+ (caddr_t)&(sc->sc_stats.lasttxstart_tv),
+ sizeof(struct timeval));
+
+ sc->sc_stats.lasttxstart_mics = clkread();
+#endif
+ }
+ splx(s);
+ m_freem(m);
+
+ /*
+ * After 10 times reading the docs, I realized
+ * that in the case the receiver NAKs the buffer request,
+ * the hardware retries till shutdown.
+ * This is integrated now in the code above.
+ */
+
+ return;
+}
+
+void
+callstart(vsc, dummy)
+ void *vsc, *dummy;
+{
+ struct bah_softc *sc;
+
+ sc = (struct bah_softc *)vsc;
+ bah_start(&sc->sc_arccom.ac_if);
+}
+
+__inline void
+movepin(from, to, len)
+ __volatile u_char *from;
+ u_char *to;
+ int len;
+{
+#ifdef BAHASMCOPY
+ unsigned long longd, longd1, longd2, longd3, longd4;
+ ushort shortd;
+
+ if ((len > 3) && (((long)to) & 3)) {
+ switch (((long)to) & 3) {
+ case 3: *to++ = *from;
+ from += 2; --len;
+ break;
+ case 1: *to++ = *from;
+ from += 2; --len;
+ case 2: asm ("movepw %1@(0),%0": "=d" (shortd) : "a" (from));
+ *((ushort *)to)++ = shortd;
+ from += 4; len -= 2;
+ break;
+ default:
+ }
+
+ while (len >= 32) {
+ asm("movepl %1@(0),%0" : "=d"(longd1) : "a" (from));
+ asm("movepl %1@(8),%0" : "=d"(longd2) : "a" (from));
+ asm("movepl %1@(16),%0" : "=d"(longd3) : "a" (from));
+ asm("movepl %1@(24),%0" : "=d"(longd4) : "a" (from));
+ *((unsigned long *)to)++ = longd1;
+ *((unsigned long *)to)++ = longd2;
+ *((unsigned long *)to)++ = longd3;
+ *((unsigned long *)to)++ = longd4;
+
+ asm("movepl %1@(32),%0" : "=d"(longd1) : "a" (from));
+ asm("movepl %1@(40),%0" : "=d"(longd2) : "a" (from));
+ asm("movepl %1@(48),%0" : "=d"(longd3) : "a" (from));
+ asm("movepl %1@(56),%0" : "=d"(longd4) : "a" (from));
+ *((unsigned long *)to)++ = longd1;
+ *((unsigned long *)to)++ = longd2;
+ *((unsigned long *)to)++ = longd3;
+ *((unsigned long *)to)++ = longd4;
+
+ from += 64; len -= 32;
+ }
+ while (len > 0) {
+ asm("movepl %1@(0),%0" : "=d"(longd) : "a" (from));
+ *((unsigned long *)to)++ = longd;
+ from += 8; len -= 4;
+ }
+
+ }
+#endif /* BAHASMCOPY */
+ while (len > 0) {
+ *to++ = *from;
+ from += 2;
+ --len;
+ }
+
+}
+
+/*
+ * Arcnet interface receiver soft interrupt:
+ * get the stuff out of any filled buffer we find.
+ */
+void
+bah_srint(vsc, dummy)
+ void *vsc, *dummy;
+{
+ struct bah_softc *sc;
+ int buffer, len, len1, amount, offset, s, i, type;
+ u_char __volatile *bah_ram_ptr;
+ struct mbuf *m, *dst, *head;
+ struct arc_header *ah;
+ struct ifnet *ifp;
+#ifdef BAHTIMINGS
+ u_long copystart, lencopy, perbyte;
+#endif
+ sc = (struct bah_softc *)vsc;
+ ifp = &sc->sc_arccom.ac_if;
+ head = 0;
+
+ s = splnet();
+ buffer = sc->sc_rx_act ^ 1;
+ splx(s);
+
+ /* Allocate header mbuf */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+ if (m == 0) {
+ /*
+ * in case s.th. goes wrong with mem, drop it
+ * to make sure the receiver can be started again
+ * count it as input error (we dont have any other
+ * detectable)
+ */
+ ifp->if_ierrors++;
+ goto cleanup;
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+
+ /*
+ * Align so that IP packet will be longword aligned. Here we
+ * assume that m_data of new packet is longword aligned.
+ * When implementing PHDS, we might have to change it to 2,
+ * (2*sizeof(ulong) - ARC_HDRNEWLEN)), packet type dependent.
+ */
+
+ bah_ram_ptr = sc->sc_base->buffers + buffer*512*2;
+ offset = bah_ram_ptr[2*2];
+ if (offset)
+ len = 256 - offset;
+ else {
+ offset = bah_ram_ptr[3*2];
+ len = 512 - offset;
+ }
+ type = bah_ram_ptr[offset*2];
+ m->m_data += 1 + arc_isphds(type);
+
+ head = m;
+ ah = mtod(head, struct arc_header *);
+
+ ah->arc_shost = bah_ram_ptr[0*2];
+ ah->arc_dhost = bah_ram_ptr[1*2];
+
+ m->m_pkthdr.len = len+2; /* whole packet length */
+ m->m_len = 2; /* mbuf filled with ARCnet addresses */
+ bah_ram_ptr += offset*2; /* ram buffer continues there */
+
+ while (len > 0) {
+
+ len1 = len;
+ amount = M_TRAILINGSPACE(m);
+
+ if (amount == 0) {
+ dst = m;
+ MGET(m, M_DONTWAIT, MT_DATA);
+
+ if (m == 0) {
+ ifp->if_ierrors++;
+ goto cleanup;
+ }
+
+ if (len1 >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+
+ m->m_len = 0;
+ dst->m_next = m;
+ amount = M_TRAILINGSPACE(m);
+ }
+
+ if (amount < len1)
+ len1 = amount;
+
+#ifdef BAHTIMINGS
+ lencopy = len;
+ copystart = clkread();
+#endif
+
+ movepin(bah_ram_ptr, mtod(m, u_char *) + m->m_len, len1);
+
+#ifdef BAHTIMINGS
+ perbyte = 1000 * (clkread() - copystart) / lencopy;
+ sc->sc_stats.mincopyin =
+ ulmin(sc->sc_stats.mincopyin, perbyte);
+ sc->sc_stats.maxcopyin =
+ ulmax(sc->sc_stats.maxcopyin, perbyte);
+#endif
+
+ m->m_len += len1;
+ bah_ram_ptr += len1*2;
+ len -= len1;
+ }
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, head);
+#endif
+
+ arc_input(&sc->sc_arccom.ac_if, head);
+
+ /* arc_input has freed it, we dont need to... */
+
+ head = NULL;
+ ifp->if_ipackets++;
+
+cleanup:
+
+ if (head != NULL)
+ m_freem(head);
+
+ /* mark buffer as invalid by source id 0 */
+ sc->sc_base->buffers[buffer*512*2] = 0;
+ s = splnet();
+
+ if (--sc->sc_rx_fillcount == 2 - 1) {
+
+ /* was off, restart it on buffer just emptied */
+ sc->sc_rx_act = buffer;
+ sc->sc_intmask |= ARC_RI;
+
+ /* this also clears the RI flag interupt: */
+ sc->sc_base->command = ARC_RXBC(buffer);
+ sc->sc_base->status = sc->sc_intmask;
+
+#ifdef BAH_DEBUG
+ printf("%s: srint: restarted rx on buf %ld\n",
+ sc->sc_dev.dv_xname, buffer);
+#endif
+ }
+ splx(s);
+}
+
+__inline static void
+bah_tint(sc, isr)
+ struct bah_softc *sc;
+ int isr;
+{
+ struct ifnet *ifp;
+
+ int buffer;
+#ifdef BAHTIMINGS
+ int clknow;
+#endif
+
+ ifp = &(sc->sc_arccom.ac_if);
+ buffer = sc->sc_tx_act;
+
+ /*
+ * retransmit code:
+ * Normal situtations first for fast path:
+ * If acknowledgement received ok or broadcast, we're ok.
+ * else if
+ */
+
+ if (isr & ARC_TMA || sc->sc_broadcast[buffer])
+ sc->sc_arccom.ac_if.if_opackets++;
+#ifdef BAHRETRANSMIT
+ else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0
+ && --sc->sc_retransmits[buffer] > 0) {
+ /* retransmit same buffer */
+ sc->sc_base->command = ARC_TX(buffer);
+ return;
+ }
+#endif
+ else
+ ifp->if_oerrors++;
+
+
+#ifdef BAHTIMINGS
+ clknow = clkread();
+
+ sc->sc_stats.minsend = ulmin(sc->sc_stats.minsend,
+ clknow - sc->sc_stats.lasttxstart_mics);
+
+ sc->sc_stats.maxsend = ulmax(sc->sc_stats.maxsend,
+ clknow - sc->sc_stats.lasttxstart_mics);
+#endif
+
+ /* We know we can accept another buffer at this point. */
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ if (--sc->sc_tx_fillcount > 0) {
+
+ /*
+ * start tx on other buffer.
+ * This also clears the int flag
+ */
+ buffer ^= 1;
+ sc->sc_tx_act = buffer;
+
+ /*
+ * already given:
+ * sc->sc_intmask |= ARC_TA;
+ * sc->sc_base->status = sc->sc_intmask;
+ */
+ sc->sc_base->command = ARC_TX(buffer);
+ /* init watchdog timer */
+ ifp->if_timer = ARCTIMEOUT;
+
+#ifdef BAHTIMINGS
+ bcopy((caddr_t)&time,
+ (caddr_t)&(sc->sc_stats.lasttxstart_tv),
+ sizeof(struct timeval));
+
+ sc->sc_stats.lasttxstart_mics = clkread();
+#endif
+
+#if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
+ printf("%s: tint: starting tx on buffer %d, status 0x%02x\n",
+ sc->sc_dev.dv_xname, buffer, sc->sc_base->status);
+#endif
+ } else {
+ /* have to disable TX interrupt */
+ sc->sc_intmask &= ~ARC_TA;
+ sc->sc_base->status = sc->sc_intmask;
+ /* ... and watchdog timer */
+ ifp->if_timer = 0;
+
+#ifdef BAH_DEBUG
+ printf("%s: tint: no more buffers to send, status 0x%02x\n",
+ sc->sc_dev.dv_xname, sc->sc_base->status);
+#endif
+ }
+
+#ifdef BAHSOFTCOPY
+ /* schedule soft int to fill a new buffer for us */
+ add_sicallback((sifunc_t)callstart, sc, NULL);
+#else
+ /* call it directly */
+ callstart(sc, NULL);
+#endif
+}
+
+/*
+ * Our interrupt routine
+ */
+int
+bahintr(sc)
+ struct bah_softc *sc;
+{
+ u_char isr, maskedisr;
+ int buffer;
+ u_long newsec;
+
+ isr = sc->sc_base->status;
+ maskedisr = isr & sc->sc_intmask;
+ if (!maskedisr)
+ return (0);
+
+#if defined(BAH_DEBUG) && (BAH_DEBUG>1)
+ printf("%s: intr: status 0x%02x, intmask 0x%02x\n",
+ sc->sc_dev.dv_xname, isr, sc->sc_intmask);
+#endif
+
+ if (maskedisr & ARC_POR) {
+ sc->sc_arccom.ac_anaddr = sc->sc_base->dipswitches;
+ sc->sc_base->command = ARC_CLR(CLR_POR);
+ log(LOG_WARNING, "%s: intr: got spurious power on reset int\n",
+ sc->sc_dev.dv_xname);
+ }
+
+ if (maskedisr & ARC_RECON) {
+ /*
+ * we dont need to:
+ * sc->sc_base->command = ARC_CONF(CONF_LONG);
+ */
+ sc->sc_base->command = ARC_CLR(CLR_RECONFIG);
+ sc->sc_arccom.ac_if.if_collisions++;
+
+ /*
+ * If more than 2 seconds per reconfig:
+ * Reset time and counter.
+ * else:
+ * If more than ARC_EXCESSIVE_RECONFIGS reconfigs
+ * since last burst, complain and set treshold for
+ * warnings to ARC_EXCESSIVE_RECONS_REWARN.
+ *
+ * This allows for, e.g., new stations on the cable, or
+ * cable switching as long as it is over after (normally)
+ * 16 seconds.
+ *
+ * XXX TODO: check timeout bits in status word and double
+ * time if necessary.
+ */
+
+ newsec = time.tv_sec;
+ if (newsec - sc->sc_recontime > 2 * sc->sc_reconcount) {
+ sc->sc_recontime = newsec;
+ sc->sc_reconcount = 0;
+ sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
+ } else if (++sc->sc_reconcount > sc->sc_reconcount_excessive) {
+ sc->sc_reconcount_excessive =
+ ARC_EXCESSIVE_RECONS_REWARN;
+ log(LOG_WARNING,
+ "%s: excessive token losses, cable problem?\n",
+ sc->sc_dev.dv_xname);
+ sc->sc_recontime = newsec;
+ sc->sc_reconcount = 0;
+ }
+ }
+
+ if (maskedisr & ARC_RI) {
+
+#if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
+ printf("%s: intr: hard rint, act %ld\n",
+ sc->sc_dev.dv_xname, sc->sc_rx_act);
+#endif
+
+ buffer = sc->sc_rx_act;
+ /* look if buffer is marked invalid: */
+ if (sc->sc_base->buffers[buffer*512*2] == 0) {
+ /* invalid marked buffer (or illegally configured sender) */
+ log(LOG_WARNING,
+ "%s: spurious RX interrupt or sender 0 (ignored)\n",
+ sc->sc_dev.dv_xname);
+ /*
+ * restart receiver on same buffer.
+ */
+ sc->sc_base->command = ARC_RXBC(buffer);
+
+ } else if (++sc->sc_rx_fillcount > 1) {
+ sc->sc_intmask &= ~ARC_RI;
+ sc->sc_base->status = sc->sc_intmask;
+ } else {
+
+ buffer ^= 1;
+ sc->sc_rx_act = buffer;
+
+ /*
+ * Start receiver on other receive buffer.
+ * This also clears the RI interupt flag.
+ */
+ sc->sc_base->command = ARC_RXBC(buffer);
+ /* we are in the RX intr, so mask is ok for RX */
+
+#ifdef BAH_DEBUG
+ printf("%s: started rx for buffer %ld, status 0x%02x\n",
+ sc->sc_dev.dv_xname, sc->sc_rx_act,
+ sc->sc_base->status);
+#endif
+ }
+
+#ifdef BAHSOFTCOPY
+ /* this one starts a soft int to copy out of the hw */
+ add_sicallback((sifunc_t)bah_srint, sc,NULL);
+#else
+ /* this one does the copy here */
+ bah_srint(sc,NULL);
+#endif
+ }
+
+ if (maskedisr & ARC_TA)
+ bah_tint(sc, isr);
+
+ return (1);
+}
+
+/*
+ * Process an ioctl request.
+ * This code needs some work - it looks pretty ugly.
+ */
+int
+bah_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct bah_softc *sc;
+ register struct ifaddr *ifa;
+ int s, error;
+
+ error = 0;
+ sc = bah_cd.cd_devs[ifp->if_unit];
+ ifa = (struct ifaddr *)data;
+ s = splnet();
+
+#if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
+ printf("%s: ioctl() called, cmd = 0x%x\n",
+ sc->sc_dev.dv_xname, command);
+#endif
+
+ switch (command) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ bah_init(sc);
+ break;
+#endif
+ default:
+ bah_init(sc);
+ break;
+ }
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running,
+ * then stop it.
+ */
+ bah_stop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ bah_init(sc);
+ }
+ break;
+
+ /* Multicast not supported */
+
+ default:
+ error = EINVAL;
+ }
+
+ splx(s);
+ return (error);
+}
+
+/*
+ * watchdog routine for transmitter.
+ *
+ * We need this, because else a receiver whose hardware is alive, but whose
+ * software has not enabled the Receiver, would make our hardware wait forever
+ * Discovered this after 20 times reading the docs.
+ *
+ * Only thing we do is disable transmitter. We'll get an transmit timeout,
+ * and the int handler will have to decide not to retransmit (in case
+ * retransmission is implemented).
+ *
+ * This one assumes being called inside splnet(), and that net >= ipl2
+ */
+
+void
+bah_watchdog(unit)
+int unit;
+{
+ struct bah_softc *sc;
+ struct ifnet *ifp;
+
+ sc = bah_cd.cd_devs[unit];
+ ifp = &(sc->sc_arccom.ac_if);
+
+ sc->sc_base->command = ARC_TXDIS;
+ return;
+}
diff --git a/sys/dev/ic/smc90cx6reg.h b/sys/dev/ic/smc90cx6reg.h
new file mode 100644
index 00000000000..f2ec2a06e5c
--- /dev/null
+++ b/sys/dev/ic/smc90cx6reg.h
@@ -0,0 +1,99 @@
+/* $NetBSD: smc90cx6reg.h,v 1.4 1995/06/07 00:16:59 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Ignatios Souvatzis
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ignatios Souvatzis
+ * for the NetBSD project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The A2060/A560 card use the SMC COM90C26 Arcnet chipset.
+ * First or last 16k segment, resp., write a fifo which drives the reset line.
+ * 2nd 16k segment contains the registers.
+ * 3rd 16k segment contains the buffer RAM.
+ * All are only accessible at even addresses.
+ */
+
+/* CBM Arcnet board */
+#define MANUFACTURER_1 514
+#define PRODUCT_1 9
+
+/* Ameristar board */
+#define MANUFACTURER_2 1053
+#define PRODUCT_2 9
+
+struct a2060 {
+ volatile u_int8_t kick1;
+ u_int8_t pad1[16383];
+ volatile u_int8_t status; /* also intmask */
+ u_int8_t pad2;
+ volatile u_int8_t command;
+ u_int8_t pad3[16381];
+ volatile u_int8_t buffers[4096]; /* even bytes only */
+ u_int8_t pad4[12228];
+ volatile u_int8_t kick2;
+ u_int8_t pad5[16383];
+};
+
+#define checkbyte buffers[0]
+#define dipswitches buffers[2]
+
+/* calculate address for board b, buffer no n and offset o */
+#define BUFPTR(b,n,o) (&(b)->buffers[(n)*512+(o)*2])
+
+#define ARC_TXDIS 0x01
+#define ARC_RXDIS 0x02
+#define ARC_TX(x) (0x03 | ((x)<<3))
+#define ARC_RX(x) (0x04 | ((x)<<3))
+#define ARC_RXBC(x) (0x84 | ((x)<<3))
+
+#define ARC_CONF(x) (0x05 | (x))
+#define CLR_POR 0x08
+#define CLR_RECONFIG 0x10
+
+#define ARC_CLR(x) (0x06 | (x))
+#define CONF_LONG 0x08
+#define CONF_SHORT 0x00
+
+/*
+ * These are not in the COM90C65 docs. Derived from the arcnet.asm
+ * packet driver by Philippe Prindeville and Russel Nelson.
+ */
+
+#define ARC_LDTST(x) (0x07 | (x))
+#define TEST_ON 0x08
+#define TEST_OFF 0x00
+
+#define ARC_TA 1 /* int mask also */
+#define ARC_TMA 2
+#define ARC_RECON 4 /* int mask also */
+#define ARC_TEST 8 /* not in the COM90C65 docs (see above) */
+#define ARC_POR 0x10 /* non maskable interrupt */
+#define ARC_ET1 0x20 /* timeout value bits, normally 1 */
+#define ARC_ET2 0x40 /* timeout value bits, normally 1 */
+#define ARC_RI 0x80 /* int mask also */
diff --git a/sys/dev/ic/z8530sc.c b/sys/dev/ic/z8530sc.c
index 7b7ef11d4aa..387f2b8aaf7 100644
--- a/sys/dev/ic/z8530sc.c
+++ b/sys/dev/ic/z8530sc.c
@@ -1,4 +1,5 @@
-/* $NetBSD: z8530sc.c,v 1.1 1996/01/24 01:07:23 gwr Exp $ */
+/* $OpenBSD: z8530sc.c,v 1.2 1996/04/21 22:21:35 deraadt Exp $ */
+/* $NetBSD: z8530sc.c,v 1.3 1996/04/10 21:44:35 gwr Exp $ */
/*
* Copyright (c) 1994 Gordon W. Ross
@@ -82,7 +83,7 @@ zs_break(cs, set)
cs->cs_preg[5] &= ~ZSWR5_BREAK;
cs->cs_creg[5] &= ~ZSWR5_BREAK;
}
- ZS_WRITE(cs, 5, cs->cs_creg[5]);
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
splx(s);
}
@@ -96,8 +97,8 @@ zs_getspeed(cs)
{
int tconst;
- tconst = ZS_READ(cs, 12);
- tconst |= ZS_READ(cs, 13) << 8;
+ tconst = zs_read_reg(cs, 12);
+ tconst |= zs_read_reg(cs, 13) << 8;
return (TCONST_TO_BPS(cs->cs_pclk_div16, tconst));
}
@@ -112,21 +113,20 @@ zs_iflush(cs)
for (;;) {
/* Is there input available? */
- rr0 = *(cs->cs_reg_csr);
- ZS_DELAY();
+ rr0 = zs_read_csr(cs);
if ((rr0 & ZSRR0_RX_READY) == 0)
break;
- /* Read the data. */
- c = *(cs->cs_reg_data);
- ZS_DELAY();
+ /*
+ * 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);
- /* Need to read status register too? */
- rr1 = ZS_READ(cs, 1);
if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
/* Clear the receive error. */
- *(cs->cs_reg_csr) = ZSWR0_RESET_ERRORS;
- ZS_DELAY();
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
}
}
}
@@ -149,8 +149,7 @@ zs_loadchannelregs(cs)
bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16);
reg = cs->cs_creg; /* current regs */
- *(cs->cs_reg_csr) = ZSM_RESET_ERR; /* XXX: reset error condition */
- ZS_DELAY();
+ zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */
#if 1
/*
@@ -161,17 +160,17 @@ zs_loadchannelregs(cs)
#endif
/* baud clock divisor, stop bits, parity */
- ZS_WRITE(cs, 4, reg[4]);
+ zs_write_reg(cs, 4, reg[4]);
/* misc. TX/RX control bits */
- ZS_WRITE(cs, 10, reg[10]);
+ zs_write_reg(cs, 10, reg[10]);
/* char size, enable (RX/TX) */
- ZS_WRITE(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE);
- ZS_WRITE(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE);
+ zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE);
+ zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE);
/* interrupt enables: TX, TX, STATUS */
- ZS_WRITE(cs, 1, reg[1]);
+ zs_write_reg(cs, 1, reg[1]);
#if 0
/*
@@ -182,27 +181,27 @@ zs_loadchannelregs(cs)
* and they should not be touched thereafter.
*/
/* interrupt vector */
- ZS_WRITE(cs, 2, reg[2]);
+ zs_write_reg(cs, 2, reg[2]);
/* master interrupt control */
- ZS_WRITE(cs, 9, reg[9]);
+ zs_write_reg(cs, 9, reg[9]);
#endif
/* clock mode control */
- ZS_WRITE(cs, 11, reg[11]);
+ zs_write_reg(cs, 11, reg[11]);
/* baud rate (lo/hi) */
- ZS_WRITE(cs, 12, reg[12]);
- ZS_WRITE(cs, 13, reg[13]);
+ zs_write_reg(cs, 12, reg[12]);
+ zs_write_reg(cs, 13, reg[13]);
/* Misc. control bits */
- ZS_WRITE(cs, 14, reg[14]);
+ zs_write_reg(cs, 14, reg[14]);
/* which lines cause status interrupts */
- ZS_WRITE(cs, 15, reg[15]);
+ zs_write_reg(cs, 15, reg[15]);
/* char size, enable (RX/TX)*/
- ZS_WRITE(cs, 3, reg[3]);
- ZS_WRITE(cs, 5, reg[5]);
+ zs_write_reg(cs, 3, reg[3]);
+ zs_write_reg(cs, 5, reg[5]);
}
@@ -224,16 +223,15 @@ zsc_intr_hard(arg)
register struct zsc_softc *zsc = arg;
register struct zs_chanstate *cs_a;
register struct zs_chanstate *cs_b;
- register int rval, soft;
+ register int rval;
register u_char rr3;
cs_a = &zsc->zsc_cs[0];
cs_b = &zsc->zsc_cs[1];
rval = 0;
- soft = 0;
/* Note: only channel A has an RR3 */
- rr3 = ZS_READ(cs_a, 3);
+ rr3 = zs_read_reg(cs_a, 3);
/* Handle receive interrupts first. */
if (rr3 & ZSRR3_IP_A_RX)
@@ -241,33 +239,30 @@ zsc_intr_hard(arg)
if (rr3 & ZSRR3_IP_B_RX)
(*cs_b->cs_ops->zsop_rxint)(cs_b);
+ /* Handle status interrupts (i.e. flow control). */
+ if (rr3 & ZSRR3_IP_A_STAT)
+ (*cs_a->cs_ops->zsop_stint)(cs_a);
+ if (rr3 & ZSRR3_IP_B_STAT)
+ (*cs_b->cs_ops->zsop_stint)(cs_b);
+
/* Handle transmit done interrupts. */
if (rr3 & ZSRR3_IP_A_TX)
(*cs_a->cs_ops->zsop_txint)(cs_a);
if (rr3 & ZSRR3_IP_B_TX)
(*cs_b->cs_ops->zsop_txint)(cs_b);
- /* Handle status interrupts. */
- if (rr3 & ZSRR3_IP_A_STAT)
- (*cs_a->cs_ops->zsop_stint)(cs_a);
- if (rr3 & ZSRR3_IP_B_STAT)
- (*cs_b->cs_ops->zsop_stint)(cs_b);
-
/* Clear interrupt. */
if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) {
- *(cs_a->cs_reg_csr) = ZSWR0_CLR_INTR;
- ZS_DELAY();
+ zs_write_csr(cs_a, ZSWR0_CLR_INTR);
rval |= 1;
}
if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) {
- *(cs_b->cs_reg_csr) = ZSWR0_CLR_INTR;
- ZS_DELAY();
+ zs_write_csr(cs_b, ZSWR0_CLR_INTR);
rval |= 2;
}
- if ((cs_a->cs_softreq) || (cs_b->cs_softreq))
- {
- /* This is a machine-dependent function. */
+ if ((cs_a->cs_softreq) || (cs_b->cs_softreq)) {
+ /* This is a machine-dependent function (or macro). */
zsc_req_softint(zsc);
}
@@ -284,18 +279,19 @@ zsc_intr_soft(arg)
{
register struct zsc_softc *zsc = arg;
register struct zs_chanstate *cs;
- register int req, rval, s, unit;
+ register int rval, unit;
rval = 0;
for (unit = 0; unit < 2; unit++) {
cs = &zsc->zsc_cs[unit];
- s = splzs();
- req = cs->cs_softreq;
- cs->cs_softreq = 0;
- splx(s);
-
- if (req) {
+ /*
+ * The softint flag can be safely cleared once
+ * we have decided to call the softint routine.
+ * (No need to do splzs() first.)
+ */
+ if (cs->cs_softreq) {
+ cs->cs_softreq = 0;
(*cs->cs_ops->zsop_softint)(cs);
rval = 1;
}
@@ -304,15 +300,15 @@ zsc_intr_soft(arg)
}
-static int
+static void
zsnull_intr(cs)
struct zs_chanstate *cs;
{
- ZS_WRITE(cs, 1, 0);
- ZS_WRITE(cs, 15, 0);
+ zs_write_reg(cs, 1, 0);
+ zs_write_reg(cs, 15, 0);
}
-static int
+static void
zsnull_softint(cs)
struct zs_chanstate *cs;
{
diff --git a/sys/dev/ic/z8530sc.h b/sys/dev/ic/z8530sc.h
index 57ec9c4dc91..f271fe46bde 100644
--- a/sys/dev/ic/z8530sc.h
+++ b/sys/dev/ic/z8530sc.h
@@ -1,4 +1,4 @@
-/* $NetBSD: z8530sc.h,v 1.1 1996/01/24 01:07:24 gwr Exp $ */
+/* $NetBSD: z8530sc.h,v 1.2 1996/04/10 21:44:44 gwr Exp $ */
/*
* Copyright (c) 1994 Gordon W. Ross
@@ -50,10 +50,10 @@
* Function vector - per channel
*/
struct zsops {
- int (*zsop_rxint)(); /* receive char available */
- int (*zsop_stint)(); /* external/status */
- int (*zsop_txint)(); /* xmit buffer empty */
- int (*zsop_softint)(); /* process software interrupt */
+ void (*zsop_rxint)(); /* receive char available */
+ void (*zsop_stint)(); /* external/status */
+ void (*zsop_txint)(); /* xmit buffer empty */
+ void (*zsop_softint)(); /* process software interrupt */
};
extern struct zsops zsops_null;
@@ -93,9 +93,9 @@ struct zs_chanstate {
u_char cs_heldchange; /* change pending (creg != preg) */
u_char cs_rr0; /* last rr0 processed */
+ u_char cs_rr0_new; /* rr0 saved in status interrupt. */
char cs_softreq; /* need soft interrupt call */
- char cs__spare;
};
struct zsc_softc {
diff --git a/sys/dev/ic/z8530tty.c b/sys/dev/ic/z8530tty.c
index 577a2845d51..db07810fdf9 100644
--- a/sys/dev/ic/z8530tty.c
+++ b/sys/dev/ic/z8530tty.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: z8530tty.c,v 1.2 1996/04/18 23:47:26 niklas Exp $ */
-/* $NetBSD: z8530tty.c,v 1.1 1996/01/24 01:07:25 gwr Exp $ */
+/* $OpenBSD: z8530tty.c,v 1.3 1996/04/21 22:21:46 deraadt Exp $ */
+/* $NetBSD: z8530tty.c,v 1.6 1996/04/10 21:44:47 gwr Exp $ */
/*
* Copyright (c) 1994 Gordon W. Ross
@@ -60,6 +60,7 @@
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/ioctl.h>
+#include <sys/malloc.h>
#include <sys/tty.h>
#include <sys/time.h>
#include <sys/kernel.h>
@@ -86,9 +87,14 @@ extern int zs_check_kgdb();
* Note: must be a power of two!
*/
#ifndef ZSTTY_RING_SIZE
-#define ZSTTY_RING_SIZE 1024
+#define ZSTTY_RING_SIZE 2048
#endif
-#define ZSTTY_RING_MASK (ZSTTY_RING_SIZE-1)
+
+/*
+ * Make this an option variable one can patch.
+ * But be warned: this must be a power of 2!
+ */
+int zstty_rbuf_size = ZSTTY_RING_SIZE;
struct zstty_softc {
struct device zst_dev; /* required first: base device */
@@ -126,7 +132,8 @@ struct zstty_softc {
*/
u_int zst_rbget; /* ring buffer `get' index */
volatile u_int zst_rbput; /* ring buffer `put' index */
- u_short zst_rbuf[ZSTTY_RING_SIZE]; /* rr1, data pairs */
+ u_int zst_ringmask;
+ u_short *zst_rbuf; /* rr1, data pairs */
};
@@ -134,9 +141,12 @@ struct zstty_softc {
static int zstty_match(struct device *, void *, void *);
static void zstty_attach(struct device *, struct device *, void *);
-struct cfdriver zsttycd = {
- NULL, "zstty", zstty_match, zstty_attach,
- DV_TTY, sizeof(struct zstty_softc), NULL,
+struct cfattach zstty_ca = {
+ sizeof(struct zstty_softc), zstty_match, zstty_attach
+};
+
+struct cfdriver zstty_cd = {
+ NULL, "zstty", DV_TTY
};
struct zsops zsops_tty;
@@ -221,11 +231,16 @@ zstty_attach(parent, self, aux)
}
printf("\n");
- tp = zst->zst_tty = ttymalloc();
+ tp = ttymalloc();
tp->t_dev = dev;
tp->t_oproc = zsstart;
tp->t_param = zsparam;
+ zst->zst_tty = tp;
+ zst->zst_ringmask = zstty_rbuf_size - 1;
+ zst->zst_rbuf = malloc(zstty_rbuf_size * sizeof(zst->zst_rbuf[0]),
+ M_DEVBUF, M_WAITOK);
+
/*
* Hardware init
*/
@@ -244,7 +259,7 @@ zstty_attach(parent, self, aux)
reset = (channel == 0) ?
ZSWR9_A_RESET : ZSWR9_B_RESET;
s = splzs();
- ZS_WRITE(cs, 9, reset);
+ zs_write_reg(cs, 9, reset);
splx(s);
}
@@ -269,10 +284,10 @@ zstty(dev)
int unit = minor(dev);
#ifdef DIAGNOSTIC
- if (unit >= zsttycd.cd_ndevs)
+ if (unit >= zstty_cd.cd_ndevs)
panic("zstty");
#endif
- zst = zsttycd.cd_devs[unit];
+ zst = zstty_cd.cd_devs[unit];
return (zst->zst_tty);
}
@@ -293,9 +308,9 @@ zsopen(dev, flags, mode, p)
int error, s, unit;
unit = minor(dev);
- if (unit >= zsttycd.cd_ndevs)
+ if (unit >= zstty_cd.cd_ndevs)
return (ENXIO);
- zst = zsttycd.cd_devs[unit];
+ zst = zstty_cd.cd_devs[unit];
if (zst == NULL)
return (ENXIO);
tp = zst->zst_tty;
@@ -344,12 +359,10 @@ zsopen(dev, flags, mode, p)
/* Wait for carrier. */
for (;;) {
- register int rr0;
/* Might never get status intr if carrier already on. */
- rr0 = *(cs->cs_reg_csr);
- ZS_DELAY();
- if (rr0 & ZSRR0_DCD) {
+ cs->cs_rr0 = zs_read_csr(cs);
+ if (cs->cs_rr0 & ZSRR0_DCD) {
tp->t_state |= TS_CARR_ON;
break;
}
@@ -399,7 +412,7 @@ zsclose(dev, flags, mode, p)
struct zsinfo *zi;
int hup, s;
- zst = zsttycd.cd_devs[minor(dev)];
+ zst = zstty_cd.cd_devs[minor(dev)];
cs = zst->zst_cs;
tp = zst->zst_tty;
@@ -437,7 +450,7 @@ zsread(dev, uio, flags)
register struct zstty_softc *zst;
register struct tty *tp;
- zst = zsttycd.cd_devs[minor(dev)];
+ zst = zstty_cd.cd_devs[minor(dev)];
tp = zst->zst_tty;
return (linesw[tp->t_line].l_read(tp, uio, flags));
}
@@ -451,7 +464,7 @@ zswrite(dev, uio, flags)
register struct zstty_softc *zst;
register struct tty *tp;
- zst = zsttycd.cd_devs[minor(dev)];
+ zst = zstty_cd.cd_devs[minor(dev)];
tp = zst->zst_tty;
return (linesw[tp->t_line].l_write(tp, uio, flags));
}
@@ -472,7 +485,7 @@ zsioctl(dev, cmd, data, flag, p)
register struct tty *tp;
register int error, tmp;
- zst = zsttycd.cd_devs[minor(dev)];
+ zst = zstty_cd.cd_devs[minor(dev)];
cs = zst->zst_cs;
tp = zst->zst_tty;
@@ -541,7 +554,7 @@ zsstart(tp)
register struct zs_chanstate *cs;
register int s, nch;
- zst = zsttycd.cd_devs[minor(tp->t_dev)];
+ zst = zstty_cd.cd_devs[minor(tp->t_dev)];
cs = zst->zst_cs;
s = spltty();
@@ -574,9 +587,8 @@ zsstart(tp)
cs->cs_preg[1] |= ZSWR1_TIE;
cs->cs_creg[1] |= ZSWR1_TIE;
- ZS_WRITE(cs, 1, cs->cs_creg[1]);
- *(cs->cs_reg_data) = *p;
- ZS_DELAY();
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ zs_write_data(cs, *p);
zst->zst_tba = p + 1;
zst->zst_tbc = nch - 1;
} else {
@@ -587,7 +599,7 @@ zsstart(tp)
(void) splzs();
cs->cs_preg[1] &= ~ZSWR1_TIE;
cs->cs_creg[1] &= ~ZSWR1_TIE;
- ZS_WRITE(cs, 1, cs->cs_creg[1]);
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
}
out:
splx(s);
@@ -605,7 +617,7 @@ zsstop(tp, flag)
register struct zs_chanstate *cs;
register int s;
- zst = zsttycd.cd_devs[minor(tp->t_dev)];
+ zst = zstty_cd.cd_devs[minor(tp->t_dev)];
cs = zst->zst_cs;
s = splzs();
@@ -637,7 +649,7 @@ zsparam(tp, t)
register int s, bps, cflag, tconst;
u_char tmp3, tmp4, tmp5, reset;
- zst = zsttycd.cd_devs[minor(tp->t_dev)];
+ zst = zstty_cd.cd_devs[minor(tp->t_dev)];
cs = zst->zst_cs;
/*
@@ -709,9 +721,8 @@ zsparam(tp, t)
*/
tmp3 |= ZSWR3_RX_ENABLE;
if (cflag & CCTS_OFLOW) {
- if (*(cs->cs_reg_csr) & ZSRR0_DCD)
+ if (zs_read_csr(cs) & ZSRR0_DCD)
tmp3 |= ZSWR3_HFC;
- ZS_DELAY();
}
cs->cs_preg[3] = tmp3;
@@ -773,7 +784,7 @@ zs_modem(zst, onoff)
cs->cs_heldchange = 1;
} else {
cs->cs_creg[5] = (cs->cs_creg[5] | bis) & and;
- ZS_WRITE(cs, 5, cs->cs_creg[5]);
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
}
}
splx(s);
@@ -788,33 +799,37 @@ zs_modem(zst, onoff)
* XXX: need to do input flow-control to avoid ring overrun.
*/
-static int
+/*
+ * receiver ready interrupt. (splzs)
+ */
+static void
zstty_rxint(cs)
register struct zs_chanstate *cs;
{
register struct zstty_softc *zst;
- register put, put_next;
+ register put, put_next, ringmask;
register u_char c, rr0, rr1;
zst = cs->cs_private;
put = zst->zst_rbput;
+ ringmask = zst->zst_ringmask;
nextchar:
- /* Read the input data ASAP. */
- c = *(cs->cs_reg_data);
- ZS_DELAY();
- /* Save the status register too. */
- rr1 = ZS_READ(cs, 1);
+ /*
+ * 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 (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
/* Clear the receive error. */
- *(cs->cs_reg_csr) = ZSWR0_RESET_ERRORS;
- ZS_DELAY();
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
}
zst->zst_rbuf[put] = (c << 8) | rr1;
- put_next = (put + 1) & ZSTTY_RING_MASK;
+ put_next = (put + 1) & ringmask;
/* Would overrun if increment makes (put==get). */
if (put_next == zst->zst_rbget) {
@@ -825,8 +840,7 @@ nextchar:
}
/* Keep reading until the FIFO is empty. */
- rr0 = *(cs->cs_reg_csr);
- ZS_DELAY();
+ rr0 = zs_read_csr(cs);
if (rr0 & ZSRR0_RX_READY)
goto nextchar;
@@ -835,63 +849,93 @@ nextchar:
/* Ask for softint() call. */
cs->cs_softreq = 1;
- return(1);
}
-static int
+/*
+ * transmitter ready interrupt. (splzs)
+ */
+static void
zstty_txint(cs)
register struct zs_chanstate *cs;
{
register struct zstty_softc *zst;
- register int count, rval;
+ register int count;
zst = cs->cs_private;
count = zst->zst_tbc;
+ /*
+ * If our transmit buffer still has data,
+ * just send the next character.
+ */
if (count > 0) {
/* Send the next char. */
- *(cs->cs_reg_data) = *zst->zst_tba++;
- ZS_DELAY();
zst->zst_tbc = --count;
- rval = 0;
- } else {
- /* Nothing more to send. */
- *(cs->cs_reg_csr) = ZSWR0_RESET_TXINT;
- ZS_DELAY();
- zst->zst_intr_flags |= INTR_TX_EMPTY;
- rval = 1; /* want softcall */
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tba++;
+ return;
}
- cs->cs_softreq = rval;
- return (rval);
+ zs_write_csr(cs, ZSWR0_RESET_TXINT);
+
+ /* Ask the softint routine for more output. */
+ zst->zst_intr_flags |= INTR_TX_EMPTY;
+ cs->cs_softreq = 1;
}
-static int
+/*
+ * status change interrupt. (splzs)
+ */
+static void
zstty_stint(cs)
register struct zs_chanstate *cs;
{
register struct zstty_softc *zst;
- register int rr0;
+ register struct tty *tp;
+ register u_char rr0;
zst = cs->cs_private;
+ tp = zst->zst_tty;
- rr0 = *(cs->cs_reg_csr);
- ZS_DELAY();
+ rr0 = zs_read_csr(cs);
+ zs_write_csr(cs, ZSWR0_RESET_STATUS);
- *(cs->cs_reg_csr) = ZSWR0_RESET_STATUS;
- ZS_DELAY();
+ /*
+ * The chip's hardware flow control is, as noted in zsreg.h,
+ * busted---if the DCD line goes low the chip shuts off the
+ * receiver (!). If we want hardware CTS flow control but do
+ * not have it, and carrier is now on, turn HFC on; if we have
+ * HFC now but carrier has gone low, turn it off.
+ */
+ if (rr0 & ZSRR0_DCD) {
+ if (tp->t_cflag & CCTS_OFLOW &&
+ (cs->cs_creg[3] & ZSWR3_HFC) == 0) {
+ cs->cs_creg[3] |= ZSWR3_HFC;
+ zs_write_reg(cs, 3, cs->cs_creg[3]);
+ }
+ } else {
+ if (cs->cs_creg[3] & ZSWR3_HFC) {
+ cs->cs_creg[3] &= ~ZSWR3_HFC;
+ zs_write_reg(cs, 3, cs->cs_creg[3]);
+ }
+ }
- if ((rr0 & ZSRR0_BREAK) &&
+ /*
+ * Check here for console break, so that we can abort
+ * even when interrupts are locking up the machine.
+ */
+ if ((rr0 & ZSRR0_BREAK) &&
(zst->zst_hwflags & ZS_HWFLAG_CONSOLE))
{
zs_abort();
- return (0);
+ return;
}
+ cs->cs_rr0_new = rr0;
zst->zst_intr_flags |= INTR_ST_CHECK;
+
/* Ask for softint() call. */
cs->cs_softreq = 1;
- return (1);
}
/*
@@ -911,7 +955,10 @@ zsoverrun(zst, ptime, what)
}
}
-static int
+/*
+ * Software interrupt. Called at zssoft
+ */
+static void
zstty_softint(cs)
struct zs_chanstate *cs;
{
@@ -919,24 +966,29 @@ zstty_softint(cs)
register struct linesw *line;
register struct tty *tp;
register int get, c, s;
- int intr_flags;
+ int intr_flags, ringmask;
register u_short ring_data;
register u_char rr0, rr1;
zst = cs->cs_private;
tp = zst->zst_tty;
line = &linesw[tp->t_line];
+ ringmask = zst->zst_ringmask;
/* Atomically get and clear flags. */
s = splzs();
intr_flags = zst->zst_intr_flags;
zst->zst_intr_flags = 0;
- splx(s);
+
+ /*
+ * Lower to tty priority while servicing the ring.
+ */
+ (void) spltty();
if (intr_flags & INTR_RX_OVERRUN) {
/* May turn this on again below. */
intr_flags &= ~INTR_RX_OVERRUN;
- zsoverrun(zst, "ring");
+ zsoverrun(zst, &zst->zst_rotime, "ring");
}
/*
@@ -945,7 +997,7 @@ zstty_softint(cs)
get = zst->zst_rbget;
while (get != zst->zst_rbput) {
ring_data = zst->zst_rbuf[get];
- get = (get + 1) & ZSTTY_RING_MASK;
+ get = (get + 1) & ringmask;
if (ring_data & ZSRR1_DO)
intr_flags |= INTR_RX_OVERRUN;
@@ -960,32 +1012,36 @@ zstty_softint(cs)
}
zst->zst_rbget = get;
- /* If set, it is from the loop above. */
+ /*
+ * If the overrun flag is set now, it was set while
+ * copying char/status pairs from the ring, which
+ * means this was a hardware (fifo) overrun.
+ */
if (intr_flags & INTR_RX_OVERRUN) {
- zsoverrun(zst, "fifo");
+ zsoverrun(zst, &zst->zst_fotime, "fifo");
}
if (intr_flags & INTR_TX_EMPTY) {
/*
- * Transmit done. Change registers and resume,
- * or just clear BUSY.
+ * The transmitter output buffer count is zero.
+ * If we suspended output for a "held" change,
+ * then handle that now and resume. Otherwise,
+ * try to start a new output chunk.
*/
if (cs->cs_heldchange) {
- s = splzs();
- rr0 = *(cs->cs_reg_csr);
- ZS_DELAY();
+ (void) splzs();
+ rr0 = zs_read_csr(cs);
if ((rr0 & ZSRR0_DCD) == 0)
cs->cs_preg[3] &= ~ZSWR3_HFC;
zs_loadchannelregs(cs);
- splx(s);
+ (void) spltty();
cs->cs_heldchange = 0;
-
if (zst->zst_heldtbc &&
(tp->t_state & TS_TTSTOP) == 0)
{
zst->zst_tbc = zst->zst_heldtbc - 1;
- *(cs->cs_reg_data) = *zst->zst_tba++;
- ZS_DELAY();
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tba++;
goto tx_resumed;
}
}
@@ -1001,31 +1057,11 @@ zstty_softint(cs)
if (intr_flags & INTR_ST_CHECK) {
/*
- * Status line change.
- *
- * The chip's hardware flow control is, as noted in zsreg.h,
- * busted---if the DCD line goes low the chip shuts off the
- * receiver (!). If we want hardware CTS flow control but do
- * not have it, and carrier is now on, turn HFC on; if we have
- * HFC now but carrier has gone low, turn it off.
+ * Status line change. HFC bit is run in
+ * hardware interrupt, to avoid locking
+ * at splzs here.
*/
- s = splzs();
- rr0 = *(cs->cs_reg_csr);
- if (rr0 & ZSRR0_DCD) {
- if (tp->t_cflag & CCTS_OFLOW &&
- (cs->cs_creg[3] & ZSWR3_HFC) == 0) {
- cs->cs_creg[3] |= ZSWR3_HFC;
- ZS_WRITE(cs, 3, cs->cs_creg[3]);
- }
- } else {
- if (cs->cs_creg[3] & ZSWR3_HFC) {
- cs->cs_creg[3] &= ~ZSWR3_HFC;
- ZS_WRITE(cs, 3, cs->cs_creg[3]);
- }
- }
- splx(s);
-
- /* Was there a change on DCD? */
+ rr0 = cs->cs_rr0_new;
if ((rr0 ^ cs->cs_rr0) & ZSRR0_DCD) {
c = ((rr0 & ZSRR0_DCD) != 0);
if (line->l_modem(tp, c) == 0)
@@ -1034,7 +1070,7 @@ zstty_softint(cs)
cs->cs_rr0 = rr0;
}
- return (1);
+ splx(s);
}
struct zsops zsops_tty = {
@@ -1043,3 +1079,4 @@ struct zsops zsops_tty = {
zstty_txint, /* xmit buffer empty */
zstty_softint, /* process software interrupt */
};
+