summaryrefslogtreecommitdiff
path: root/sys/arch/mac68k
diff options
context:
space:
mode:
authorbriggs <briggs@cvs.openbsd.org>1996-05-26 19:02:15 +0000
committerbriggs <briggs@cvs.openbsd.org>1996-05-26 19:02:15 +0000
commit4e2e9714c65149d74c0d51f529869cbb80f91351 (patch)
tree6739b24d2cf272fa63690366f755421c3246eab6 /sys/arch/mac68k
parent4d20277b0fb5051e3e3ee1ced5ba6ebb190ad69f (diff)
Missed a few files in the previous updates.
Diffstat (limited to 'sys/arch/mac68k')
-rw-r--r--sys/arch/mac68k/dev/ascvar.h36
-rw-r--r--sys/arch/mac68k/dev/grf_subr.c85
-rw-r--r--sys/arch/mac68k/dev/itevar.h55
-rw-r--r--sys/arch/mac68k/dev/ncr5380var.h79
-rw-r--r--sys/arch/mac68k/dev/obio.c74
-rw-r--r--sys/arch/mac68k/dev/sbc.c1087
-rw-r--r--sys/arch/mac68k/dev/sbcreg.h28
-rw-r--r--sys/arch/mac68k/dev/z8530sc.c396
-rw-r--r--sys/arch/mac68k/dev/z8530sc.h174
-rw-r--r--sys/arch/mac68k/dev/z8530tty.c1433
-rw-r--r--sys/arch/mac68k/dev/z8530tty.h143
-rw-r--r--sys/arch/mac68k/dev/zs.c752
12 files changed, 4342 insertions, 0 deletions
diff --git a/sys/arch/mac68k/dev/ascvar.h b/sys/arch/mac68k/dev/ascvar.h
new file mode 100644
index 00000000000..4863e392a9b
--- /dev/null
+++ b/sys/arch/mac68k/dev/ascvar.h
@@ -0,0 +1,36 @@
+/* $OpenBSD: ascvar.h,v 1.1 1996/05/26 19:02:05 briggs Exp $ */
+/* $NetBSD: ascvar.h,v 1.1 1996/05/05 06:16:28 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Allen Briggs. 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 Allen Briggs.
+ * 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.
+ */
+
+int asc_setbellparams __P((int freq, int length, int volume));
+int asc_getbellparams __P((int *freq, int *length, int *volume));
+void asc_bellstop __P((int param));
+int asc_ringbell __P((void));
diff --git a/sys/arch/mac68k/dev/grf_subr.c b/sys/arch/mac68k/dev/grf_subr.c
new file mode 100644
index 00000000000..872a41eaca5
--- /dev/null
+++ b/sys/arch/mac68k/dev/grf_subr.c
@@ -0,0 +1,85 @@
+/* $OpenBSD: grf_subr.c,v 1.1 1996/05/26 19:02:06 briggs Exp $ */
+/* $NetBSD: grf_subr.c,v 1.1 1996/05/19 22:27:08 scottr Exp $ */
+
+/*-
+ * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+
+#include <machine/grfioctl.h>
+
+#include <mac68k/dev/nubus.h>
+#include <mac68k/dev/grfvar.h>
+
+void
+grf_establish(sc, g_mode, g_phys)
+ struct grfbus_softc *sc;
+ int (*g_mode) __P((struct grf_softc *, int, void *));
+ caddr_t (*g_phys) __P((struct grf_softc *, vm_offset_t));
+{
+ struct grfmode *gm = &sc->curr_mode;
+ struct grfbus_attach_args ga;
+
+ /* Print hardware characteristics. */
+ printf("%s: %d x %d, ", sc->sc_dev.dv_xname, gm->width, gm->height);
+ if (gm->psize == 1)
+ printf("monochrome\n");
+ else
+ printf("%d color\n", 1 << gm->psize);
+
+ /* Attach grf semantics to the hardware. */
+ ga.ga_name = "grf";
+ ga.ga_grfmode = gm;
+ ga.ga_slot = &sc->sc_slot; /* XXX */
+ ga.ga_mode = g_mode;
+ ga.ga_phys = g_phys;
+ (void)config_found(&sc->sc_dev, &ga, grfbusprint);
+}
+
+int
+grfbusprint(aux, name)
+ void *aux;
+ char *name;
+{
+ struct grfbus_attach_args *ga = aux;
+
+ if (name)
+ printf("%s at %s", ga->ga_name, name);
+
+ return (UNCONF);
+}
diff --git a/sys/arch/mac68k/dev/itevar.h b/sys/arch/mac68k/dev/itevar.h
new file mode 100644
index 00000000000..b6faa91b098
--- /dev/null
+++ b/sys/arch/mac68k/dev/itevar.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: itevar.h,v 1.1 1996/05/26 19:02:07 briggs Exp $ */
+/* $NetBSD: itevar.h,v 1.1 1996/05/05 06:16:49 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Allen Briggs. 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 Allen Briggs.
+ * 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.
+ */
+
+#include <machine/adbsys.h>
+
+int ite_intr __P((adb_event_t *event));
+int iteon __P((dev_t dev, int flags));
+int iteoff __P((dev_t dev, int flags));
+
+#ifndef CN_DEAD
+#include <dev/cons.h>
+#endif
+
+void itestop __P((struct tty * tp, int flag));
+void itestart __P((register struct tty * tp));
+int iteopen __P((dev_t dev, int mode, int devtype, struct proc * p));
+int iteclose __P((dev_t dev, int flag, int mode, struct proc * p));
+int iteread __P((dev_t dev, struct uio * uio, int flag));
+int itewrite __P((dev_t dev, struct uio * uio, int flag));
+int iteioctl __P((dev_t, int, caddr_t, int, struct proc *));
+struct tty *itetty __P((dev_t dev));
+
+int itecnprobe __P((struct consdev * cp));
+int itecninit __P((struct consdev * cp));
+int itecngetc __P((dev_t dev));
+int itecnputc __P((dev_t dev, int c));
diff --git a/sys/arch/mac68k/dev/ncr5380var.h b/sys/arch/mac68k/dev/ncr5380var.h
new file mode 100644
index 00000000000..3be2849859a
--- /dev/null
+++ b/sys/arch/mac68k/dev/ncr5380var.h
@@ -0,0 +1,79 @@
+/* $OpenBSD: ncr5380var.h,v 1.1 1996/05/26 19:02:08 briggs Exp $ */
+/* $NetBSD: ncr5380var.h,v 1.2 1996/05/25 16:42:31 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Allen Briggs. 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 Allen Briggs.
+ * 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.
+ */
+
+static volatile u_char *scsi_enable = NULL;
+static volatile u_char *scsi_flag = NULL;
+
+static __inline__ void
+scsi_clear_drq __P((void))
+{
+ int s;
+
+ s = splhigh();
+ *scsi_flag = 0x80 | V2IF_SCSIDRQ;
+ splx(s);
+}
+
+static __inline__ void
+scsi_clear_irq __P((void))
+{
+ int s;
+
+ s = splhigh();
+ *scsi_flag = 0x80 | V2IF_SCSIIRQ;
+ splx(s);
+}
+
+static __inline__ void
+scsi_ienable __P((void))
+{
+ int s;
+
+ s = splhigh();
+ *scsi_enable = 0x80 | (V2IF_SCSIIRQ | V2IF_SCSIDRQ);
+ splx(s);
+}
+
+static __inline__ void
+scsi_idisable __P((void))
+{
+ int s;
+
+ s = splhigh();
+ *scsi_enable = V2IF_SCSIIRQ | V2IF_SCSIDRQ;
+ splx(s);
+}
+
+void pdma_stat __P((void));
+void pdma_cleanup __P((void));
+void scsi_show __P((void));
+
diff --git a/sys/arch/mac68k/dev/obio.c b/sys/arch/mac68k/dev/obio.c
new file mode 100644
index 00000000000..5603bae9537
--- /dev/null
+++ b/sys/arch/mac68k/dev/obio.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: obio.c,v 1.1 1996/05/26 19:02:08 briggs Exp $ */
+/* $NetBSD: obio.c,v 1.1 1996/05/05 06:17:07 briggs Exp $ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1993 Adam Glass
+ * 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 Adam Glass and Gordon Ross.
+ * 4. The name of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/autoconf.h>
+#include <machine/pte.h>
+
+static int obio_match __P((struct device *, void *, void *));
+static void obio_attach __P((struct device *, struct device *, void *));
+
+struct cfattach obio_ca = {
+ sizeof(struct device), obio_match, obio_attach
+};
+
+struct cfdriver obio_cd = {
+ NULL, "obio", DV_DULL
+};
+
+static int
+obio_match(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct confargs *ca = aux;
+
+ if (ca->ca_bustype != BUS_OBIO)
+ return (0);
+ return(1);
+}
+
+static void
+obio_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ printf("\n");
+
+ (void) config_search(bus_scan, self, aux);
+}
diff --git a/sys/arch/mac68k/dev/sbc.c b/sys/arch/mac68k/dev/sbc.c
new file mode 100644
index 00000000000..b46460122dd
--- /dev/null
+++ b/sys/arch/mac68k/dev/sbc.c
@@ -0,0 +1,1087 @@
+/* $OpenBSD: sbc.c,v 1.1 1996/05/26 19:02:09 briggs Exp $ */
+/* $NetBSD: sbc.c,v 1.6 1996/05/08 03:44:56 scottr Exp $ */
+
+/*
+ * Copyright (c) 1996 Scott Reynolds
+ * Copyright (c) 1995 David Jones
+ * Copyright (c) 1995 Allen Briggs
+ * 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. The name of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by David Jones, Allen
+ * Briggs and Scott Reynolds.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.
+ */
+
+/*
+ * This file contains only the machine-dependent parts of the mac68k
+ * NCR 5380 SCSI driver. (Autoconfig stuff and PDMA functions.)
+ * The machine-independent parts are in ncr5380sbc.c
+ *
+ * Supported hardware includes:
+ * Macintosh II family 5380-based controller
+ *
+ * Credits, history:
+ *
+ * Scott Reynolds wrote this module, based on work by Allen Briggs
+ * (mac68k), David Jones (sun3), and Leo Weppelman (atari). Allen
+ * supplied some crucial interpretation of the NetBSD 1.1 'ncrscsi'
+ * driver. Allen, Gordon W. Ross, and Jason Thorpe all helped to
+ * refine this code, and were considerable sources of moral support.
+ *
+ * The sbc_options code is based on similar code in Jason's modified
+ * NetBSD/sparc 'si' driver.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_debug.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/ncr5380reg.h>
+#include <dev/ic/ncr5380var.h>
+
+#include <machine/viareg.h>
+
+#include "sbcreg.h"
+
+/*
+ * Transfers smaller than this are done using PIO
+ * (on assumption they're not worth PDMA overhead)
+ */
+#define MIN_DMA_LEN 128
+
+/*
+ * Transfers larger than 8192 bytes need to be split up
+ * due to the size of the PDMA space.
+ */
+#define MAX_DMA_LEN 0x2000
+
+/*
+ * From Guide to the Macintosh Family Hardware, p. 137
+ * These are offsets from SCSIBase (see pmap_bootstrap.c)
+ */
+#define SBC_REGISTER_OFFSET 0x10000
+#define SBC_DMA_DRQ_OFFSET 0x06000
+#define SBC_DMA_NODRQ_OFFSET 0x12000
+
+#ifdef SBC_DEBUG
+# define SBC_DB_INTR 0x01
+# define SBC_DB_DMA 0x02
+# define SBC_DB_REG 0x04
+# define SBC_DB_BREAK 0x08
+
+ int sbc_debug = 0 /* | SBC_DB_INTR | SBC_DB_DMA */;
+ int sbc_link_flags = 0 /* | SDEV_DB2 */;
+
+# ifndef DDB
+# define Debugger() printf("Debug: sbc.c:%d\n", __LINE__)
+# endif
+# define SBC_BREAK \
+ do { if (sbc_debug & SBC_DB_BREAK) Debugger(); } while (0)
+#else
+# define SBC_BREAK
+#endif
+
+/*
+ * This structure is used to keep track of PDMA requests.
+ */
+struct sbc_pdma_handle {
+ int dh_flags; /* flags */
+#define SBC_DH_BUSY 0x01 /* This handle is in use */
+#define SBC_DH_OUT 0x02 /* PDMA data out (write) */
+ u_char *dh_addr; /* data buffer */
+ int dh_len; /* length of data buffer */
+};
+
+/*
+ * The first structure member has to be the ncr5380_softc
+ * so we can just cast to go back and forth between them.
+ */
+struct sbc_softc {
+ struct ncr5380_softc ncr_sc;
+ volatile struct sbc_regs *sc_regs;
+ volatile long *sc_drq_addr;
+ volatile u_char *sc_nodrq_addr;
+ volatile u_char *sc_ienable;
+ volatile u_char *sc_iflag;
+ int sc_options; /* options for this instance. */
+ struct sbc_pdma_handle sc_pdma[SCI_OPENINGS];
+};
+
+/*
+ * Options. By default, SCSI interrupts and reselect are disabled.
+ * You may enable either of these features with the `flags' directive
+ * in your kernel's configuration file.
+ *
+ * Alternatively, you can patch your kernel with DDB or some other
+ * mechanism. The sc_options member of the softc is OR'd with
+ * the value in sbc_options.
+ */
+#define SBC_PDMA 0x01 /* Use PDMA for polled transfers */
+#define SBC_INTR 0x02 /* Allow SCSI IRQ/DRQ interrupts */
+#define SBC_RESELECT 0x04 /* Allow disconnect/reselect */
+#define SBC_OPTIONS_MASK (SBC_RESELECT|SBC_INTR|SBC_PDMA)
+#define SBC_OPTIONS_BITS "\10\3RESELECT\2INTR\1PDMA"
+int sbc_options = SBC_PDMA;
+
+static int sbc_match __P((struct device *, void *, void *));
+static void sbc_attach __P((struct device *, struct device *, void *));
+static int sbc_print __P((void *, char *));
+static void sbc_minphys __P((struct buf *bp));
+
+static int sbc_wait_busy __P((struct ncr5380_softc *));
+static int sbc_ready __P((struct ncr5380_softc *));
+static int sbc_wait_dreq __P((struct ncr5380_softc *));
+static int sbc_pdma_in __P((struct ncr5380_softc *, int, int, u_char *));
+static int sbc_pdma_out __P((struct ncr5380_softc *, int, int, u_char *));
+#ifdef SBC_DEBUG
+static void decode_5380_intr __P((struct ncr5380_softc *));
+#endif
+
+ void sbc_intr_enable __P((struct ncr5380_softc *));
+ void sbc_intr_disable __P((struct ncr5380_softc *));
+ void sbc_irq_intr __P((void *));
+ void sbc_drq_intr __P((void *));
+ void sbc_dma_alloc __P((struct ncr5380_softc *));
+ void sbc_dma_free __P((struct ncr5380_softc *));
+ void sbc_dma_poll __P((struct ncr5380_softc *));
+ void sbc_dma_setup __P((struct ncr5380_softc *));
+ void sbc_dma_start __P((struct ncr5380_softc *));
+ void sbc_dma_eop __P((struct ncr5380_softc *));
+ void sbc_dma_stop __P((struct ncr5380_softc *));
+
+static struct scsi_adapter sbc_ops = {
+ ncr5380_scsi_cmd, /* scsi_cmd() */
+ sbc_minphys, /* scsi_minphys() */
+ NULL, /* open_target_lu() */
+ NULL, /* close_target_lu() */
+};
+
+/* This is copied from julian's bt driver */
+/* "so we have a default dev struct for our link struct." */
+static struct scsi_device sbc_dev = {
+ NULL, /* Use default error handler. */
+ NULL, /* Use default start handler. */
+ NULL, /* Use default async handler. */
+ NULL, /* Use default "done" routine. */
+};
+
+struct cfattach sbc_ca = {
+ sizeof(struct sbc_softc), sbc_match, sbc_attach
+};
+
+struct cfdriver sbc_cd = {
+ NULL, "sbc", DV_DULL
+};
+
+
+static int
+sbc_match(parent, match, args)
+ struct device *parent;
+ void *match, *args;
+{
+ if (!mac68k_machine.scsi80)
+ return 0;
+ return 1;
+}
+
+static void
+sbc_attach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct sbc_softc *sc = (struct sbc_softc *) self;
+ struct ncr5380_softc *ncr_sc = (struct ncr5380_softc *) sc;
+ extern vm_offset_t SCSIBase;
+
+ /* Pull in the options flags. */
+ sc->sc_options = ((ncr_sc->sc_dev.dv_cfdata->cf_flags | sbc_options)
+ & SBC_OPTIONS_MASK);
+
+ /*
+ * Set up base address of 5380
+ */
+ sc->sc_regs = (struct sbc_regs *)(SCSIBase + SBC_REGISTER_OFFSET);
+
+ /*
+ * Fill in the prototype scsi_link.
+ */
+ ncr_sc->sc_link.adapter_softc = sc;
+ ncr_sc->sc_link.adapter_target = 7;
+ ncr_sc->sc_link.adapter = &sbc_ops;
+ ncr_sc->sc_link.device = &sbc_dev;
+
+ /*
+ * Initialize fields used by the MI code
+ */
+ ncr_sc->sci_r0 = &sc->sc_regs->sci_pr0.sci_reg;
+ ncr_sc->sci_r1 = &sc->sc_regs->sci_pr1.sci_reg;
+ ncr_sc->sci_r2 = &sc->sc_regs->sci_pr2.sci_reg;
+ ncr_sc->sci_r3 = &sc->sc_regs->sci_pr3.sci_reg;
+ ncr_sc->sci_r4 = &sc->sc_regs->sci_pr4.sci_reg;
+ ncr_sc->sci_r5 = &sc->sc_regs->sci_pr5.sci_reg;
+ ncr_sc->sci_r6 = &sc->sc_regs->sci_pr6.sci_reg;
+ ncr_sc->sci_r7 = &sc->sc_regs->sci_pr7.sci_reg;
+
+ /*
+ * MD function pointers used by the MI code.
+ */
+ ncr_sc->sc_pio_out = sbc_pdma_out;
+ ncr_sc->sc_pio_in = sbc_pdma_in;
+ ncr_sc->sc_dma_alloc = NULL;
+ ncr_sc->sc_dma_free = NULL;
+ ncr_sc->sc_dma_poll = NULL;
+ ncr_sc->sc_intr_on = NULL;
+ ncr_sc->sc_intr_off = NULL;
+ ncr_sc->sc_dma_setup = NULL;
+ ncr_sc->sc_dma_start = NULL;
+ ncr_sc->sc_dma_eop = NULL;
+ ncr_sc->sc_dma_stop = NULL;
+ ncr_sc->sc_flags = 0;
+ ncr_sc->sc_min_dma_len = MIN_DMA_LEN;
+
+ if ((sc->sc_options & SBC_INTR) == 0) {
+ ncr_sc->sc_flags |= NCR5380_FORCE_POLLING;
+ } else {
+ if (sc->sc_options & SBC_RESELECT)
+ ncr_sc->sc_flags |= NCR5380_PERMIT_RESELECT;
+ ncr_sc->sc_dma_alloc = sbc_dma_alloc;
+ ncr_sc->sc_dma_free = sbc_dma_free;
+ ncr_sc->sc_dma_poll = sbc_dma_poll;
+ ncr_sc->sc_dma_setup = sbc_dma_setup;
+ ncr_sc->sc_dma_start = sbc_dma_start;
+ ncr_sc->sc_dma_eop = sbc_dma_eop;
+ ncr_sc->sc_dma_stop = sbc_dma_stop;
+ mac68k_register_scsi_drq(sbc_drq_intr, ncr_sc);
+ mac68k_register_scsi_irq(sbc_irq_intr, ncr_sc);
+ }
+
+ /*
+ * Initialize fields used only here in the MD code.
+ */
+ sc->sc_drq_addr = (long *) (SCSIBase + SBC_DMA_DRQ_OFFSET);
+ sc->sc_nodrq_addr = (u_char *) (SCSIBase + SBC_DMA_NODRQ_OFFSET);
+ if (VIA2 == VIA2OFF) {
+ sc->sc_ienable = Via1Base + VIA2 * 0x2000 + vIER;
+ sc->sc_iflag = Via1Base + VIA2 * 0x2000 + vIFR;
+ } else {
+ sc->sc_ienable = Via1Base + VIA2 * 0x2000 + rIER;
+ sc->sc_iflag = Via1Base + VIA2 * 0x2000 + rIFR;
+ }
+
+ if (sc->sc_options)
+ printf(": options=%b", sc->sc_options, SBC_OPTIONS_BITS);
+ printf("\n");
+
+ /* Now enable SCSI interrupts through VIA2, if appropriate */
+ if (sc->sc_options & SBC_INTR)
+ sbc_intr_enable(ncr_sc);
+
+#ifdef SBC_DEBUG
+ if (sbc_debug)
+ printf("%s: softc=%p regs=%p\n", ncr_sc->sc_dev.dv_xname,
+ sc, sc->sc_regs);
+ ncr_sc->sc_link.flags |= sbc_link_flags;
+#endif
+
+ /*
+ * Initialize the SCSI controller itself.
+ */
+ ncr5380_init(ncr_sc);
+ ncr5380_reset_scsibus(ncr_sc);
+ config_found(self, &(ncr_sc->sc_link), sbc_print);
+}
+
+static int
+sbc_print(aux, name)
+ void *aux;
+ char *name;
+{
+ if (name != NULL)
+ printf("%s: scsibus ", name);
+ return UNCONF;
+}
+
+static void
+sbc_minphys(struct buf *bp)
+{
+ if (bp->b_bcount > MAX_DMA_LEN)
+ bp->b_bcount = MAX_DMA_LEN;
+ return (minphys(bp));
+}
+
+
+/***
+ * General support for Mac-specific SCSI logic.
+ ***/
+
+/* These are used in the following inline functions. */
+int sbc_wait_busy_timo = 1000 * 5000; /* X2 = 10 S. */
+int sbc_ready_timo = 1000 * 5000; /* X2 = 10 S. */
+int sbc_wait_dreq_timo = 1000 * 5000; /* X2 = 10 S. */
+
+/* Return zero on success. */
+static __inline__ int
+sbc_wait_busy(sc)
+ struct ncr5380_softc *sc;
+{
+ register int timo = sbc_wait_busy_timo;
+ for (;;) {
+ if (SCI_BUSY(sc)) {
+ timo = 0; /* return 0 */
+ break;
+ }
+ if (--timo < 0)
+ break; /* return -1 */
+ delay(2);
+ }
+ return (timo);
+}
+
+static __inline__ int
+sbc_ready(sc)
+ struct ncr5380_softc *sc;
+{
+ register int timo = sbc_ready_timo;
+
+ for (;;) {
+ if ((*sc->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH))
+ == (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) {
+ timo = 0;
+ break;
+ }
+ if (((*sc->sci_csr & SCI_CSR_PHASE_MATCH) == 0)
+ || (SCI_BUSY(sc) == 0)) {
+ timo = -1;
+ break;
+ }
+ if (--timo < 0)
+ break; /* return -1 */
+ delay(2);
+ }
+ return (timo);
+}
+
+static __inline__ int
+sbc_wait_dreq(sc)
+ struct ncr5380_softc *sc;
+{
+ register int timo = sbc_wait_dreq_timo;
+
+ for (;;) {
+ if ((*sc->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH))
+ == (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) {
+ timo = 0;
+ break;
+ }
+ if (--timo < 0)
+ break; /* return -1 */
+ delay(2);
+ }
+ return (timo);
+}
+
+
+/***
+ * Macintosh SCSI interrupt support routines.
+ ***/
+
+void
+sbc_intr_enable(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ register struct sbc_softc *sc = (struct sbc_softc *) ncr_sc;
+ int s;
+
+ s = splhigh();
+ *sc->sc_ienable = 0x80 | (V2IF_SCSIIRQ | V2IF_SCSIDRQ);
+ splx(s);
+}
+
+void
+sbc_intr_disable(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ register struct sbc_softc *sc = (struct sbc_softc *) ncr_sc;
+ int s;
+
+ s = splhigh();
+ *sc->sc_ienable = (V2IF_SCSIIRQ | V2IF_SCSIDRQ);
+ splx(s);
+}
+
+void
+sbc_irq_intr(p)
+ void *p;
+{
+ register struct ncr5380_softc *ncr_sc = p;
+ register int claimed = 0;
+
+ /* How we ever arrive here without IRQ set is a mystery... */
+ if (*ncr_sc->sci_csr & SCI_CSR_INT) {
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_INTR)
+ decode_5380_intr(ncr_sc);
+#endif
+ claimed = ncr5380_intr(ncr_sc);
+ if (!claimed) {
+ if (((*ncr_sc->sci_csr & ~SCI_CSR_PHASE_MATCH) == SCI_CSR_INT)
+ && ((*ncr_sc->sci_bus_csr & ~SCI_BUS_RST) == 0))
+ SCI_CLR_INTR(ncr_sc); /* RST interrupt */
+#ifdef SBC_DEBUG
+ else {
+ printf("%s: spurious intr\n",
+ ncr_sc->sc_dev.dv_xname);
+ SBC_BREAK;
+ }
+#endif
+ }
+ }
+}
+
+#ifdef SBC_DEBUG
+void
+decode_5380_intr(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ register u_char csr = *ncr_sc->sci_csr;
+ register u_char bus_csr = *ncr_sc->sci_bus_csr;
+
+ if (((csr & ~(SCI_CSR_PHASE_MATCH | SCI_CSR_ATN)) == SCI_CSR_INT) &&
+ ((bus_csr & ~(SCI_BUS_MSG | SCI_BUS_CD | SCI_BUS_IO | SCI_BUS_DBP)) == SCI_BUS_SEL)) {
+ if (csr & SCI_BUS_IO)
+ printf("%s: reselect\n", ncr_sc->sc_dev.dv_xname);
+ else
+ printf("%s: select\n", ncr_sc->sc_dev.dv_xname);
+ } else if (((csr & ~SCI_CSR_ACK) == (SCI_CSR_DONE | SCI_CSR_INT)) &&
+ ((bus_csr & (SCI_BUS_RST | SCI_BUS_BSY | SCI_BUS_SEL)) == SCI_BUS_BSY))
+ printf("%s: dma eop\n", ncr_sc->sc_dev.dv_xname);
+ else if (((csr & ~SCI_CSR_PHASE_MATCH) == SCI_CSR_INT) &&
+ ((bus_csr & ~SCI_BUS_RST) == 0))
+ printf("%s: bus reset\n", ncr_sc->sc_dev.dv_xname);
+ else if (((csr & ~(SCI_CSR_DREQ | SCI_CSR_ATN | SCI_CSR_ACK)) == (SCI_CSR_PERR | SCI_CSR_INT | SCI_CSR_PHASE_MATCH)) &&
+ ((bus_csr & (SCI_BUS_RST | SCI_BUS_BSY | SCI_BUS_SEL)) == SCI_BUS_BSY))
+ printf("%s: parity error\n", ncr_sc->sc_dev.dv_xname);
+ else if (((csr & ~SCI_CSR_ATN) == SCI_CSR_INT) &&
+ ((bus_csr & (SCI_BUS_RST | SCI_BUS_BSY | SCI_BUS_REQ | SCI_BUS_SEL)) == (SCI_BUS_BSY | SCI_BUS_REQ)))
+ printf("%s: phase mismatch\n", ncr_sc->sc_dev.dv_xname);
+ else if (((csr & ~SCI_CSR_PHASE_MATCH) == (SCI_CSR_INT | SCI_CSR_DISC)) &&
+ (bus_csr == 0))
+ printf("%s: disconnect\n", ncr_sc->sc_dev.dv_xname);
+ else
+ printf("%s: unknown intr: csr=%x, bus_csr=%x\n",
+ ncr_sc->sc_dev.dv_xname, csr, bus_csr);
+}
+#endif
+
+/***
+ * The following code implements polled PDMA.
+ ***/
+
+static int
+sbc_pdma_out(ncr_sc, phase, count, data)
+ struct ncr5380_softc *ncr_sc;
+ int phase;
+ int count;
+ u_char *data;
+{
+ struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
+ register volatile long *long_data = sc->sc_drq_addr;
+ register volatile u_char *byte_data = sc->sc_nodrq_addr;
+ register int len = count;
+
+ if (count < ncr_sc->sc_min_dma_len || (sc->sc_options & SBC_PDMA) == 0)
+ return ncr5380_pio_out(ncr_sc, phase, count, data);
+
+ if (sbc_wait_busy(ncr_sc) == 0) {
+ *ncr_sc->sci_mode |= SCI_MODE_DMA;
+ *ncr_sc->sci_icmd |= SCI_ICMD_DATA;
+ *ncr_sc->sci_dma_send = 0;
+
+#define W1 *byte_data = *data++
+#define W4 *long_data = *((long*)data)++
+ while (len >= 64) {
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ W1;
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ W1;
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ W1;
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ W1;
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ W4; W4; W4; W4;
+ W4; W4; W4; W4;
+ W4; W4; W4; W4;
+ W4; W4; W4;
+ len -= 64;
+ }
+ while (len) {
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ W1;
+ len--;
+ }
+#undef W1
+#undef W4
+ if (sbc_wait_dreq(ncr_sc))
+ printf("%s: timeout waiting for DREQ.\n",
+ ncr_sc->sc_dev.dv_xname);
+
+ *byte_data = 0;
+
+ SCI_CLR_INTR(ncr_sc);
+ *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
+ *ncr_sc->sci_icmd = 0;
+ }
+ return count - len;
+
+timeout:
+ printf("%s: pdma_out: timeout len=%d count=%d\n",
+ ncr_sc->sc_dev.dv_xname, len, count);
+ if ((*ncr_sc->sci_csr & SCI_CSR_PHASE_MATCH) == 0) {
+ *ncr_sc->sci_icmd &= ~SCI_ICMD_DATA;
+ --len;
+ }
+
+ SCI_CLR_INTR(ncr_sc);
+ *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
+ *ncr_sc->sci_icmd = 0;
+ return count - len;
+}
+
+static int
+sbc_pdma_in(ncr_sc, phase, count, data)
+ struct ncr5380_softc *ncr_sc;
+ int phase;
+ int count;
+ u_char *data;
+{
+ struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
+ register volatile long *long_data = sc->sc_drq_addr;
+ register volatile u_char *byte_data = sc->sc_nodrq_addr;
+ register int len = count;
+
+ if (count < ncr_sc->sc_min_dma_len || (sc->sc_options & SBC_PDMA) == 0)
+ return ncr5380_pio_in(ncr_sc, phase, count, data);
+
+ if (sbc_wait_busy(ncr_sc) == 0) {
+ *ncr_sc->sci_mode |= SCI_MODE_DMA;
+ *ncr_sc->sci_icmd |= SCI_ICMD_DATA;
+ *ncr_sc->sci_irecv = 0;
+
+#define R4 *((long *)data)++ = *long_data
+#define R1 *data++ = *byte_data
+ while (len >= 1024) {
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 128 */
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 256 */
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 384 */
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 512 */
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 640 */
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 768 */
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 896 */
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 1024 */
+ len -= 1024;
+ }
+ while (len >= 128) {
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 128 */
+ len -= 128;
+ }
+ while (len) {
+ if (sbc_ready(ncr_sc))
+ goto timeout;
+ R1;
+ len--;
+ }
+#undef R4
+#undef R1
+ SCI_CLR_INTR(ncr_sc);
+ *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
+ *ncr_sc->sci_icmd = 0;
+ }
+ return count - len;
+
+timeout:
+ printf("%s: pdma_in: timeout len=%d count=%d\n",
+ ncr_sc->sc_dev.dv_xname, len, count);
+
+ SCI_CLR_INTR(ncr_sc);
+ *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
+ *ncr_sc->sci_icmd = 0;
+ return count - len;
+}
+
+
+/***
+ * The following code implements interrupt-driven PDMA.
+ ***/
+
+/*
+ * This is the meat of the PDMA transfer.
+ * When we get here, we shove data as fast as the mac can take it.
+ * We depend on several things:
+ * * All macs after the Mac Plus that have a 5380 chip should have a general
+ * logic IC that handshakes data for blind transfers.
+ * * If the SCSI controller finishes sending/receiving data before we do,
+ * the same general logic IC will generate a /BERR for us in short order.
+ * * The fault address for said /BERR minus the base address for the
+ * transfer will be the amount of data that was actually written.
+ *
+ * We use the nofault flag and the setjmp/longjmp in locore.s so we can
+ * detect and handle the bus error for early termination of a command.
+ * This is usually caused by a disconnecting target.
+ */
+void
+sbc_drq_intr(p)
+ void *p;
+{
+ extern int *nofault, mac68k_buserr_addr;
+ register struct sbc_softc *sc = (struct sbc_softc *) p;
+ register struct ncr5380_softc *ncr_sc = (struct ncr5380_softc *) p;
+ register struct sci_req *sr = ncr_sc->sc_current;
+ register struct sbc_pdma_handle *dh = sr->sr_dma_hand;
+ label_t faultbuf;
+ volatile u_int32_t *long_drq;
+ u_int32_t *long_data;
+ volatile u_int8_t *drq;
+ u_int8_t *data;
+ register int count;
+ int dcount, resid;
+
+ /*
+ * If we're not ready to xfer data, or have no more, just return.
+ */
+ if ((*ncr_sc->sci_csr & SCI_CSR_DREQ) == 0 || dh->dh_len == 0)
+ return;
+
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_INTR)
+ printf("%s: drq intr, dh_len=0x%x, dh_flags=0x%x\n",
+ ncr_sc->sc_dev.dv_xname, dh->dh_len, dh->dh_flags);
+#endif
+
+ /*
+ * Setup for a possible bus error caused by SCSI controller
+ * switching out of DATA-IN/OUT before we're done with the
+ * current transfer.
+ */
+ nofault = (int *) &faultbuf;
+
+ if (setjmp((label_t *) nofault)) {
+ nofault = (int *) 0;
+ count = ( (u_long) mac68k_buserr_addr
+ - (u_long) sc->sc_drq_addr);
+
+ if ((count < 0) || (count > dh->dh_len)) {
+ printf("%s: complete=0x%x (pending 0x%x)\n",
+ ncr_sc->sc_dev.dv_xname, count, dh->dh_len);
+ panic("something is wrong");
+ }
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_INTR)
+ printf("%s: drq /berr, pending=0x%x, complete=0x%x\n",
+ ncr_sc->sc_dev.dv_xname, dh->dh_len, count);
+#endif
+
+ dh->dh_addr += count;
+ dh->dh_len -= count;
+ mac68k_buserr_addr = 0;
+
+ return;
+ }
+
+ if (dh->dh_flags & SBC_DH_OUT) { /* Data Out */
+ /*
+ * Get the source address aligned.
+ */
+ resid =
+ count = min(dh->dh_len, 4 - (((int) dh->dh_addr) & 0x3));
+ if (count && count < 4) {
+ data = (u_int8_t *) dh->dh_addr;
+ drq = (u_int8_t *) sc->sc_drq_addr;
+#define W1 *drq++ = *data++
+ while (count) {
+ W1; count--;
+ }
+#undef W1
+ dh->dh_addr += resid;
+ dh->dh_len -= resid;
+ }
+
+ /*
+ * Get ready to start the transfer.
+ */
+ while (dh->dh_len) {
+ dcount = count = min(dh->dh_len, MAX_DMA_LEN);
+ long_drq = (volatile u_int32_t *) sc->sc_drq_addr;
+ long_data = (u_int32_t *) dh->dh_addr;
+
+#define W4 *long_drq++ = *long_data++
+ while (count >= 64) {
+ W4; W4; W4; W4; W4; W4; W4; W4;
+ W4; W4; W4; W4; W4; W4; W4; W4; /* 64 */
+ count -= 64;
+ }
+ while (count >= 4) {
+ W4; count -= 4;
+ }
+#undef W4
+ data = (u_int8_t *) long_data;
+ drq = (u_int8_t *) long_drq;
+#define W1 *drq++ = *data++
+ while (count) {
+ W1; count--;
+ }
+#undef W1
+ dh->dh_len -= dcount;
+ dh->dh_addr += dcount;
+ }
+ } else { /* Data In */
+ /*
+ * Get the dest address aligned.
+ */
+ resid =
+ count = min(dh->dh_len, 4 - (((int) dh->dh_addr) & 0x3));
+ if (count && count < 4) {
+ data = (u_int8_t *) dh->dh_addr;
+ drq = (u_int8_t *) sc->sc_drq_addr;
+#define R1 *data++ = *drq++
+ while (count) {
+ R1; count--;
+ }
+#undef R1
+ dh->dh_addr += resid;
+ dh->dh_len -= resid;
+ }
+
+ /*
+ * Get ready to start the transfer.
+ */
+ while (dh->dh_len) {
+ dcount = count = min(dh->dh_len, MAX_DMA_LEN);
+ long_drq = (volatile u_int32_t *) sc->sc_drq_addr;
+ long_data = (u_int32_t *) dh->dh_addr;
+
+#define R4 *long_data++ = *long_drq++
+ while (count >= 512) {
+ if ((*ncr_sc->sci_csr & SCI_CSR_DREQ) == 0) {
+ nofault = (int *) 0;
+
+ dh->dh_addr += (dcount - count);
+ dh->dh_len -= (dcount - count);
+ return;
+ }
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 64 */
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 128 */
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 256 */
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4;
+ R4; R4; R4; R4; R4; R4; R4; R4; /* 512 */
+ count -= 512;
+ }
+ while (count >= 4) {
+ R4; count -= 4;
+ }
+#undef R4
+ data = (u_int8_t *) long_data;
+ drq = (u_int8_t *) long_drq;
+#define R1 *data++ = *drq++
+ while (count) {
+ R1; count--;
+ }
+#undef R1
+ dh->dh_len -= dcount;
+ dh->dh_addr += dcount;
+ }
+ }
+
+ /*
+ * OK. No bus error occurred above. Clear the nofault flag
+ * so we no longer short-circuit bus errors.
+ */
+ nofault = (int *) 0;
+}
+
+void
+sbc_dma_alloc(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ struct sbc_softc *sc = (struct sbc_softc *) ncr_sc;
+ struct sci_req *sr = ncr_sc->sc_current;
+ struct scsi_xfer *xs = sr->sr_xs;
+ struct sbc_pdma_handle *dh;
+ int i, xlen;
+
+#ifdef DIAGNOSTIC
+ if (sr->sr_dma_hand != NULL)
+ panic("sbc_dma_alloc: already have PDMA handle");
+#endif
+
+ /* Polled transfers shouldn't allocate a PDMA handle. */
+ if (sr->sr_flags & SR_IMMED)
+ return;
+
+#ifndef SBCTEST
+ /* XXX - we don't trust PDMA writes yet! */
+ if (xs->flags & SCSI_DATA_OUT)
+ return;
+#endif
+
+ xlen = ncr_sc->sc_datalen;
+
+ /* Make sure our caller checked sc_min_dma_len. */
+ if (xlen < MIN_DMA_LEN)
+ panic("sbc_dma_alloc: len=0x%x\n", xlen);
+
+ /*
+ * Find free PDMA handle. Guaranteed to find one since we
+ * have as many PDMA handles as the driver has processes.
+ * (instances?)
+ */
+ for (i = 0; i < SCI_OPENINGS; i++) {
+ if ((sc->sc_pdma[i].dh_flags & SBC_DH_BUSY) == 0)
+ goto found;
+ }
+ panic("sbc: no free PDMA handles");
+found:
+ dh = &sc->sc_pdma[i];
+ dh->dh_flags = SBC_DH_BUSY;
+ dh->dh_addr = ncr_sc->sc_dataptr;
+ dh->dh_len = xlen;
+
+ /* Copy the 'write' flag for convenience. */
+ if (xs->flags & SCSI_DATA_OUT)
+ dh->dh_flags |= SBC_DH_OUT;
+
+ sr->sr_dma_hand = dh;
+}
+
+void
+sbc_dma_free(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ struct sci_req *sr = ncr_sc->sc_current;
+ struct sbc_pdma_handle *dh = sr->sr_dma_hand;
+
+#ifdef DIAGNOSTIC
+ if (sr->sr_dma_hand == NULL)
+ panic("sbc_dma_free: no DMA handle");
+#endif
+
+ if (ncr_sc->sc_state & NCR_DOINGDMA)
+ panic("sbc_dma_free: free while in progress");
+
+ if (dh->dh_flags & SBC_DH_BUSY) {
+ dh->dh_flags = 0;
+ dh->dh_addr = NULL;
+ dh->dh_len = 0;
+ }
+ sr->sr_dma_hand = NULL;
+}
+
+void
+sbc_dma_poll(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ struct sci_req *sr = ncr_sc->sc_current;
+
+ /*
+ * We shouldn't arrive here; if SR_IMMED is set, then
+ * dma_alloc() should have refused to allocate a handle
+ * for the transfer. This forces the polled PDMA code
+ * to handle the request...
+ */
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_DMA)
+ printf("%s: lost DRQ interrupt?\n", ncr_sc->sc_dev.dv_xname);
+#endif
+ sr->sr_flags |= SR_OVERDUE;
+}
+
+void
+sbc_dma_setup(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ /* Not needed; we don't have real DMA */
+}
+
+void
+sbc_dma_start(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ struct sci_req *sr = ncr_sc->sc_current;
+ struct sbc_pdma_handle *dh = sr->sr_dma_hand;
+
+ /*
+ * Match bus phase, set DMA mode, and assert data bus (for
+ * writing only), then start the transfer.
+ */
+ if (dh->dh_flags & SBC_DH_OUT) {
+ *ncr_sc->sci_tcmd = PHASE_DATA_OUT;
+ SCI_CLR_INTR(ncr_sc);
+ *ncr_sc->sci_mode |= SCI_MODE_DMA;
+ *ncr_sc->sci_icmd = SCI_ICMD_DATA;
+ *ncr_sc->sci_dma_send = 0;
+ } else {
+ *ncr_sc->sci_tcmd = PHASE_DATA_IN;
+ SCI_CLR_INTR(ncr_sc);
+ *ncr_sc->sci_mode |= SCI_MODE_DMA;
+ *ncr_sc->sci_icmd = 0;
+ *ncr_sc->sci_irecv = 0;
+ }
+ ncr_sc->sc_state |= NCR_DOINGDMA;
+
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_DMA)
+ printf("%s: PDMA started, va=%p, len=0x%x\n",
+ ncr_sc->sc_dev.dv_xname, dh->dh_addr, dh->dh_len);
+#endif
+}
+
+void
+sbc_dma_eop(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ /* Not used; the EOP pin is wired high (GMFH, pp. 389-390) */
+}
+
+void
+sbc_dma_stop(ncr_sc)
+ struct ncr5380_softc *ncr_sc;
+{
+ struct sci_req *sr = ncr_sc->sc_current;
+ struct sbc_pdma_handle *dh = sr->sr_dma_hand;
+ register int ntrans;
+
+ if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) {
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_DMA)
+ printf("%s: dma_stop: DMA not running\n",
+ ncr_sc->sc_dev.dv_xname);
+#endif
+ return;
+ }
+ ncr_sc->sc_state &= ~NCR_DOINGDMA;
+
+ if ((ncr_sc->sc_state & NCR_ABORTING) == 0) {
+ ntrans = ncr_sc->sc_datalen - dh->dh_len;
+
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_DMA)
+ printf("%s: dma_stop: ntrans=0x%x\n",
+ ncr_sc->sc_dev.dv_xname, ntrans);
+#endif
+
+ if (ntrans > ncr_sc->sc_datalen)
+ panic("sbc_dma_stop: excess transfer\n");
+
+ /* Adjust data pointer */
+ ncr_sc->sc_dataptr += ntrans;
+ ncr_sc->sc_datalen -= ntrans;
+
+ /* Clear any pending interrupts. */
+ SCI_CLR_INTR(ncr_sc);
+ }
+
+ /* Put SBIC back into PIO mode. */
+ *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
+ *ncr_sc->sci_icmd = 0;
+
+#ifdef SBC_DEBUG
+ if (sbc_debug & SBC_DB_REG)
+ printf("%s: dma_stop: csr=0x%x, bus_csr=0x%x\n",
+ ncr_sc->sc_dev.dv_xname, *ncr_sc->sci_csr,
+ *ncr_sc->sci_bus_csr);
+#endif
+}
diff --git a/sys/arch/mac68k/dev/sbcreg.h b/sys/arch/mac68k/dev/sbcreg.h
new file mode 100644
index 00000000000..6daf826b440
--- /dev/null
+++ b/sys/arch/mac68k/dev/sbcreg.h
@@ -0,0 +1,28 @@
+/* $OpenBSD: sbcreg.h,v 1.1 1996/05/26 19:02:10 briggs Exp $ */
+/* $NetBSD: sbcreg.h,v 1.1 1996/04/25 22:26:56 scottr Exp $ */
+
+/*
+ * Register map for the Mac II SCSI Interface (sbc)
+ * This register map is for the SYM/NCR5380 SCSI Bus Interface
+ * Controller (SBIC), with the wonderful 16 bytes/register layout
+ * that Macs have.
+ */
+
+/*
+ * Am5380 Register map (with padding)
+ */
+typedef union {
+ volatile u_char sci_reg;
+ volatile u_char pad[16];
+} ncr5380_padded_reg_t;
+
+struct sbc_regs {
+ ncr5380_padded_reg_t sci_pr0;
+ ncr5380_padded_reg_t sci_pr1;
+ ncr5380_padded_reg_t sci_pr2;
+ ncr5380_padded_reg_t sci_pr3;
+ ncr5380_padded_reg_t sci_pr4;
+ ncr5380_padded_reg_t sci_pr5;
+ ncr5380_padded_reg_t sci_pr6;
+ ncr5380_padded_reg_t sci_pr7;
+};
diff --git a/sys/arch/mac68k/dev/z8530sc.c b/sys/arch/mac68k/dev/z8530sc.c
new file mode 100644
index 00000000000..2447c5233e0
--- /dev/null
+++ b/sys/arch/mac68k/dev/z8530sc.c
@@ -0,0 +1,396 @@
+/* $OpenBSD: z8530sc.c,v 1.1 1996/05/26 19:02:10 briggs Exp $ */
+/* $NetBSD: z8530sc.c,v 1.1 1996/05/18 18:54:28 briggs Exp $ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (common part)
+ *
+ * This file contains the machine-independent parts of the
+ * driver common to tty and keyboard/mouse sub-drivers.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+/* #include <dev/ic/z8530reg.h> */
+#include "z8530reg.h"
+#include <machine/z8530var.h>
+
+int
+zs_break(cs, set)
+ struct zs_chanstate *cs;
+ int set;
+{
+ int s;
+
+ s = splzs();
+ if (set) {
+ cs->cs_preg[5] |= ZSWR5_BREAK;
+ cs->cs_creg[5] |= ZSWR5_BREAK;
+ } else {
+ cs->cs_preg[5] &= ~ZSWR5_BREAK;
+ cs->cs_creg[5] &= ~ZSWR5_BREAK;
+ }
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
+ splx(s);
+
+ return 0;
+}
+
+
+/*
+ * Compute the current baud rate given a ZSCC channel.
+ */
+int
+zs_getspeed(cs)
+ struct zs_chanstate *cs;
+{
+ int tconst;
+
+ tconst = zs_read_reg(cs, 12);
+ tconst |= zs_read_reg(cs, 13) << 8;
+ return (TCONST_TO_BPS(cs->cs_pclk_div16, tconst));
+}
+
+/*
+ * drain on-chip fifo
+ */
+void
+zs_iflush(cs)
+ struct zs_chanstate *cs;
+{
+ u_char c, rr0, rr1;
+
+ for (;;) {
+ /* Is there input available? */
+ rr0 = zs_read_csr(cs);
+ if ((rr0 & ZSRR0_RX_READY) == 0)
+ break;
+
+ /*
+ * 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);
+
+ if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
+ /* Clear the receive error. */
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
+ }
+ }
+}
+
+/*
+ * Figure out if a chip is an NMOS 8530, a CMOS 8530,
+ * or an 85230. We use a form of the test in the Zilog SCC
+ * users manual.
+ */
+int
+zs_checkchip(cs)
+ struct zs_chanstate *cs;
+{
+ char r1, r2, r3;
+ int chip;
+
+ /* we assume we can write to the chip */
+
+ r1=cs->cs_creg[15]; /* see if bit 0 sticks */
+ zs_write_reg(cs, 15, (r1 | ZSWR15_ENABLE_ENHANCED));
+ if ((zs_read_reg(cs, 15) & ZSWR15_ENABLE_ENHANCED) != 0) {
+ /* we have either an 8580 or 85230. NB Zilog says we should only
+ * have an 85230 at this point, but the 8580 seems to pass this
+ * test too. To test, we try to write to WR7', and see if we
+ * loose sight of RR14. */
+ r2=cs->cs_creg[14];
+ r3=(r2 != 0x47) ? 0x47 : 0x40;
+ /* unique bit pattern to turn on reading of WR7' at RR14 */
+ zs_write_reg(cs, 7, ~r2);
+ if (zs_read_reg(cs, ZSRR_ENHANCED) != r2) {
+ chip = ZS_CHIP_ESCC;
+ zs_write_reg(cs, 7, cs->cs_creg[ZS_ENHANCED_REG]);
+ } else {
+ chip = ZS_CHIP_8580;
+ zs_write_reg(cs, 7, cs->cs_creg[7]);
+ }
+ zs_write_reg(cs, 15, r1);
+ } else { /* now we have to tell an NMOS from a CMOS; does WR15 D2 work? */
+ zs_write_reg(cs, 15, (r1 | ZSWR15_SDLC_FIFO));
+ r2=cs->cs_creg[2];
+ zs_write_reg(cs, 2, (r2 | 0x80));
+ chip = (zs_read_reg(cs, 6) & 0x80) ? ZS_CHIP_NMOS : ZS_CHIP_CMOS;
+ zs_write_reg(cs, 2, r2);
+ }
+ zs_write_reg(cs, 15, r1);
+ return chip;
+}
+
+/*
+ * Write the given register set to the given zs channel in the proper order.
+ * The channel must not be transmitting at the time. The receiver will
+ * be disabled for the time it takes to write all the registers.
+ * Call this with interrupts disabled.
+ */
+void
+zs_loadchannelregs(cs)
+ struct zs_chanstate *cs;
+{
+ u_char *reg;
+
+ /* Copy "pending" regs to "current" */
+ bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16);
+ reg = cs->cs_creg; /* current regs */
+
+ zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */
+
+#if 1
+ /*
+ * XXX: Is this really a good idea?
+ * XXX: Should go elsewhere! -gwr
+ */
+ zs_iflush(cs); /* XXX */
+#endif
+
+ /* disable interrupts */
+ zs_write_reg(cs, 1, reg[1] &
+ ~(ZSWR1_RIE_SPECIAL_ONLY | ZSWR1_TIE | ZSWR1_SIE));
+
+ /* baud clock divisor, stop bits, parity */
+ zs_write_reg(cs, 4, reg[4]);
+
+ /* misc. TX/RX control bits */
+ zs_write_reg(cs, 10, reg[10]);
+
+ /* char size, enable (RX/TX) */
+ zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE);
+ zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE);
+
+ /* synchronous mode stuff */
+ zs_write_reg(cs, 6, reg[6]);
+ zs_write_reg(cs, 7, reg[7]);
+
+#if 0
+ /*
+ * Registers 2 and 9 are special because they are
+ * actually common to both channels, but must be
+ * programmed through channel A. The "zsc" attach
+ * function takes care of setting these registers
+ * and they should not be touched thereafter.
+ */
+ /* interrupt vector */
+ zs_write_reg(cs, 2, reg[2]);
+ /* master interrupt control */
+ zs_write_reg(cs, 9, reg[9]);
+#endif
+
+ /* Shut down the BRG */
+ zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA);
+
+ if ((cs->cs_cclk_flag & ZSC_EXTERN) ||
+ (cs->cs_pclk_flag & ZSC_EXTERN))
+ zsmd_setclock(cs);
+ /* the md layer wants to do something; let it. */
+
+ /* clock mode control */
+ zs_write_reg(cs, 11, reg[11]);
+
+ /* baud rate (lo/hi) */
+ zs_write_reg(cs, 12, reg[12]);
+ zs_write_reg(cs, 13, reg[13]);
+
+ /* Misc. control bits */
+ zs_write_reg(cs, 14, reg[14]);
+
+ /* which lines cause status interrupts */
+ zs_write_reg(cs, 15, reg[15]);
+
+ /* Zilog docs recommend resetting external status twice at this
+ * point. Mainly as the status bits are latched, and the first
+ * interrupt clear might unlatch them to new values, generating
+ * a second interrupt request.
+ */
+ zs_write_csr(cs, ZSM_RESET_STINT);
+ zs_write_csr(cs, ZSM_RESET_STINT);
+
+ /* char size, enable (RX/TX)*/
+ zs_write_reg(cs, 3, reg[3]);
+ zs_write_reg(cs, 5, reg[5]);
+
+ /* interrupt enables: TX, TX, STATUS */
+ zs_write_reg(cs, 1, reg[1]);
+
+ cs->cs_cclk_flag = cs->cs_pclk_flag;
+ cs->cs_csource = cs->cs_psource;
+}
+
+
+/*
+ * ZS hardware interrupt. Scan all ZS channels. NB: we know here that
+ * channels are kept in (A,B) pairs.
+ *
+ * Do just a little, then get out; set a software interrupt if more
+ * work is needed.
+ *
+ * We deliberately ignore the vectoring Zilog gives us, and match up
+ * only the number of `reset interrupt under service' operations, not
+ * the order.
+ */
+int
+zsc_intr_hard(arg)
+ void *arg;
+{
+ register struct zsc_softc *zsc = arg;
+ register struct zs_chanstate *cs_a;
+ register struct zs_chanstate *cs_b;
+ register int rval;
+ register u_char rr3;
+
+ cs_a = &zsc->zsc_cs[0];
+ cs_b = &zsc->zsc_cs[1];
+ rval = 0;
+
+ /* Note: only channel A has an RR3 */
+ rr3 = zs_read_reg(cs_a, 3);
+
+ /* Handle receive interrupts first. */
+ if (rr3 & ZSRR3_IP_A_RX)
+ (*cs_a->cs_ops->zsop_rxint)(cs_a);
+ 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);
+
+ /* Clear interrupt. */
+ if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) {
+ zs_write_csr(cs_a, ZSWR0_CLR_INTR);
+ rval |= 1;
+ }
+ if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) {
+ 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 (or macro). */
+ zsc_req_softint(zsc);
+ }
+
+ return (rval);
+}
+
+
+/*
+ * ZS software interrupt. Scan all channels for deferred interrupts.
+ */
+int
+zsc_intr_soft(arg)
+ void *arg;
+{
+ register struct zsc_softc *zsc = arg;
+ register struct zs_chanstate *cs;
+ register int rval, unit;
+
+ rval = 0;
+ for (unit = 0; unit < 2; unit++) {
+ cs = &zsc->zsc_cs[unit];
+
+ /*
+ * 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;
+ }
+ }
+ return (rval);
+}
+
+static void zsnull_intr __P((struct zs_chanstate *));
+static void zsnull_softint __P((struct zs_chanstate *));
+
+static void
+zsnull_intr(cs)
+ struct zs_chanstate *cs;
+{
+ zs_write_reg(cs, 1, 0);
+ zs_write_reg(cs, 15, 0);
+}
+
+static void
+zsnull_softint(cs)
+ struct zs_chanstate *cs;
+{
+}
+
+struct zsops zsops_null = {
+ zsnull_intr, /* receive char available */
+ zsnull_intr, /* external/status */
+ zsnull_intr, /* xmit buffer empty */
+ zsnull_softint, /* process software interrupt */
+};
diff --git a/sys/arch/mac68k/dev/z8530sc.h b/sys/arch/mac68k/dev/z8530sc.h
new file mode 100644
index 00000000000..ba19bff490d
--- /dev/null
+++ b/sys/arch/mac68k/dev/z8530sc.h
@@ -0,0 +1,174 @@
+/* $OpenBSD: z8530sc.h,v 1.1 1996/05/26 19:02:11 briggs Exp $ */
+/* $NetBSD: z8530sc.h,v 1.1 1996/05/18 18:54:30 briggs Exp $ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+
+/*
+ * Clock source info structure
+ */
+struct zsclksrc {
+ long clk; /* clock rate, in MHz, present on signal line */
+ int flags; /* Specifies how this source can be used
+ (RTxC divided, RTxC BRG, PCLK BRG, TRxC divided)
+ and also if the source is "external" and if it
+ is changeable (by an ioctl ex.). The
+ source usage flags are used by the tty
+ child. The other bits tell zsloadchannelregs
+ if it should call an md signal source
+ changing routine. ZSC_VARIABLE says if
+ an ioctl should be able to cahnge the
+ clock rate.*/
+};
+#define ZSC_PCLK 0x01
+#define ZSC_RTXBRG 0x02
+#define ZSC_RTXDIV 0x04
+#define ZSC_TRXDIV 0x08
+#define ZSC_VARIABLE 0x40
+#define ZSC_EXTERN 0x80
+
+#define ZSC_BRG 0x03
+#define ZSC_DIV 0x0c
+
+
+/*
+ * Software state, per zs channel.
+ */
+struct zs_chanstate {
+
+ /* Pointers to the device registers. */
+ volatile u_char *cs_reg_csr; /* ctrl, status, and reg. number. */
+ volatile u_char *cs_reg_data; /* data or numbered register */
+
+ int cs_channel; /* sub-unit number */
+ void *cs_private; /* sub-driver data pointer */
+ struct zsops *cs_ops;
+
+ int cs_defspeed; /* default baud rate (from PROM) */
+ int cs_pclk_div16; /* PCLK / 16 used only by kbd & ms kids */
+ int cs_clock_count; /* how many signal sources available */
+ struct zsclksrc cs_clocks[4]; /* info on available signal sources */
+
+ /*
+ * We must keep a copy of the write registers as they are
+ * mostly write-only and we sometimes need to set and clear
+ * individual bits (e.g., in WR3). Not all of these are
+ * needed but 16 bytes is cheap and this makes the addressing
+ * simpler. Unfortunately, we can only write to some registers
+ * when the chip is not actually transmitting, so whenever
+ * we are expecting a `transmit done' interrupt the preg array
+ * is allowed to `get ahead' of the current values. In a
+ * few places we must change the current value of a register,
+ * rather than (or in addition to) the pending value; for these
+ * cs_creg[] contains the current value.
+ */
+ u_char cs_creg[16]; /* current values */
+ u_char cs_preg[16]; /* pending values */
+ long cs_cclk_flag; /* flag for current clock source */
+ long cs_pclk_flag; /* flag for pending clock source */
+ int cs_csource; /* current source # */
+ int cs_psource; /* pending source # */
+
+ 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_chip; /* type of chip */
+ char cs__spare;
+};
+#define ZS_ENHANCED_REG 8
+ /* cs_Xreg which is used to hold WR7' data; reg 8 is an alias to the
+ * data port, so we won't miss its loss. */
+
+/*
+ * Function vector - per channel
+ */
+typedef void (*zsop_t)(register struct zs_chanstate *);
+struct zsops {
+ zsop_t zsop_rxint; /* receive char available */
+ zsop_t zsop_stint; /* external/status */
+ zsop_t zsop_txint; /* xmit buffer empty */
+ zsop_t zsop_softint; /* process software interrupt */
+};
+
+extern struct zsops zsops_null;
+
+struct zsc_softc {
+ struct device zsc_dev; /* required first: base device */
+ struct zs_chanstate zsc_cs[2]; /* channel A and B soft state */
+};
+
+struct zsc_attach_args {
+ int channel; /* two serial channels per zsc */
+ int hwflags;
+};
+#define ZS_HWFLAG_CONSOLE 1
+#define ZS_HWFLAG_CONABRT 2
+#define ZS_HWFLAG_RAW 4
+#define ZS_HWFLAG_IGCTS 16
+#define ZS_HWFLAG_IGDCD 32
+/* _CONSOLE says this port is the console, _CONABRT says a Break sequence acts as
+ an abort, and _RAW recomends "raw" mode defaults on a tty.
+ _CONABRT is turned off if an overly-long break is received.
+ _IGCTS and _IGDCD tell the tty layer to ignore CTS or DCD. Assume
+ whatever's least supprising (CTS and DCD present). Used mainly for
+ external clock support on mac68k. The DCD and CTS pins are used also
+ for clock inputs; not good for the UNIX I/O model! */
+
+#define ZS_CHIP_NMOS 0
+#define ZS_CHIP_CMOS 1
+#define ZS_CHIP_8580 2
+#define ZS_CHIP_ESCC 3
+
+void zs_loadchannelregs __P((struct zs_chanstate *));
+int zsc_intr_soft __P((void *));
+int zsc_intr_hard __P((void *));
+int zs_checkchip __P((struct zs_chanstate *));
+int zs_break __P((struct zs_chanstate *, int));
+int zs_getspeed __P((struct zs_chanstate *));
+void zs_iflush __P((struct zs_chanstate *));
+
diff --git a/sys/arch/mac68k/dev/z8530tty.c b/sys/arch/mac68k/dev/z8530tty.c
new file mode 100644
index 00000000000..fa4cb3274de
--- /dev/null
+++ b/sys/arch/mac68k/dev/z8530tty.c
@@ -0,0 +1,1433 @@
+/* $OpenBSD: z8530tty.c,v 1.1 1996/05/26 19:02:12 briggs Exp $ */
+/* $NetBSD: z8530tty.c,v 1.2 1996/05/23 02:06:53 briggs Exp $ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (tty interface)
+ *
+ * This is the "slave" driver that will be attached to
+ * the "zsc" driver for plain "tty" async. serial lines.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#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>
+#include <sys/syslog.h>
+
+/* #include <dev/ic/z8530reg.h> */
+#include "z8530reg.h"
+#include <machine/z8530var.h>
+
+#ifdef KGDB
+extern int zs_check_kgdb();
+#endif
+
+/*
+ * 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;
+
+/* This should usually be 3/4 of ZSTTY_RING_SIZE */
+int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE - (ZSTTY_RING_SIZE >> 2));
+
+struct zstty_stats z8530tty_stats;
+
+
+/* Definition of the driver for autoconfig. */
+static int zstty_match(struct device *, void *, void *);
+static void zstty_attach(struct device *, struct device *, void *);
+
+struct cfattach zstty_ca = {
+ sizeof(struct zstty_softc), zstty_match, zstty_attach
+};
+
+struct cfdriver zstty_cd = {
+ NULL, "zstty", DV_TTY
+};
+
+struct zsops zsops_tty;
+
+/* Routines called from other code. */
+cdev_decl(zs); /* open, close, read, write, ioctl, stop, ... */
+
+static void zsstart __P((struct tty *));
+static int zsparam __P((struct tty *, struct termios *));
+static void zs_modem __P((struct zstty_softc *zst, int onoff));
+static int zshwiflow __P((struct tty *, int));
+static void zs_hwiflow __P((struct zstty_softc *, int));
+static int zsgetbaud __P((register struct zs_chanstate *,
+ register int *rate, register int *tc, register u_char *rr4,
+ register u_char *rr11, register u_char *rr14,
+ register int *source, register int *sourceflag));
+
+/*
+ * zstty_match: how is this zs channel configured?
+ */
+int
+zstty_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct cfdata *cf = match;
+ struct zsc_attach_args *args = aux;
+
+ /* Exact match is better than wildcard. */
+ if (cf->cf_loc[0] == args->channel)
+ return 2;
+
+ /* This driver accepts wildcard. */
+ if (cf->cf_loc[0] == -1)
+ return 1;
+
+ return 0;
+}
+
+void
+zstty_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+
+{
+ struct zsc_softc *zsc = (void *) parent;
+ struct zstty_softc *zst = (void *) self;
+ struct zsc_attach_args *args = aux;
+ struct zs_chanstate *cs;
+ struct cfdata *cf;
+ struct tty *tp;
+ int channel, tty_unit;
+ dev_t dev;
+
+ cf = zst->zst_dev.dv_cfdata;
+ tty_unit = zst->zst_dev.dv_unit;
+ channel = args->channel;
+ cs = &zsc->zsc_cs[channel];
+ cs->cs_private = zst;
+ cs->cs_ops = &zsops_tty;
+
+ zst->zst_cs = cs;
+ zst->zst_swflags = cf->cf_flags; /* softcar, etc. */
+ zst->zst_hwflags = args->hwflags;
+
+ zst->zst_cflag = ZSTTY_DEF_CFLAG; /* set up defaults */
+ zst->zst_iflag = TTYDEF_IFLAG; /* an ioctl can change */
+ zst->zst_lflag = TTYDEF_LFLAG; /* these values, modifying */
+ zst->zst_oflag = TTYDEF_OFLAG; /* initial defaults */
+ zst->zst_ispeed = zst->zst_ospeed = cs->cs_defspeed;
+ /* zst_cc set after tty is malloc'd */
+
+ dev = makedev(ZSTTY_MAJOR, tty_unit);
+
+ if (zst->zst_swflags)
+ printf(" flags 0x%x", zst->zst_swflags);
+
+ if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)
+ printf(" (console)");
+ else {
+#ifdef KGDB
+ /*
+ * Allow kgdb to "take over" this port. If this port is
+ * NOT the kgdb port, zs_check_kgdb() will return zero.
+ * If it IS the kgdb port, it will print "kgdb,...\n"
+ * and then return non-zero.
+ */
+ if (zs_check_kgdb(cs, dev)) {
+ /*
+ * This is the kgdb port (exclusive use)
+ * so skip the normal attach code.
+ */
+ return;
+ }
+#endif
+ }
+
+ tp = ttymalloc();
+ tp->t_dev = dev;
+ tp->t_oproc = zsstart;
+ tp->t_param = zsparam;
+ tp->t_hwiflow = zshwiflow;
+ ttychars(tp);
+ bcopy(tp->t_cc, zst->zst_cc, sizeof(tp->t_cc));
+
+ zst->zst_tty = tp;
+ zst->zst_rbhiwat = zstty_rbuf_size; /* impossible value */
+ zst->zst_ringmask = zstty_rbuf_size - 1;
+ zst->zst_rbuf = malloc(zstty_rbuf_size * sizeof(zst->zst_rbuf[0]),
+ M_DEVBUF, M_WAITOK);
+
+ zstty_mdattach(zsc, zst, cs, tp); /*let the md code customize stuff */
+
+ if (zst->zst_hwflags & (ZS_HWFLAG_IGCTS | ZS_HWFLAG_IGDCD)) {
+ printf("\n Ignoring ");
+ switch (zst->zst_hwflags & (ZS_HWFLAG_IGCTS | ZS_HWFLAG_IGDCD)) {
+ case ZS_HWFLAG_IGCTS:
+ printf("CTS line "); break;
+ case ZS_HWFLAG_IGDCD:
+ printf("DCD line "); break;
+ default:
+ printf("CTS and DCD lines ");
+ }
+ }
+
+ printf("\n");
+ /*
+ * Hardware init
+ */
+ if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE) {
+ /* This unit is the console. */
+ zst->zst_swflags |= TIOCFLAG_SOFTCAR;
+ /* Call _param so interrupts get enabled. */
+ bcopy(&zst->zst_termios, &tp->t_termios, sizeof(struct termios));
+ /* copy the whole termios in as the first "first open" won't
+ * do it since the speed != 0 */
+ cs->cs_defspeed = zs_getspeed(cs);
+ tp->t_ispeed = cs->cs_defspeed;
+ tp->t_ospeed = cs->cs_defspeed;
+ (void) zsparam(tp, &tp->t_termios);
+ } else {
+ /* Not the console; may need reset. */
+ int reset, s;
+ reset = (channel == 0) ?
+ ZSWR9_A_RESET : ZSWR9_B_RESET;
+ s = splzs();
+ zs_write_reg(cs, 9, reset);
+ splx(s);
+ }
+
+ /*
+ * Initialize state of modem control lines (DTR).
+ * If softcar is set, turn on DTR now and leave it.
+ * otherwise, turn off DTR now, and raise in open.
+ * (Keeps modem from answering too early.)
+ */
+ zs_modem(zst, (zst->zst_swflags & TIOCFLAG_SOFTCAR) ? 1 : 0);
+}
+
+
+/*
+ * Return pointer to our tty.
+ */
+struct tty *
+zstty(dev)
+ dev_t dev;
+{
+ struct zstty_softc *zst;
+ int unit = minor(dev);
+
+#ifdef DIAGNOSTIC
+ if (unit >= zstty_cd.cd_ndevs)
+ panic("zstty");
+#endif
+ zst = zstty_cd.cd_devs[unit];
+ return (zst->zst_tty);
+}
+
+
+/*
+ * Open a zs serial (tty) port.
+ */
+int
+zsopen(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ register struct tty *tp;
+ register struct zs_chanstate *cs;
+ struct zstty_softc *zst;
+ int error, s, unit;
+
+ unit = minor(dev);
+ if (unit >= zstty_cd.cd_ndevs)
+ return (ENXIO);
+ zst = zstty_cd.cd_devs[unit];
+ if (zst == NULL)
+ return (ENXIO);
+ tp = zst->zst_tty;
+ cs = zst->zst_cs;
+
+#ifdef ZSTTYDEBUG
+ zsprintf("zs_open to channel at %p\n",cs->cs_reg_csr);
+#endif
+
+ /* If KGDB took the line, then tp==NULL */
+ if (tp == NULL)
+ return (EBUSY);
+
+ /* It's simpler to do this up here. */
+ if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE))
+ == (TS_ISOPEN | TS_XCLUDE))
+ && (p->p_ucred->cr_uid != 0) )
+ {
+ return (EBUSY);
+ }
+
+ s = spltty();
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ if ((tp->t_ispeed == 0) || (zst->zst_resetdef)) {
+ /* First open. Executed if either the tty
+ * was uninitialized, or if we choose to
+ * reset defaults w/ each open. */
+ bcopy(&zst->zst_termios, &tp->t_termios,
+ sizeof(struct termios));
+ if (zst->zst_swflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (zst->zst_swflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (zst->zst_swflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ }
+ (void) zsparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+ /* Flush any pending input. */
+ zst->zst_rbget = zst->zst_rbput;
+ zs_iflush(cs); /* XXX */
+ /* Turn on DTR */
+ zs_modem(zst, 1);
+ if (zst->zst_swflags & TIOCFLAG_SOFTCAR) {
+ tp->t_state |= TS_CARR_ON;
+ }
+ }
+ error = 0;
+
+ /* Wait for carrier. */
+#ifdef ZSTTYDEBUG
+ zsprintf("wait for carrier...\n");
+#endif
+ for (;;) {
+
+ if (zst->zst_hwflags & ZS_HWFLAG_IGDCD) {
+ tp->t_state |= TS_CARR_ON;
+ break;
+ }
+
+ /* Might never get status intr if carrier already on. */
+ cs->cs_rr0 = zs_read_csr(cs);
+ if (cs->cs_rr0 & ZSRR0_DCD) {
+ tp->t_state |= TS_CARR_ON;
+ break;
+ }
+
+ if ((tp->t_state & TS_CARR_ON) ||
+ (tp->t_cflag & CLOCAL) ||
+ (flags & O_NONBLOCK) )
+ {
+ break;
+ }
+
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)&tp->t_rawq,
+ TTIPRI | PCATCH, ttopen, 0);
+ if (error) {
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ /* Never get here with softcar */
+ zs_modem(zst, 0);
+ tp->t_state &= ~TS_WOPEN;
+ ttwakeup(tp);
+ }
+ break;
+ }
+ }
+
+ splx(s);
+
+#ifdef ZSTTYDEBUG
+ zsprintf("...carrier %s\n",
+ (tp->t_state & TS_CARR_ON) ? "on" : "off");
+#endif
+
+ if (error == 0)
+ error = linesw[tp->t_line].l_open(dev, tp);
+
+ return (error);
+}
+
+/*
+ * Close a zs serial port.
+ */
+int
+zsclose(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ struct zstty_softc *zst;
+ register struct zs_chanstate *cs;
+ register struct tty *tp;
+ int hup;
+
+#ifdef ZSTTYDEBUG
+ zsprintf("zs_close\n");
+#endif
+
+ zst = zstty_cd.cd_devs[minor(dev)];
+ cs = zst->zst_cs;
+ tp = zst->zst_tty;
+
+ /* XXX This is for cons.c. */
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flags);
+ hup = tp->t_cflag & HUPCL;
+ if (zst->zst_swflags & TIOCFLAG_SOFTCAR)
+ hup = 0;
+ if (hup) {
+ zs_modem(zst, 0);
+ /* hold low for 1 second */
+ (void) tsleep((caddr_t)cs, TTIPRI, ttclos, hz);
+ }
+ if (cs->cs_creg[5] & ZSWR5_BREAK) {
+ zs_break(cs, 0);
+ }
+ /* XXX - turn off interrupts? */
+
+ ttyclose(tp);
+ return (0);
+}
+
+/*
+ * Read/write zs serial port.
+ */
+int
+zsread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register struct zstty_softc *zst;
+ register struct tty *tp;
+
+ zst = zstty_cd.cd_devs[minor(dev)];
+ tp = zst->zst_tty;
+ return (linesw[tp->t_line].l_read(tp, uio, flags));
+}
+
+int
+zswrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register struct zstty_softc *zst;
+ register struct tty *tp;
+
+ zst = zstty_cd.cd_devs[minor(dev)];
+ tp = zst->zst_tty;
+ return (linesw[tp->t_line].l_write(tp, uio, flags));
+}
+
+#define TIOCFLAG_ALL (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | \
+ TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF )
+
+int
+zsioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ register struct zstty_softc *zst;
+ register struct zs_chanstate *cs;
+ register struct tty *tp;
+ register int error, tmp;
+
+ zst = zstty_cd.cd_devs[minor(dev)];
+ cs = zst->zst_cs;
+ tp = zst->zst_tty;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+ error = zsmdioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ switch (cmd) {
+
+ case TIOCSBRK:
+ zs_break(cs, 1);
+ break;
+
+ case TIOCCBRK:
+ zs_break(cs, 0);
+ break;
+
+ case TIOCGFLAGS:
+ *(int *)data = zst->zst_swflags;
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+ tmp = *(int *)data;
+ /* Check for random bits... */
+ if (tmp & ~TIOCFLAG_ALL)
+ return(EINVAL);
+ /* Silently enforce softcar on the console. */
+ if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)
+ tmp |= TIOCFLAG_SOFTCAR;
+ /* These flags take effect during open. */
+ zst->zst_swflags = tmp;
+ break;
+
+ case TIOCSDTR:
+ zs_modem(zst, 1);
+ break;
+
+ case TIOCCDTR:
+ zs_modem(zst, 0);
+ break;
+
+#if 0
+ case SetSafeOpen:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+ zst->zst_resetdef = 1;
+ break;
+
+ case ClearSafeOpen:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+ zst->zst_resetdef = 0;
+ break;
+
+ case SetOpenDefaults:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+ bcopy(&tp->t_termios, &zst->zst_termios, \
+ sizeof(struct termios));
+ break;
+#endif
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMGET:
+ default:
+ return (ENOTTY);
+ }
+ return (0);
+}
+
+/*
+ * Start or restart transmission.
+ */
+static void
+zsstart(tp)
+ register struct tty *tp;
+{
+ register struct zstty_softc *zst;
+ register struct zs_chanstate *cs;
+ register int s, nch;
+
+ zst = zstty_cd.cd_devs[minor(tp->t_dev)];
+ cs = zst->zst_cs;
+
+ s = spltty();
+
+ /*
+ * If currently active or delaying, no need to do anything.
+ */
+ if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
+ goto out;
+
+ /*
+ * If under CRTSCTS hfc and halted, do nothing
+ */
+ if (tp->t_cflag & CRTSCTS)
+ if (zst->zst_tx_stopped)
+ goto out;
+
+ /*
+ * If there are sleepers, and output has drained below low
+ * water mark, awaken.
+ */
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+
+ nch = ndqb(&tp->t_outq, 0); /* XXX */
+ if (nch) {
+ register char *p = tp->t_outq.c_cf;
+
+ /* mark busy, enable tx done interrupts, & send first byte */
+ tp->t_state |= TS_BUSY;
+ (void) splzs();
+
+ cs->cs_preg[1] |= ZSWR1_TIE;
+ cs->cs_creg[1] = cs->cs_preg[1];
+ 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 {
+ /*
+ * Nothing to send, turn off transmit done interrupts.
+ * This is useful if something is doing polled output.
+ */
+ (void) splzs();
+ cs->cs_preg[1] &= ~ZSWR1_TIE;
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+out:
+ splx(s);
+}
+
+/*
+ * Stop output, e.g., for ^S or output flush.
+ */
+int
+zsstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ register struct zstty_softc *zst;
+ register struct zs_chanstate *cs;
+ register int s;
+
+ zst = zstty_cd.cd_devs[minor(tp->t_dev)];
+ cs = zst->zst_cs;
+
+ s = splzs();
+ if (tp->t_state & TS_BUSY) {
+ /*
+ * Device is transmitting; must stop it.
+ */
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0; /* XXX */
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+#ifndef ZS_TOLERANCE
+#define ZS_TOLERANCE 50
+/* 5% in tenths of a % */
+#endif
+
+/*
+ * Search through the signal sources in the channel, and
+ * pick the best one for the baud rate requested. Return
+ * a -1 if not achievable in tolerance. Otherwise ret 0
+ * and fill in the values.
+ *
+ * This routine draws inspiration from the Atari port's zs.c
+ * driver in NetBSD1.1 which did the same type of source switching.
+ * Tolerance code inspired by comspeed routine in isa/com.c.
+ *
+ * By Bill Studenmund, 1996-05-12
+ */
+static int
+zsgetbaud(cs, rate, tc, rr4, rr11, rr14, source, sourceflag)
+ register struct zs_chanstate *cs;
+ register int *rate, *tc, *source, *sourceflag;
+ register u_char *rr4, *rr11, *rr14;
+{
+ int i, tc0, tc1, s, sf, rate0, rate1, err, tol;
+
+ s = -1; /* no valid source yet */
+ tol = ZS_TOLERANCE;
+
+ /*
+ * Step through all the sources and see which one matches
+ * the best. A source has to match BETTER than tol to be chosen.
+ * Thus if two sources give the same error, the first one will be
+ * chosen. Also, allow for the possability that one source might run
+ * both the BRG and the direct divider (i.e. RTxC).
+ */
+ for (i=0; i< cs->cs_clock_count; i++) {
+ if (cs->cs_clocks[i].clk <= 0)
+ continue; /* skip non-existant or bad clocks */
+ if (cs->cs_clocks[i].flags & ZSC_BRG) {
+ /* check out BRG at /16 */
+ tc1 = BPS_TO_TCONST(cs->cs_clocks[i].clk >> 4, rate[0]);
+ if (tc1 >= 0) {
+ rate1 = TCONST_TO_BPS(cs->cs_clocks[i].clk >> 4, tc1);
+ err = abs(((rate1 - rate[0])*1000)/rate[0]);
+ if (err < tol) {
+ tol = err;
+ s = i;
+ sf = cs->cs_clocks[i].flags & ~ZSC_DIV;
+ tc0 = tc1;
+ rate0 = rate1;
+ }
+ }
+ }
+ if (cs->cs_clocks[i].flags & ZSC_DIV) {
+ /*
+ * Check out either /1, /16, /32, or /64
+ * Note: for /1, you'd better be using a synchronized
+ * clock!
+ */
+ int b0 = cs->cs_clocks[i].clk, e0 = abs(b0-rate[0]);
+ int b1 = b0 >> 4, e1 = abs(b1-rate[0]);
+ int b2 = b1 >> 1, e2 = abs(b2-rate[0]);
+ int b3 = b2 >> 1, e3 = abs(b3-rate[0]);
+
+ if (e0 < e1 && e0 < e2 && e0 < e3) {
+ err = e0;
+ rate1 = b0;
+ tc1 = ZSWR4_CLK_X1;
+ } else if (e0 > e1 && e1 < e2 && e1 < e3) {
+ err = e1;
+ rate1 = b1;
+ tc1 = ZSWR4_CLK_X16;
+ } else if (e0 > e2 && e1 > e2 && e2 < e3) {
+ err = e2;
+ rate1 = b2;
+ tc1 = ZSWR4_CLK_X32;
+ } else {
+ err = e3;
+ rate1 = b3;
+ tc1 = ZSWR4_CLK_X64;
+ }
+
+ err = (err * 1000)/rate[0];
+ if (err < tol) {
+ tol = err;
+ s = i;
+ sf = cs->cs_clocks[i].flags & ~ZSC_BRG;
+ tc0 = tc1;
+ rate0 = rate1;
+ }
+ }
+ }
+#ifdef ZSTTYDEBUG
+ zsprintf("Checking for rate %d. Found source #%d.\n",rate[0], s);
+#endif
+ if (s == -1) return (-1);
+ /*
+ * Now we have a source, so set it up.
+ */
+ *source = s;
+ *sourceflag = sf;
+ rate[0] = rate0;
+ if (sf & ZSC_BRG) {
+ *rr4 = ZSWR4_CLK_X16;
+ *rr11= ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD;
+ if (sf & ZSC_PCLK) {
+ *rr14 = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK;
+ } else {
+ *rr14 = ZSWR14_BAUD_ENA;
+ }
+ *tc = tc0;
+ } else {
+ *rr4 = tc0;
+ if (sf & ZSC_RTXDIV) {
+ *rr11 = ZSWR11_RXCLK_RTXC | ZSWR11_TXCLK_RTXC;
+ } else {
+ *rr11 = ZSWR11_RXCLK_TRXC | ZSWR11_TXCLK_TRXC;
+ }
+ *rr14= 0;
+ *tc = 0xffff;
+ }
+#ifdef ZSTTYDEBUG
+ zsprintf("Rate is %7d, tc is %7d, source no. %2d, flags %4x\n", \
+ *rate, *tc, *source, *sourceflag);
+ zsprintf("Registers are: 4 %x, 11 %x, 14 %x\n\n", *rr4, *rr11, *rr14);
+#endif
+ return (0);
+}
+
+/*
+ * Set ZS tty parameters from termios.
+ * XXX - Should just copy the whole termios after
+ * making sure all the changes could be done.
+ * XXX - Only whack the UART when params change...
+ */
+static int
+zsparam(tp, t)
+ register struct tty *tp;
+ register struct termios *t;
+{
+ register struct zstty_softc *zst;
+ register struct zs_chanstate *cs;
+ register int s, cflag, hfc;
+ u_char tmp3, tmp4, tmp5, tmp11, tmp14;
+ int bps, tconst, src, srcflag;
+
+ zst = zstty_cd.cd_devs[minor(tp->t_dev)];
+ cs = zst->zst_cs;
+
+ bps = t->c_ospeed;
+ if (bps < 0 || (t->c_ispeed && t->c_ispeed != bps))
+ return (EINVAL);
+ if (bps == 0) {
+ /* stty 0 => drop DTR and RTS */
+ zs_modem(zst, 0);
+ return (0);
+ }
+ if (0 > zsgetbaud(cs, &bps, &tconst, &tmp4, &tmp11, &tmp14,
+ &src, &srcflag))
+ return (EINVAL);
+
+ tp->t_ispeed = tp->t_ospeed = bps;
+ cs->cs_psource = src;
+ cs->cs_pclk_flag = srcflag;
+
+ cflag = t->c_cflag;
+
+ /*
+ * Make sure we don't enable hfc on a signal line we're ignoring
+ *
+ * As we enable CTS interrupts only if we have CRTSCTS, this code
+ * also effectivly turns off ZSWR15_CTS_IE.
+ */
+ if (zst->zst_hwflags & ZS_HWFLAG_IGDCD)
+ cflag &= ~MDMBUF;
+ if (zst->zst_hwflags & ZS_HWFLAG_IGCTS)
+ cflag &= ~CRTSCTS;
+
+ tp->t_cflag = cflag;
+ /*
+ * Block interrupts so that state will not
+ * be altered until we are done setting it up.
+ */
+ s = splzs();
+
+ /*
+ * Initial values in cs_preg are set before
+ * our attach routine is called. The master
+ * interrupt enable is handled by zsc.c
+ */
+
+ cs->cs_preg[12] = tconst & 255;
+ cs->cs_preg[13] = tconst >> 8;
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ tmp3 = ZSWR3_RX_5;
+ tmp5 = ZSWR5_TX_5;
+ break;
+ case CS6:
+ tmp3 = ZSWR3_RX_6;
+ tmp5 = ZSWR5_TX_6;
+ break;
+ case CS7:
+ tmp3 = ZSWR3_RX_7;
+ tmp5 = ZSWR5_TX_7;
+ break;
+ case CS8:
+ default:
+ tmp3 = ZSWR3_RX_8;
+ tmp5 = ZSWR5_TX_8;
+ break;
+ }
+
+ cs->cs_preg[3] = tmp3 | ZSWR3_RX_ENABLE;
+ cs->cs_preg[5] = tmp5 | ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS;
+
+ tmp4 |= (cflag & CSTOPB ? ZSWR4_TWOSB : ZSWR4_ONESB);
+ if ((cflag & PARODD) == 0)
+ tmp4 |= ZSWR4_EVENP;
+ if (cflag & PARENB)
+ tmp4 |= ZSWR4_PARENB;
+ cs->cs_preg[4] = tmp4;
+
+ /*
+ * Output hardware flow control on the chip is horrendous:
+ * if carrier detect drops, the receiver is disabled and if
+ * CTS drops, the transmitter is stoped IN MID CHARACTER!
+ * Therefore, do not set the HFC bit, and instead use
+ * the status interrupts to detect CTS changes.
+ */
+ if (cflag & CRTSCTS) {
+ zst->zst_rbhiwat = zstty_rbuf_hiwat;
+ cs->cs_preg[15] |= ZSWR15_CTS_IE;
+ } else {
+ zst->zst_rbhiwat = zstty_rbuf_size; /* impossible value */
+ cs->cs_preg[15] &= ~ZSWR15_CTS_IE;
+ }
+ /* Shouldn't the zst_rbhiwat stuff be if (cflag & CHWFLOW) ? wrs */
+
+ /*
+ * Disable DCD interrupts if we've been told to ignore
+ * the DCD pin. Happens on mac68k because the input line for
+ * DCD can also be used as a clock input.
+ */
+ if (zst->zst_hwflags & ZS_HWFLAG_IGDCD)
+ cs->cs_preg[15] &= ~ZSWR15_DCD_IE;
+ else
+ cs->cs_preg[15] |= ZSWR15_DCD_IE;
+
+ /*
+ * now find out which line to change for input flow control.
+ * Important as some ports (mac68k) don't always have input
+ * flow control when they have output flow control (RTS actually
+ * controls buffers on the Xmitter output).
+ */
+ hfc = (cflag & CRTSCTS) ? 1 : 0;
+ hfc |= (cflag & MDMBUF) ? 2 : 0;
+
+ zst->zst_hwimask = zst->zst_hwimasks[hfc];
+ if ((zst->zst_rx_blocked) && (zst->zst_hwimask))
+ cs->cs_preg[5] &= ~zst->zst_hwimask;
+ /* make sure we enforce halted-ness */
+
+ /* XXX check for loss of output blocking if loosing hwi ability? */
+
+ /*
+ * If nothing is being transmitted, set up new current values,
+ * else mark them as pending.
+ */
+ if (cs->cs_heldchange == 0) {
+ if (tp->t_state & TS_BUSY) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 0xFF;
+ } else {
+ zs_loadchannelregs(cs);
+ }
+ }
+ splx(s);
+ /* check for ttstart if lost output flow control? XXX */
+ return (0);
+}
+
+/*
+ * Raise or lower modem control (DTR/RTS) signals. If a character is
+ * in transmission, the change is deferred.
+ */
+static void
+zs_modem(zst, onoff)
+ struct zstty_softc *zst;
+ int onoff;
+{
+ struct zs_chanstate *cs;
+ struct tty *tp;
+ int s, bis, and;
+
+ cs = zst->zst_cs;
+ tp = zst->zst_tty;
+
+ if (onoff) {
+ bis = ZSWR5_DTR | ZSWR5_RTS;
+ and = ~0;
+ } else {
+ bis = 0;
+ and = ~(ZSWR5_DTR | ZSWR5_RTS);
+ }
+ s = splzs();
+ cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and;
+ if (cs->cs_heldchange == 0) {
+ if (tp->t_state & TS_BUSY) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = (1<<5);
+ } else {
+ cs->cs_creg[5] = cs->cs_preg[5];
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
+ }
+ }
+ splx(s);
+}
+
+/*
+ * Try to block or unblock input using hardware flow-control.
+ * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
+ * if this function returns non-zero, the TS_TBLOCK flag will
+ * be set or cleared according to the "stop" arg passed.
+ */
+int
+zshwiflow(tp, stop)
+ struct tty *tp;
+ int stop;
+{
+ register struct zstty_softc *zst;
+ int s;
+
+ zst = zstty_cd.cd_devs[minor(tp->t_dev)];
+
+ /*
+ * This loop checks to see that we can in fact control input.
+ * If not, then do little except tell the upper layer the truth.
+ */
+ if (zst->zst_hwimask == 0)
+ if (stop)
+ return 0;
+ else
+ return 1; /* yes, w/o hwi we can unblock input. ;-) */
+
+ s = splzs();
+ if (stop) {
+ /*
+ * The tty layer is asking us to block input.
+ * If we already did it, just return TRUE.
+ */
+ if (zst->zst_rx_blocked)
+ goto out;
+ zst->zst_rx_blocked = 1;
+ z8530tty_stats.tty_block++;
+ } else {
+ /*
+ * The tty layer is asking us to resume input.
+ * The input ring is always empty by now.
+ */
+ zst->zst_rx_blocked = 0;
+ z8530tty_stats.tty_unblock++;
+ }
+ zs_hwiflow(zst, stop);
+ out:
+ splx(s);
+ return 1;
+}
+
+/*
+ * Internal version of zshwiflow
+ * called at splzs
+ */
+static void
+zs_hwiflow(zst, stop)
+ register struct zstty_softc *zst;
+ int stop;
+{
+ register struct zs_chanstate *cs;
+ register struct tty *tp;
+ register int bis, and;
+
+ cs = zst->zst_cs;
+ tp = zst->zst_tty;
+
+ if (stop) {
+ /* Block input (Lower RTS) */
+ bis = 0;
+ and = ~zst->zst_hwimask;
+ } else {
+ /* Unblock input (Raise RTS) */
+ bis = zst->zst_hwimask;
+ and = ~0;
+ }
+
+ cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and;
+ if (cs->cs_heldchange == 0) {
+ if (tp->t_state & TS_BUSY) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = (1<<5);
+ } else {
+ cs->cs_creg[5] = cs->cs_preg[5];
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
+ }
+ }
+}
+
+
+/****************************************************************
+ * Interface to the lower layer (zscc)
+ ****************************************************************/
+
+static void zstty_rxint __P((register struct zs_chanstate *));
+static void zstty_txint __P((register struct zs_chanstate *));
+static void zstty_stint __P((register struct zs_chanstate *));
+static void zsoverrun __P((struct zstty_softc *, long *, char *));
+static void zstty_softint __P((struct zs_chanstate *));
+/*
+ * XXX: need to do input flow-control to avoid ring overrun.
+ */
+
+/*
+ * receiver ready interrupt.
+ * called at splzs
+ */
+static void
+zstty_rxint(cs)
+ register struct zs_chanstate *cs;
+{
+ register struct zstty_softc *zst;
+ register int cc, put, put_next, ringmask;
+ register u_char c, rr0, rr1;
+ register u_short ch_rr1;
+
+ zst = cs->cs_private;
+ put = zst->zst_rbput;
+ ringmask = zst->zst_ringmask;
+
+nextchar:
+
+ /*
+ * 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);
+ ch_rr1 = (c << 8) | rr1;
+
+ if (ch_rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
+ /* Clear the receive error. */
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
+ }
+
+ /* XXX: Check for the stop character? */
+
+ zst->zst_rbuf[put] = ch_rr1;
+ put_next = (put + 1) & ringmask;
+
+ /* Would overrun if increment makes (put==get). */
+ if (put_next == zst->zst_rbget) {
+ zst->zst_rx_overrun = 1;
+ } else {
+ /* OK, really increment. */
+ put = put_next;
+ }
+
+ /* Keep reading until the FIFO is empty. */
+ rr0 = zs_read_csr(cs);
+ if (rr0 & ZSRR0_RX_READY)
+ goto nextchar;
+
+ /* Done reading. */
+ zst->zst_rbput = put;
+
+ /*
+ * If ring is getting too full, try to block input.
+ */
+ cc = put - zst->zst_rbget;
+ if (cc < 0)
+ cc += zstty_rbuf_size;
+ if ((cc > zst->zst_rbhiwat) && (zst->zst_rx_blocked == 0)) {
+ zst->zst_rx_blocked = 1;
+ zs_hwiflow(zst, 1);
+ z8530tty_stats.ring_block++;
+ }
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+/*
+ * transmitter ready interrupt. (splzs)
+ */
+static void
+zstty_txint(cs)
+ register struct zs_chanstate *cs;
+{
+ register struct zstty_softc *zst;
+ register int count;
+
+ zst = cs->cs_private;
+
+ /*
+ * If we suspended output for a "held" change,
+ * then handle that now and resume.
+ * Do flow-control changes ASAP.
+ * When the only change is for flow control,
+ * avoid hitting other registers, because that
+ * often makes the stupid zs drop input...
+ */
+ if (cs->cs_heldchange) {
+ if (cs->cs_heldchange == (1<<5)) {
+ /* Avoid whacking the chip... */
+ cs->cs_creg[5] = cs->cs_preg[5];
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
+ } else
+ zs_loadchannelregs(cs);
+ cs->cs_heldchange = 0;
+ count = zst->zst_heldtbc;
+ } else
+ count = zst->zst_tbc;
+
+ /*
+ * If our transmit buffer still has data,
+ * just send the next character.
+ */
+ if (count > 0) {
+ /* Send the next char. */
+ zst->zst_tbc = --count;
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tba++;
+ return;
+ }
+
+ zs_write_csr(cs, ZSWR0_RESET_TXINT);
+
+ /* Ask the softint routine for more output. */
+ zst->zst_tx_empty = 1;
+ cs->cs_softreq = 1;
+}
+
+/*
+ * status change interrupt. (splzs)
+ */
+static void
+zstty_stint(cs)
+ register struct zs_chanstate *cs;
+{
+ register struct zstty_softc *zst;
+ register struct tty *tp;
+ register u_char rr0;
+
+ zst = cs->cs_private;
+ tp = zst->zst_tty;
+
+ rr0 = zs_read_csr(cs);
+ zs_write_csr(cs, ZSWR0_RESET_STATUS);
+
+ /*
+ * 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_CONABRT))
+ {
+ zs_abort(zst);
+ return;
+ }
+
+ /*
+ * Need to handle CTS output flow control here.
+ * Output remains stopped as long as either the
+ * zst_tx_stopped or TS_TTSTOP flag is set.
+ * Never restart here; the softint routine will
+ * do that after things are ready to move.
+ */
+ if (((rr0 & ZSRR0_CTS) == 0) && (tp->t_cflag & CRTSCTS)) {
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0;
+ zst->zst_tx_stopped = 1;
+ }
+
+ cs->cs_rr0_new = rr0;
+ zst->zst_st_check = 1;
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+/*
+ * Print out a ring or fifo overrun error message.
+ */
+static void
+zsoverrun(zst, ptime, what)
+ struct zstty_softc *zst;
+ long *ptime;
+ char *what;
+{
+
+ if (*ptime != time.tv_sec) {
+ *ptime = time.tv_sec;
+ log(LOG_WARNING, "%s: %s overrun\n",
+ zst->zst_dev.dv_xname, what);
+ }
+}
+
+/*
+ * Software interrupt. Called at zssoft
+ *
+ * The main job to be done here is to empty the input ring
+ * by passing its contents up to the tty layer. The ring is
+ * always emptied during this operation, therefore the ring
+ * must not be larger than the space after "high water" in
+ * the tty layer, or the tty layer might drop our input.
+ *
+ * Note: an "input blockage" condition is assumed to exist if
+ * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
+ */
+static void
+zstty_softint(cs)
+ struct zs_chanstate *cs;
+{
+ register struct zstty_softc *zst;
+ register struct linesw *line;
+ register struct tty *tp;
+ register int get, c, s;
+ int ringmask, overrun;
+ register u_short ring_data;
+ register u_char rr0, delta, flag;
+
+ zst = cs->cs_private;
+ tp = zst->zst_tty;
+ line = &linesw[tp->t_line];
+ ringmask = zst->zst_ringmask;
+ overrun = 0;
+
+ /*
+ * Raise to tty priority while servicing the ring.
+ */
+ s = spltty();
+
+ if (zst->zst_rx_overrun) {
+ zst->zst_rx_overrun = 0;
+ zsoverrun(zst, &zst->zst_rotime, "ring");
+ }
+
+ /*
+ * Copy data from the receive ring into the tty layer.
+ */
+ get = zst->zst_rbget;
+ while (get != zst->zst_rbput) {
+ ring_data = zst->zst_rbuf[get];
+ get = (get + 1) & ringmask;
+
+ if (ring_data & ZSRR1_DO)
+ overrun++;
+ /* low byte of ring_data is rr1 */
+ c = (ring_data >> 8) & 0xff;
+ if (ring_data & ZSRR1_FE)
+ c |= TTY_FE;
+ if (ring_data & ZSRR1_PE)
+ c |= TTY_PE;
+
+ line->l_rint(c, tp);
+ }
+ zst->zst_rbget = get;
+
+ /*
+ * 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 (overrun) {
+ zsoverrun(zst, &zst->zst_fotime, "fifo");
+ }
+
+ /*
+ * We have emptied the input ring. Maybe unblock input.
+ * Note: an "input blockage" condition is assumed to exist
+ * when EITHER zst_rx_blocked or the TS_TBLOCK flag is set,
+ * so unblock here ONLY if TS_TBLOCK has not been set.
+ */
+ if (zst->zst_rx_blocked && ((tp->t_state & TS_TBLOCK) == 0)) {
+ (void) splzs();
+ zst->zst_rx_blocked = 0;
+ zs_hwiflow(zst, 0); /* unblock input */
+ z8530tty_stats.ring_unblock++;
+ (void) spltty();
+ }
+
+ /*
+ * Do any deferred work for status interrupts.
+ * The rr0 was saved in the h/w interrupt to
+ * avoid another splzs in here.
+ */
+ if (zst->zst_st_check) {
+ zst->zst_st_check = 0;
+
+ rr0 = cs->cs_rr0_new;
+ delta = rr0 ^ cs->cs_rr0;
+ cs->cs_rr0 = rr0;
+ if ((delta & ZSRR0_DCD) &&
+ ~(zst->zst_hwflags & ZS_HWFLAG_IGDCD)) {
+ c = ((rr0 & ZSRR0_DCD) != 0);
+ if ((tp->t_cflag & CHWFLOW) == CHWFLOW) {
+ flag = 1;
+ tp->t_cflag &= ~MDMBUF;
+ } else
+ flag = 0;
+ if (line->l_modem(tp, c) == 0)
+ zs_modem(zst, c);
+ if (flag)
+ tp->t_cflag |= MDMBUF;
+ /*
+ * The above trick hides MDMBUF from the tty layer
+ * if we also have CRTSCTS; Used as mac68k takes
+ * the two of them as meaning do CRTSCTS with DCD
+ * as the hwi line. Just CRTSCTS doesn't have a
+ * hwi line.
+ */
+ }
+ if ((delta & ZSRR0_CTS) && (tp->t_cflag & CRTSCTS)) {
+ /*
+ * Only do restart here. Stop is handled
+ * at the h/w interrupt level.
+ */
+ if (rr0 & ZSRR0_CTS) {
+ zst->zst_tx_stopped = 0;
+ tp->t_state &= ~TS_TTSTOP;
+ (*line->l_start)(tp);
+ }
+ }
+ }
+
+ if (zst->zst_tx_empty) {
+ zst->zst_tx_empty = 0;
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_state & TS_FLUSH)
+ tp->t_state &= ~TS_FLUSH;
+ else
+ ndflush(&tp->t_outq, zst->zst_tba -
+ (caddr_t) tp->t_outq.c_cf);
+ line->l_start(tp);
+ }
+
+ splx(s);
+}
+
+struct zsops zsops_tty = {
+ zstty_rxint, /* receive char available */
+ zstty_stint, /* external/status */
+ zstty_txint, /* xmit buffer empty */
+ zstty_softint, /* process software interrupt */
+};
+
+
diff --git a/sys/arch/mac68k/dev/z8530tty.h b/sys/arch/mac68k/dev/z8530tty.h
new file mode 100644
index 00000000000..b292b474edb
--- /dev/null
+++ b/sys/arch/mac68k/dev/z8530tty.h
@@ -0,0 +1,143 @@
+/* $OpenBSD: z8530tty.h,v 1.1 1996/05/26 19:02:13 briggs Exp $ */
+/* $NetBSD: z8530tty.h,v 1.1 1996/05/18 18:54:35 briggs Exp $ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (tty interface)
+ *
+ * This is the "slave" driver that will be attached to
+ * the "zsc" driver for plain "tty" async. serial lines.
+ */
+
+
+/*
+ * Allow the MD var.h to override the default CFLAG so that
+ * console messages during boot come out with correct parity.
+ */
+#ifndef ZSTTY_DEF_CFLAG
+#define ZSTTY_DEF_CFLAG TTYDEF_CFLAG
+#endif
+
+/*
+ * How many input characters we can buffer.
+ * The port-specific var.h may override this.
+ * Note: must be a power of two!
+ */
+#ifndef ZSTTY_RING_SIZE
+#define ZSTTY_RING_SIZE 2048
+#endif
+
+struct zstty_stats {
+ int ring_block;
+ int ring_unblock;
+ int tty_block;
+ int tty_unblock;
+};
+
+struct zstty_softc {
+ struct device zst_dev; /* required first: base device */
+ struct tty *zst_tty;
+ struct zs_chanstate *zst_cs;
+
+ int zst_hwflags; /* see z8530var.h */
+ int zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */
+
+ /*
+ * Printing an overrun error message often takes long enough to
+ * cause another overrun, so we only print one per second.
+ */
+ long zst_rotime; /* time of last ring overrun */
+ long zst_fotime; /* time of last fifo overrun */
+
+ /*
+ * The receive ring buffer.
+ */
+ int zst_rbget; /* ring buffer `get' index */
+ volatile int zst_rbput; /* ring buffer `put' index */
+ int zst_ringmask;
+ int zst_rbhiwat;
+
+ u_short *zst_rbuf; /* rr1, data pairs */
+
+ /*
+ * The transmit byte count and address are used for pseudo-DMA
+ * output in the hardware interrupt code. PDMA can be suspended
+ * to get pending changes done; heldtbc is used for this. It can
+ * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state.
+ */
+ int zst_tbc; /* transmit byte count */
+ caddr_t zst_tba; /* transmit buffer address */
+ int zst_heldtbc; /* held tbc while xmission stopped */
+
+ /* Flags to communicate with zstty_softint() */
+ volatile char zst_rx_blocked;
+ volatile char zst_rx_overrun;
+ volatile char zst_tx_stopped;
+ volatile char zst_tx_empty;
+ volatile char zst_st_check;
+ char pad[3];
+
+ struct termios zst_termios; /* default values for tty flags */
+#define zst_cflag zst_termios.c_cflag
+#define zst_iflag zst_termios.c_iflag
+#define zst_lflag zst_termios.c_lflag
+#define zst_oflag zst_termios.c_oflag
+#define zst_cc zst_termios.c_cc
+#define zst_ispeed zst_termios.c_ispeed
+#define zst_ospeed zst_termios.c_ospeed
+
+ char zst_resetdef; /* !=0 means reset tty defs. on open */
+ char zst_hwimask; /* bits to keep low for hwiflow */
+
+ char zst_hwimasks[4]; /* masks for hwiflow for HFC modes */
+};
+
+#define ZSTTY_RAW_CFLAG (CS8 | CREAD | HUPCL )
+#define ZSTTY_RAW_IFLAG (IXANY | IMAXBEL)
+#define ZSTTY_RAW_LFLAG (ECHOE|ECHOKE|ECHOCTL)
+#define ZSTTY_RAW_OFLAG (ONLCR | OXTABS)
+/* Above taken from looking at a tty after a stty raw */
diff --git a/sys/arch/mac68k/dev/zs.c b/sys/arch/mac68k/dev/zs.c
new file mode 100644
index 00000000000..3834dde9bc5
--- /dev/null
+++ b/sys/arch/mac68k/dev/zs.c
@@ -0,0 +1,752 @@
+/* $OpenBSD: zs.c,v 1.1 1996/05/26 19:02:14 briggs Exp $ */
+/* $NetBSD: zs.c,v 1.2 1996/05/23 05:18:48 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Gordon W. Ross
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon Ross
+ *
+ * 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.
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (machine-dependent part)
+ *
+ * Runs two serial lines per chip using slave drivers.
+ * Plain tty/async lines use the zs_async slave.
+ * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <dev/cons.h>
+#include "z8530reg.h"
+#include <machine/z8530var.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+
+/*
+ * XXX: Hard code this to make console init easier...
+ */
+#define NZSC 1 /* XXX */
+
+/*
+ * Define interrupt levels.
+ */
+#define ZSHARD_PRI 6 /* Wired on the CPU board... */
+#define ZSSOFT_PRI 3 /* Want tty pri (4) but this is OK. */
+
+/* The layout of this is hardware-dependent (padding, order). */
+struct zschan {
+ volatile u_char zc_csr; /* ctrl,status, and indirect access */
+ u_char zc_xxx0;
+ u_char zc_xxx1;
+ u_char zc_xxx2;
+ volatile u_char zc_data; /* data */
+ u_char zc_xxx3;
+ u_char zc_xxx4;
+ u_char zc_xxx5;
+};
+/*
+ * The zsdevice structure is not used on the mac68k port as the
+ * chip is wired up weird. Channel B & A are interspursed with
+ * the data & control bytes
+struct zsdevice {
+ /! Yes, they are backwards. !/
+ struct zschan zs_chan_b;
+ struct zschan zs_chan_a;
+};
+*/
+
+/* Saved PROM mappings */
+static char *zsaddr[NZSC]; /* See zs_init() */
+/* Flags from cninit() */
+static int zs_hwflags[NZSC][2];
+/* Default speed for each channel */
+static int zs_defspeed[NZSC][2] = {
+ { 9600, /* tty00 */
+ 9600 }, /* tty01 */
+};
+/* console stuff */
+void *zs_conschan = 0;
+int zs_consunit;
+/* device that the console is attached to--if serial. */
+dev_t mac68k_zsdev;
+/* Mac stuff, some vestages of old mac serial driver here */
+volatile unsigned char *sccA = 0;
+
+static struct zschan *zs_get_chan_addr __P((int zsc_unit, int channel));
+void zs_init __P((void));
+
+static struct zschan *
+zs_get_chan_addr(zsc_unit, channel)
+ int zsc_unit, channel;
+{
+ char *addr;
+ struct zschan *zc;
+
+ if (zsc_unit >= NZSC)
+ return NULL;
+ addr = zsaddr[zsc_unit];
+ if (addr == NULL)
+ return NULL;
+ if (channel == 0) {
+ zc = (struct zschan *)(addr +2);
+ /* handle the fact the ports are intertwined. */
+ } else {
+ zc = (struct zschan *)(addr);
+ }
+ return (zc);
+}
+
+
+/* Find PROM mappings (for console support). */
+static int zsinited = 0; /* 0 = not, 1 = inited, not attached, 2= attached */
+
+void
+zs_init()
+{
+ if ((zsinited == 2)&&(zsaddr[0] != (char *) sccA))
+ panic("Moved zs0 address after attached!");
+ zsaddr[0] = (char *) sccA;
+ zsinited = 1;
+ if (zs_conschan != 0){ /* we might have moved io under the console */
+ zs_conschan = zs_get_chan_addr(0, zs_consunit);
+ /* so recalc the console port */
+ }
+}
+
+
+/*
+ * Even though zsparam will set up the clock multiples, etc., we
+ * still set them here as: 1) mice & keyboards don't use zsparam,
+ * and 2) the console stuff uses these defaults before device
+ * attach.
+ */
+
+static u_char zs_init_reg[16] = {
+ 0, /* 0: CMD (reset, etc.) */
+ ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE,
+ 0x18 + ZSHARD_PRI, /* IVECT */
+ ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
+ ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
+ ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
+ 0, /* 6: TXSYNC/SYNCLO */
+ 0, /* 7: RXSYNC/SYNCHI */
+ 0, /* 8: alias for data port */
+ ZSWR9_MASTER_IE,
+ 0, /*10: Misc. TX/RX control bits */
+ ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
+ 14, /*12: BAUDLO (default=9600) */
+ 0, /*13: BAUDHI (default=9600) */
+ ZSWR14_BAUD_ENA,
+ ZSWR15_BREAK_IE | ZSWR15_DCD_IE | ZSWR15_CTS_IE,
+};
+
+
+/****************************************************************
+ * Autoconfig
+ ****************************************************************/
+
+/* Definition of the driver for autoconfig. */
+static int zsc_match __P((struct device *, void *, void *));
+static void zsc_attach __P((struct device *, struct device *, void *));
+static int zsc_print __P((void *aux, char *name));
+
+struct cfattach zsc_ca = {
+ sizeof(struct zsc_softc), zsc_match, zsc_attach
+};
+
+struct cfdriver zsc_cd = {
+ NULL, "zsc", DV_DULL
+};
+
+int zshard __P((void *));
+int zssoft __P((void *));
+
+
+/*
+ * Is the zs chip present?
+ */
+static int
+zsc_match(parent, vcf, aux)
+ struct device *parent;
+ void *vcf;
+ void *aux;
+{
+ return 1;
+}
+
+static int
+zsc_print(aux, name)
+ void *aux;
+ char *name;
+{
+ struct zsc_attach_args *args = aux;
+
+ if (name != NULL)
+ printf("%s: ", name);
+
+ if (args->channel != -1)
+ printf(" channel %d", args->channel);
+
+ return UNCONF;
+}
+
+/*
+ * Attach a found zs.
+ *
+ * Match slave number to zs unit number, so that misconfiguration will
+ * not set up the keyboard as ttya, etc.
+ */
+static void
+zsc_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct zsc_softc *zsc = (void *) self;
+ struct zsc_attach_args zsc_args;
+ volatile struct zschan *zc;
+ struct zs_chanstate *cs;
+ int zsc_unit, channel;
+ int reset, s, chip;
+
+ if (!zsinited) zs_init();
+ zsinited = 2;
+
+ zsc_unit = zsc->zsc_dev.dv_unit;
+
+ /* Make sure everything's inited ok. */
+ if (zsaddr[zsc_unit] == NULL)
+ panic("zs_attach: zs%d not mapped\n", zsc_unit);
+
+ /*
+ * Initialize software state for each channel.
+ */
+ for (channel = 0; channel < 2; channel++) {
+ cs = &zsc->zsc_cs[channel];
+
+ zc = zs_get_chan_addr(zsc_unit, channel);
+ cs->cs_reg_csr = &zc->zc_csr;
+ cs->cs_reg_data = &zc->zc_data;
+
+ cs->cs_channel = channel;
+ cs->cs_private = NULL;
+ cs->cs_ops = &zsops_null;
+
+ /* Define BAUD rate clock for the MI code. */
+ cs->cs_pclk_div16 = mac68k_machine.sccClkConst*2;
+ cs->cs_csource = 0;
+ cs->cs_psource = 0;
+
+ cs->cs_defspeed = zs_defspeed[zsc_unit][channel];
+
+ bcopy(zs_init_reg, cs->cs_creg, 16);
+ bcopy(zs_init_reg, cs->cs_preg, 16);
+
+ /*
+ * Clear the master interrupt enable.
+ * The INTENA is common to both channels,
+ * so just do it on the A channel.
+ */
+ if (channel == 0) {
+ zs_write_reg(cs, 9, 0);
+
+ chip = zs_checkchip(cs);
+ printf(" chip type %d \n",chip);
+ }
+ cs->cs_chip = chip;
+
+ /*
+ * Look for a child driver for this channel.
+ * The child attach will setup the hardware.
+ */
+ zsc_args.channel = channel;
+ zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
+ if (!config_found(self, (void *) &zsc_args, zsc_print)) {
+ /* No sub-driver. Just reset it. */
+ reset = (channel == 0) ?
+ ZSWR9_A_RESET : ZSWR9_B_RESET;
+ s = splzs();
+ zs_write_reg(cs, 9, reset);
+ splx(s);
+ }
+ }
+
+ /*
+ * Set the master interrupt enable and interrupt vector.
+ * (common to both channels, do it on A)
+ */
+ cs = &zsc->zsc_cs[0];
+ s = splzs();
+ /* interrupt vector */
+ zs_write_reg(cs, 2, zs_init_reg[2]);
+ /* master interrupt control (enable) */
+ zs_write_reg(cs, 9, zs_init_reg[9]);
+ splx(s);
+}
+
+void
+zstty_mdattach(zsc, zst, cs, tp)
+ struct zsc_softc *zsc;
+ struct zstty_softc *zst;
+ struct zs_chanstate *cs;
+ struct tty *tp;
+{
+ zst->zst_resetdef = 0;
+ cs->cs_clock_count = 3; /* internal + externals */
+ cs->cs_cclk_flag = 0; /* Not doing anything fancy by default */
+ cs->cs_pclk_flag = 0;
+ cs->cs_clocks[0].clk = mac68k_machine.sccClkConst*32;
+ cs->cs_clocks[0].flags = ZSC_RTXBRG; /* allowing divide by 16 will
+ melt the driver! */
+ cs->cs_clocks[1].clk = 0;
+ cs->cs_clocks[1].flags = ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
+ cs->cs_clocks[2].clk = 0;
+ cs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
+
+ /* For the mac, we have rtscts = check CTS for output control, no
+ * input control. mdmbuf means check DCD for output, and use DTR
+ * for input control. mdmbuf & rtscts means use CTS for output
+ * control, and DTR for input control. */
+
+ zst->zst_hwimasks[1] = 0;
+ zst->zst_hwimasks[2] = ZSWR5_DTR;
+ zst->zst_hwimasks[3] = ZSWR5_DTR;
+}
+
+int
+zsmdioctl(tp, com, data, flag, p)
+ struct tty *tp;
+ u_long com;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ return (-1);
+}
+
+void
+zsmd_setclock(cs)
+ struct zs_chanstate *cs;
+{
+ if (cs->cs_pclk_flag & ZSC_EXTERN) {
+ /* XXX need to set the via! */
+ }
+}
+
+int
+zshard(arg)
+ void *arg;
+{
+ struct zsc_softc *zsc;
+ int unit, rval;
+#ifdef ZSMACDEBUG
+ itecnputc(mac68k_zsdev, 'Z');
+#endif
+
+ rval = 0;
+ unit = zsc_cd.cd_ndevs;
+ while (--unit >= 0) {
+ zsc = zsc_cd.cd_devs[unit];
+ if (zsc != NULL) {
+ rval |= zsc_intr_hard(zsc);
+ }
+ }
+#ifdef ZSMACDEBUG
+ itecnputc(mac68k_zsdev, '\n');
+#endif
+ return (rval);
+}
+
+int zssoftpending;
+
+void
+zsc_req_softint(zsc)
+ struct zsc_softc *zsc;
+{
+ if (zssoftpending == 0) {
+ /* We are at splzs here, so no need to lock. */
+ zssoftpending = ZSSOFT_PRI;
+ /* isr_soft_request(ZSSOFT_PRI); */
+ setsoftserial();
+ }
+}
+
+int
+zssoft(arg)
+ void *arg;
+{
+ struct zsc_softc *zsc;
+ int unit;
+
+ /* This is not the only ISR on this IPL. */
+ if (zssoftpending == 0)
+ return (0);
+
+ /*
+ * The soft intr. bit will be set by zshard only if
+ * the variable zssoftpending is zero. The order of
+ * these next two statements prevents our clearing
+ * the soft intr bit just after zshard has set it.
+ */
+/* isr_soft_clear(ZSSOFT_PRI); */
+ zssoftpending = 0;
+
+ /* Do ttya/ttyb first, because they go faster. */
+ unit = zsc_cd.cd_ndevs;
+ while (--unit >= 0) {
+ zsc = zsc_cd.cd_devs[unit];
+ if (zsc != NULL) {
+ (void) zsc_intr_soft(zsc);
+ }
+ }
+ return (1);
+}
+
+
+/*
+ * Read or write the chip with suitable delays.
+ */
+#define ZS_DELAY()
+/*
+ * MacII hardware has the delay built in. No need for extra delay. :-)
+ */
+
+u_char
+zs_read_reg(cs, reg)
+ struct zs_chanstate *cs;
+ u_char reg;
+{
+ u_char val;
+
+ *cs->cs_reg_csr = reg;
+ ZS_DELAY();
+ val = *cs->cs_reg_csr;
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_reg(cs, reg, val)
+ struct zs_chanstate *cs;
+ u_char reg, val;
+{
+ *cs->cs_reg_csr = reg;
+ ZS_DELAY();
+ *cs->cs_reg_csr = val;
+ ZS_DELAY();
+}
+
+u_char zs_read_csr(cs)
+ struct zs_chanstate *cs;
+{
+ register u_char v;
+
+ v = (*cs->cs_reg_csr) ^ ZSRR0_CTS;
+ /* make up for the fact CTS is wired backwards */
+ ZS_DELAY();
+ return v;
+}
+
+u_char zs_read_data(cs)
+ struct zs_chanstate *cs;
+{
+ register u_char v;
+
+ v = *cs->cs_reg_data;
+ ZS_DELAY();
+ return v;
+}
+
+void zs_write_csr(cs, val)
+ struct zs_chanstate *cs;
+ u_char val;
+{
+ *cs->cs_reg_csr = val;
+ ZS_DELAY();
+}
+
+void zs_write_data(cs, val)
+ struct zs_chanstate *cs;
+ u_char val;
+{
+ *cs->cs_reg_data = val;
+ ZS_DELAY();
+}
+
+/****************************************************************
+ * Console support functions (Originally Sun3 specific!)
+ * Now works w/ just mac68k port!
+ ****************************************************************/
+
+#define zscnpollc nullcnpollc
+cons_decl(zs);
+
+static void zs_putc __P((register volatile struct zschan *, int));
+static int zs_getc __P((register volatile struct zschan *));
+static void zscnsetup __P((void));
+extern int zsopen __P(( dev_t dev, int flags, int mode, struct proc *p));
+
+/*
+ * Console functions.
+ */
+
+/*
+ * This code modled after the zs_setparam routine in zskgdb
+ * It sets the console unit to a known state so we can output
+ * correctly.
+ */
+static void
+zscnsetup()
+{
+ struct zs_chanstate cs;
+ struct zschan *zc;
+ int tconst, s;
+
+ /* Setup temporary chanstate. */
+ bzero((caddr_t)&cs, sizeof(cs));
+ zc = zs_conschan;
+ cs.cs_reg_csr = &zc->zc_csr;
+ cs.cs_reg_data = &zc->zc_data;
+ cs.cs_channel = zs_consunit;
+
+ bcopy(zs_init_reg, cs.cs_preg, 16);
+ tconst = BPS_TO_TCONST(mac68k_machine.sccClkConst*2, zs_defspeed[0][zs_consunit]);
+ cs.cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
+ cs.cs_preg[1] = 0; /* don't enable interrupts */
+ cs.cs_preg[12] = tconst;
+ cs.cs_preg[13] = tconst >> 8;
+
+ s = splhigh();
+ zs_loadchannelregs(&cs);
+ splx(s);
+}
+
+/*
+ * zscnprobe is the routine which gets called as the kernel is trying to
+ * figure out where the console should be. Each io driver which might
+ * be the console (as defined in mac68k/conf.c) gets probed. The probe
+ * fills in the consdev structure. Important parts are the device #,
+ * and the console priority. Values are CN_DEAD (don't touch me),
+ * CN_NORMAL (I'm here, but elsewhere might be better), CN_INTERNAL
+ * (the video, better than CN_NORMAL), and CN_REMOTE (pick me!)
+ *
+ * As the mac's a bit different, we do extra work here. We mainly check
+ * to see if we have serial echo going on, and if the tty's are supposed
+ * to default to raw or not.
+ */
+void
+zscnprobe(struct consdev * cp)
+{
+ extern u_long IOBase;
+ int maj, unit;
+
+ for (maj = 0; maj < nchrdev; maj++) {
+ if (cdevsw[maj].d_open == zsopen) {
+ break;
+ }
+ }
+ if (maj == nchrdev) {
+ /* no console entry for us */
+ if (mac68k_machine.serial_boot_echo) {
+ mac68k_set_io_offsets(IOBase);
+ zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
+ zs_consunit = 1;
+ zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE;
+ zs_init();
+ zscnsetup();
+ }
+ return;
+ }
+
+ cp->cn_pri = CN_NORMAL; /* Lower than CN_INTERNAL */
+ if (mac68k_machine.serial_console != 0) {
+ cp->cn_pri = CN_REMOTE; /* Higher than CN_INTERNAL */
+ mac68k_machine.serial_boot_echo =0;
+ }
+
+ unit = (mac68k_machine.serial_console == 1) ? 0 : 1;
+ zs_consunit = unit;
+
+ mac68k_zsdev = cp->cn_dev = makedev(maj, unit);
+
+ if (mac68k_machine.serial_boot_echo) {
+ /*
+ * at this point, we know that we don't have a serial
+ * console, but are doing echo
+ */
+ mac68k_set_io_offsets(IOBase);
+ zs_conschan = (struct zschan *) -1; /* dummy flag for zs_init() */
+ zs_consunit = 1;
+ zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE;
+ zs_init();
+ zscnsetup();
+ }
+ return;
+}
+
+void
+zscninit(struct consdev * cp)
+{
+ extern u_long IOBase;
+ int chan = minor(cp->cn_dev & 1);
+
+ mac68k_set_io_offsets(IOBase);
+ zs_conschan = (struct zschan *) -1;
+ zs_consunit = chan;
+ zs_hwflags[0][zs_consunit] = ZS_HWFLAG_CONSOLE | ZS_HWFLAG_CONABRT;
+ zs_init();
+ /*
+ * zsinit will set up the addresses of the scc. It will also, if
+ * zs_conschan != 0, calculate the new address of the conschan for
+ * unit zs_consunit. So zs_init implicitly sets zs_conschan to the right
+ * number. :-)
+ */
+ zscnsetup();
+ printf("\nNetBSD/mac68k console\n");
+}
+
+
+/*
+ * Polled input char.
+ */
+static int
+zs_getc(zc)
+ register volatile struct zschan *zc;
+{
+ register int s, c, rr0;
+
+ s = splhigh();
+ /* Wait for a character to arrive. */
+ do {
+ rr0 = zc->zc_csr;
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_RX_READY) == 0);
+
+ c = zc->zc_data;
+ ZS_DELAY();
+ splx(s);
+
+ /*
+ * This is used by the kd driver to read scan codes,
+ * so don't translate '\r' ==> '\n' here...
+ */
+ return (c);
+}
+
+/*
+ * Polled output char.
+ */
+static void
+zs_putc(zc, c)
+ register volatile struct zschan *zc;
+ int c;
+{
+ register int s, rr0;
+ register long wait = 0;
+
+ s = splhigh();
+ /* Wait for transmitter to become ready. */
+ do {
+ rr0 = zc->zc_csr;
+ ZS_DELAY();
+ } while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000));
+
+ if ((rr0 & ZSRR0_TX_READY) != 0) {
+ zc->zc_data = c;
+ ZS_DELAY();
+ }
+ splx(s);
+}
+
+
+/*
+ * Polled console input putchar.
+ */
+int
+zscngetc(dev)
+ dev_t dev;
+{
+ register volatile struct zschan *zc = zs_conschan;
+ register int c;
+
+ c = zs_getc(zc);
+ return (c);
+}
+
+/*
+ * Polled console output putchar.
+ */
+void
+zscnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ register volatile struct zschan *zc = zs_conschan;
+
+ zs_putc(zc, c);
+}
+
+
+
+/*
+ * Handle user request to enter kernel debugger.
+ */
+void
+zs_abort(zst)
+ register struct zstty_softc *zst;
+{
+ register volatile struct zschan *zc = zs_conschan;
+ int rr0;
+ register long wait = 0;
+
+ /* Wait for end of break to avoid PROM abort. */
+ /* XXX - Limit the wait? */
+ do {
+ rr0 = zc->zc_csr;
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_BREAK) && (wait++ < ZSABORT_DELAY));
+
+ if (wait > ZSABORT_DELAY) {
+ if (zst != NULL) zst->zst_hwflags &= ~ZS_HWFLAG_CONABRT;
+ /* If we time out, turn off the abort ability! */
+ }
+
+ /* XXX - Always available, but may be the PROM monitor. */
+ Debugger();
+}