summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/sparc/conf/GENERIC7
-rw-r--r--sys/arch/sparc/conf/GENERIC_SCSI39
-rw-r--r--sys/arch/sparc/dev/spif.c1047
-rw-r--r--sys/arch/sparc/dev/spifreg.h298
-rw-r--r--sys/arch/sparc/dev/spifvar.h81
-rw-r--r--sys/arch/sparc/include/conf.h5
-rw-r--r--sys/arch/sparc/sparc/conf.c8
7 files changed, 1449 insertions, 6 deletions
diff --git a/sys/arch/sparc/conf/GENERIC b/sys/arch/sparc/conf/GENERIC
index a929a8d42ac..4994961f9ba 100644
--- a/sys/arch/sparc/conf/GENERIC
+++ b/sys/arch/sparc/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.35 1998/12/29 09:33:35 deraadt Exp $
+# $OpenBSD: GENERIC,v 1.36 1999/02/01 00:30:42 jason Exp $
# $NetBSD: GENERIC,v 1.48 1997/08/23 19:19:01 mjacob Exp $
# Machine architecture; required by config(8)
@@ -99,6 +99,11 @@ magma* at sbus? slot ? offset ? # magma serial cards
mtty* at magma?
mbpp* at magma?
+# SUNW,spif serial/parallel port devices
+spif* at sbus? slot ? offset ? # spif serial cards
+stty* at spif?
+sbpp* at spif?
+
bpp* at sbus? slot ? offset ? # parallel port
#
diff --git a/sys/arch/sparc/conf/GENERIC_SCSI3 b/sys/arch/sparc/conf/GENERIC_SCSI3
index 882c83b569e..c382efd8390 100644
--- a/sys/arch/sparc/conf/GENERIC_SCSI3
+++ b/sys/arch/sparc/conf/GENERIC_SCSI3
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC_SCSI3,v 1.24 1998/10/19 05:43:29 jason Exp $
+# $OpenBSD: GENERIC_SCSI3,v 1.25 1999/02/01 00:30:42 jason Exp $
# $NetBSD: GENERIC,v 1.28.2.1 1996/07/02 23:55:22 jtc Exp $
# Machine architecture; required by config(8)
@@ -95,6 +95,13 @@ magma* at sbus? slot ? offset ? # magma serial cards
mtty* at magma?
mbpp* at magma?
+# SUNW,spif serial/parallel port devices
+spif* at sbus? slot ? offset ? # spif serial cards
+stty* at spif?
+sbpp* at spif?
+
+bpp* at sbus? slot ? offset ? # parallel port
+
#
# Note the flags on the esp entries below, that work around
# deficiencies in the current driver:
diff --git a/sys/arch/sparc/dev/spif.c b/sys/arch/sparc/dev/spif.c
new file mode 100644
index 00000000000..72463efa2ff
--- /dev/null
+++ b/sys/arch/sparc/dev/spif.c
@@ -0,0 +1,1047 @@
+/* $OpenBSD: spif.c,v 1.1 1999/02/01 00:30:42 jason Exp $ */
+
+/*
+ * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
+ * 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 Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for the SUNW,spif: 8 serial, 1 parallel sbus board
+ * based heavily on Iain Hibbert's driver for the MAGMA driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+
+#include <machine/autoconf.h>
+#include <sparc/cpu.h>
+#include <sparc/sparc/cpuvar.h>
+#include <sparc/dev/sbusvar.h>
+#include <sparc/dev/spifreg.h>
+#include <sparc/dev/spifvar.h>
+
+#if PIL_TTY == 1
+# define IE_MSOFT IE_L1
+#elif PIL_TTY == 4
+# define IE_MSOFT IE_L4
+#elif PIL_TTY == 6
+# define IE_MSOFT IE_L6
+#else
+# error "no suitable software interrupt bit"
+#endif
+
+/*
+ * useful macros
+ */
+#define SET(t, f) ((t) |= (f))
+#define CLR(t, f) ((t) &= ~(f))
+#define ISSET(t, f) ((t) & (f))
+
+int spifmatch __P((struct device *, void *, void *));
+void spifattach __P((struct device *, struct device *, void *));
+
+int sttymatch __P((struct device *, void *, void *));
+void sttyattach __P((struct device *, struct device *, void *));
+int sttyopen __P((dev_t, int, int, struct proc *));
+int sttyclose __P((dev_t, int, int, struct proc *));
+int sttyread __P((dev_t, struct uio *, int));
+int sttywrite __P((dev_t, struct uio *, int));
+int sttyioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
+int sttystop __P((struct tty *, int));
+int spifstcintr __P((void *));
+int spifsoftintr __P((void *));
+int stty_param __P((struct tty *, struct termios *));
+struct tty *sttytty __P((dev_t));
+int stty_modem_control __P((struct stty_port *, int, int));
+static __inline void spif_write_ccr __P((struct stcregs *, u_int8_t));
+int spif_compute_baud __P((speed_t, int, u_int8_t *, u_int8_t *));
+void stty_start __P((struct tty *));
+
+int sbppmatch __P((struct device *, void *, void *));
+void sbppattach __P((struct device *, struct device *, void *));
+int sbppopen __P((dev_t, int, int, struct proc *));
+int sbppclose __P((dev_t, int, int, struct proc *));
+int sbppread __P((dev_t, struct uio *, int));
+int sbppwrite __P((dev_t, struct uio *, int));
+int sbpp_rw __P((dev_t, struct uio *));
+int spifppcintr __P((void *));
+int sbppselect __P((dev_t, int, struct proc *));
+int sbppioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
+
+struct cfattach spif_ca = {
+ sizeof (struct spif_softc), spifmatch, spifattach
+};
+
+struct cfdriver spif_cd = {
+ NULL, "spif", DV_IFNET
+};
+
+struct cfattach stty_ca = {
+ sizeof(struct stty_softc), sttymatch, sttyattach
+};
+
+struct cfdriver stty_cd = {
+ NULL, "stty", DV_TTY
+};
+
+struct cfattach sbpp_ca = {
+ sizeof(struct sbpp_softc), sbppmatch, sbppattach
+};
+
+struct cfdriver sbpp_cd = {
+ NULL, "sbpp", DV_DULL
+};
+
+int
+spifmatch(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = aux;
+ register struct romaux *ra = &ca->ca_ra;
+
+ if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
+ strcmp("SUNW,spif", ra->ra_name))
+ return (0);
+ return (1);
+}
+
+void
+spifattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct spif_softc *sc = (struct spif_softc *)self;
+ struct confargs *ca = aux;
+ int stcpri, ppcpri;
+
+ if (ca->ca_ra.ra_nintr != 2) {
+ printf(": expected 2 interrupts, got %d\n",
+ ca->ca_ra.ra_nintr);
+ return;
+ }
+ stcpri = ca->ca_ra.ra_intr[SERIAL_INTR].int_pri;
+ ppcpri = ca->ca_ra.ra_intr[PARALLEL_INTR].int_pri;
+
+ if (ca->ca_ra.ra_nreg != 1) {
+ printf(": expected %d registers, got %d\n",
+ 1, ca->ca_ra.ra_nreg);
+ return;
+ }
+ sc->sc_regs = mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len);
+
+ sc->sc_node = ca->ca_ra.ra_node;
+
+ sc->sc_rev = getpropint(sc->sc_node, "revlev", 0);
+
+ sc->sc_osc = getpropint(sc->sc_node, "verosc", 0);
+ switch (sc->sc_osc) {
+ case SPIF_OSC10:
+ sc->sc_osc = 10;
+ break;
+ case SPIF_OSC9:
+ default:
+ sc->sc_osc = 9;
+ break;
+ }
+
+ sc->sc_nser = 8;
+ sc->sc_npar = 1;
+
+ sc->sc_rev2 = sc->sc_regs->stc.gfrcr;
+ sc->sc_regs->stc.gsvr = 0;
+
+ spif_write_ccr(&sc->sc_regs->stc, CD180_CCR_RESET | CD180_CCR_RESETALL);
+ while (sc->sc_regs->stc.gsvr != 0xff);
+ while (sc->sc_regs->stc.gfrcr != sc->sc_rev2);
+
+ sc->sc_regs->stc.gsvr = 0;
+ sc->sc_regs->stc.msmr = SPIF_MSMR;
+ sc->sc_regs->stc.tsmr = SPIF_TSMR;
+ sc->sc_regs->stc.rsmr = SPIF_RSMR;
+ sc->sc_regs->stc.pprh = SPIF_PPRH;
+ sc->sc_regs->stc.pprl = SPIF_PPRL;
+
+ printf(": rev %d chiprev %d osc %dMhz stcpri %d ppcpri %d softpri %d\n",
+ sc->sc_rev, sc->sc_rev2, sc->sc_osc, stcpri, ppcpri, PIL_TTY);
+
+ if (sc->sc_osc == 10)
+ sc->sc_osc = 10000000;
+ else
+ sc->sc_osc = 9830400;
+
+ (void)config_found(self, sttymatch, NULL);
+ (void)config_found(self, sbppmatch, NULL);
+
+ sc->sc_ppcih.ih_fun = spifppcintr;
+ sc->sc_ppcih.ih_arg = sc;
+ intr_establish(ppcpri, &sc->sc_ppcih);
+
+ sc->sc_stcih.ih_fun = spifstcintr;
+ sc->sc_stcih.ih_arg = sc;
+ intr_establish(stcpri, &sc->sc_stcih);
+
+ sc->sc_softih.ih_fun = spifsoftintr;
+ sc->sc_softih.ih_arg = sc;
+ intr_establish(PIL_TTY, &sc->sc_softih);
+}
+
+int
+sttymatch(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct spif_softc *sc = (struct spif_softc *)parent;
+
+ return (aux == sttymatch && sc->sc_ttys == NULL);
+}
+
+void
+sttyattach(parent, dev, aux)
+ struct device *parent, *dev;
+ void *aux;
+{
+ struct spif_softc *sc = (struct spif_softc *)parent;
+ struct stty_softc *ssc = (struct stty_softc *)dev;
+ int port;
+
+ sc->sc_ttys = ssc;
+
+ for (port = 0; port < sc->sc_nser; port++) {
+ struct stty_port *sp = &ssc->sc_port[port];
+ struct tty *tp;
+
+ tp = ttymalloc();
+ if (tp == NULL)
+ break;
+ tty_attach(tp);
+
+ tp->t_oproc = stty_start;
+ tp->t_param = stty_param;
+
+ sp->sp_tty = tp;
+ sp->sp_sc = sc;
+ sp->sp_channel = port;
+
+ sp->sp_rbuf = malloc(STTY_RBUF_SIZE, M_DEVBUF, M_NOWAIT);
+ if(sp->sp_rbuf == NULL)
+ break;
+
+ sp->sp_rend = sp->sp_rbuf + STTY_RBUF_SIZE;
+ }
+
+ ssc->sc_nports = port;
+
+ printf(": %d tty%s\n", port, port == 1 ? "" : "s");
+}
+
+int
+sttyopen(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ struct spif_softc *csc;
+ struct stty_softc *sc;
+ struct stty_port *sp;
+ struct tty *tp;
+ int card = SPIF_CARD(dev);
+ int port = SPIF_PORT(dev);
+ int s;
+
+ if (card >= stty_cd.cd_ndevs || card >= spif_cd.cd_ndevs)
+ return (ENXIO);
+
+ sc = stty_cd.cd_devs[card];
+ csc = spif_cd.cd_devs[card];
+ if (sc == NULL)
+ return (ENXIO);
+
+ if (port >= sc->sc_nports)
+ return (ENXIO);
+
+ sp = &sc->sc_port[port];
+ tp = sp->sp_tty;
+ tp->t_dev = dev;
+
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ SET(tp->t_state, TS_WOPEN);
+
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ if (ISSET(sp->sp_openflags, TIOCFLAG_CLOCAL))
+ SET(tp->t_cflag, CLOCAL);
+ if (ISSET(sp->sp_openflags, TIOCFLAG_CRTSCTS))
+ SET(tp->t_cflag, CRTSCTS);
+ if (ISSET(sp->sp_openflags, TIOCFLAG_MDMBUF))
+ SET(tp->t_cflag, MDMBUF);
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+
+ sp->sp_rput = sp->sp_rget = sp->sp_rbuf;
+
+ s = spltty();
+
+ csc->sc_regs->stc.car = sp->sp_channel;
+ spif_write_ccr(&csc->sc_regs->stc,
+ CD180_CCR_RESET | CD180_CCR_RESETCHAN);
+
+ stty_param(tp, &tp->t_termios);
+
+ ttsetwater(tp);
+
+ csc->sc_regs->stc.srer = CD180_SRER_DSR | CD180_SRER_RXD;
+
+ if (ISSET(sp->sp_openflags, TIOCFLAG_SOFTCAR) || sp->sp_carrier)
+ SET(tp->t_state, TS_CARR_ON);
+ else
+ CLR(tp->t_state, TS_CARR_ON);
+ }
+ else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
+ return (EBUSY);
+ } else {
+ s = spltty();
+ }
+
+ if (!ISSET(flags, O_NONBLOCK)) {
+ while (!ISSET(tp->t_cflag, CLOCAL) &&
+ !ISSET(tp->t_state, TS_CARR_ON)) {
+ int error;
+
+ SET(tp->t_state, TS_WOPEN);
+ error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
+ "sttycd", 0);
+ if (error != 0) {
+ splx(s);
+ CLR(tp->t_state, TS_WOPEN);
+ return (error);
+ }
+ }
+ }
+
+ splx(s);
+
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+sttyclose(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
+ struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
+ struct spif_softc *csc = sp->sp_sc;
+ struct tty *tp = sp->sp_tty;
+ int port = SPIF_PORT(dev);
+ int s;
+
+ (*linesw[tp->t_line].l_close)(tp, flags);
+ s = spltty();
+
+ if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)) {
+ csc->sc_regs->stc.car = port;
+ csc->sc_regs->stc.ccr = CD180_CCR_RESET | CD180_CCR_RESETCHAN;
+ }
+
+ splx(s);
+ ttyclose(tp);
+ return (0);
+}
+
+int
+sttyioctl(dev, cmd, data, flags, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flags;
+ struct proc *p;
+{
+ struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(dev)];
+ struct stty_port *sp = &stc->sc_port[SPIF_PORT(dev)];
+ struct spif_softc *sc = sp->sp_sc;
+ struct tty *tp = sp->sp_tty;
+ int error;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p);
+ if (error >= 0)
+ return (error);
+
+ error = ttioctl(tp, cmd, data, flags, p);
+ if (error >= 0)
+ return (error);
+
+ error = 0;
+
+ switch (cmd) {
+ case TIOCSBRK:
+ SET(sp->sp_flags, STTYF_SET_BREAK);
+ sc->sc_regs->stc.car = sp->sp_channel;
+ sc->sc_regs->stc.srer |= CD180_SRER_TXD;
+ break;
+ case TIOCCBRK:
+ SET(sp->sp_flags, STTYF_CLR_BREAK);
+ sc->sc_regs->stc.car = sp->sp_channel;
+ sc->sc_regs->stc.srer |= CD180_SRER_TXD;
+ break;
+ case TIOCSDTR:
+ stty_modem_control(sp, TIOCM_DTR, DMBIS);
+ break;
+ case TIOCCDTR:
+ stty_modem_control(sp, TIOCM_DTR, DMBIC);
+ break;
+ case TIOCMBIS:
+ stty_modem_control(sp, *((int *)data), DMBIS);
+ break;
+ case TIOCMBIC:
+ stty_modem_control(sp, *((int *)data), DMBIC);
+ break;
+ case TIOCMGET:
+ *((int *)data) = stty_modem_control(sp, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *((int *)data) = sp->sp_openflags;
+ break;
+ case TIOCSFLAGS:
+ if (suser(p->p_ucred, &p->p_acflag))
+ error = EPERM;
+ else
+ sp->sp_openflags = *((int *)data) &
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
+ TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
+ break;
+ default:
+ error = ENOTTY;
+ }
+
+ return (error);
+}
+
+int
+stty_modem_control(sp, bits, how)
+ struct stty_port *sp;
+ int bits, how;
+{
+ struct spif_softc *csc = sp->sp_sc;
+ struct tty *tp = sp->sp_tty;
+ int s, msvr;
+
+ s = spltty();
+ csc->sc_regs->stc.car = sp->sp_channel;
+
+ switch (how) {
+ case DMGET:
+ bits = TIOCM_LE;
+ if (sp->sp_dtr)
+ bits |= TIOCM_DTR;
+ msvr = csc->sc_regs->stc.msvr;
+ if (ISSET(msvr, CD180_MSVR_DSR))
+ bits |= TIOCM_DSR;
+ if (ISSET(msvr, CD180_MSVR_CD))
+ bits |= TIOCM_CD;
+ if (ISSET(msvr, CD180_MSVR_CTS))
+ bits |= TIOCM_CTS;
+ if (ISSET(msvr, CD180_MSVR_RTS))
+ bits |= TIOCM_RTS;
+ break;
+ case DMSET:
+ if (ISSET(bits, TIOCM_DTR)) {
+ sp->sp_dtr = 1;
+ csc->sc_regs->dtrlatch[sp->sp_channel] = 1;
+ }
+ else {
+ sp->sp_dtr = 0;
+ csc->sc_regs->dtrlatch[sp->sp_channel] = 0;
+ }
+ if (ISSET(bits, TIOCM_RTS))
+ csc->sc_regs->stc.msvr &= ~CD180_MSVR_RTS;
+ else
+ csc->sc_regs->stc.msvr |= CD180_MSVR_RTS;
+ break;
+ case DMBIS:
+ if (ISSET(bits, TIOCM_DTR)) {
+ sp->sp_dtr = 1;
+ csc->sc_regs->dtrlatch[sp->sp_channel] = 1;
+ }
+ if (ISSET(bits, TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS))
+ csc->sc_regs->stc.msvr &= ~CD180_MSVR_RTS;
+ break;
+ case DMBIC:
+ if (ISSET(bits, TIOCM_DTR)) {
+ sp->sp_dtr = 0;
+ csc->sc_regs->dtrlatch[sp->sp_channel] = 0;
+ }
+ if (ISSET(bits, TIOCM_RTS))
+ csc->sc_regs->stc.msvr |= CD180_MSVR_RTS;
+ break;
+ }
+
+ splx(s);
+ return (bits);
+}
+
+int
+stty_param(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct stty_softc *st = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
+ struct stty_port *sp = &st->sc_port[SPIF_PORT(tp->t_dev)];
+ struct spif_softc *sc = sp->sp_sc;
+ u_int8_t rbprl, rbprh, tbprl, tbprh;
+ int s, opt;
+
+ if (t->c_ospeed &&
+ spif_compute_baud(t->c_ospeed, sc->sc_osc, &tbprl, &tbprh))
+ return (EINVAL);
+
+ if (t->c_ispeed &&
+ spif_compute_baud(t->c_ispeed, sc->sc_osc, &rbprl, &rbprh))
+ return (EINVAL);
+
+ s = spltty();
+
+ /* hang up line if ospeed is zero, otherwise raise DTR */
+ stty_modem_control(sp, TIOCM_DTR,
+ (t->c_ospeed == 0 ? DMBIC : DMBIS));
+
+ sc->sc_regs->stc.car = sp->sp_channel;
+
+ opt = 0;
+ if (ISSET(t->c_cflag, PARENB)) {
+ opt |= CD180_COR1_PARMODE_NORMAL;
+ opt |= (ISSET(t->c_cflag, PARODD) ?
+ CD180_COR1_ODDPAR :
+ CD180_COR1_EVENPAR);
+ }
+ else
+ opt |= CD180_COR1_PARMODE_NO;
+
+ if (!ISSET(t->c_iflag, INPCK))
+ opt |= CD180_COR1_IGNPAR;
+
+ if (ISSET(t->c_cflag, CSTOPB))
+ opt |= CD180_COR1_STOP2;
+
+ switch (t->c_cflag & CSIZE) {
+ case CS5:
+ opt |= CD180_COR1_CS5;
+ break;
+ case CS6:
+ opt |= CD180_COR1_CS6;
+ break;
+ case CS7:
+ opt |= CD180_COR1_CS7;
+ break;
+ default:
+ opt |= CD180_COR1_CS8;
+ break;
+ }
+ sc->sc_regs->stc.cor1 = opt;
+
+ opt = CD180_COR2_ETC;
+ if (ISSET(t->c_cflag, CRTSCTS))
+ opt |= CD180_COR2_CTSAE;
+ sc->sc_regs->stc.cor2 = opt;
+
+ sc->sc_regs->stc.cor3 = STTY_RX_FIFO_THRESHOLD;
+
+ spif_write_ccr(&sc->sc_regs->stc, CD180_CCR_CORCHG |
+ CD180_CCR_CORCHG1 | CD180_CCR_CORCHG2 | CD180_CCR_CORCHG3);
+
+ sc->sc_regs->stc.schr1 = 0x11;
+ sc->sc_regs->stc.schr2 = 0x13;
+ sc->sc_regs->stc.schr3 = 0x11;
+ sc->sc_regs->stc.schr4 = 0x13;
+ sc->sc_regs->stc.rtpr = 0x28;
+
+ sc->sc_regs->stc.mcor1 = CD180_MCOR1_CDZD | STTY_RX_DTR_THRESHOLD;
+ sc->sc_regs->stc.mcor2 = CD180_MCOR2_CDOD;
+
+ if (t->c_ospeed) {
+ sc->sc_regs->stc.tbprh = tbprh;
+ sc->sc_regs->stc.tbprl = tbprl;
+ }
+
+ if (t->c_ispeed) {
+ sc->sc_regs->stc.rbprh = rbprh;
+ sc->sc_regs->stc.rbprl = rbprl;
+ }
+
+ spif_write_ccr(&sc->sc_regs->stc, CD180_CCR_CHANCTL |
+ CD180_CCR_CHAN_TXEN | CD180_CCR_CHAN_RXEN);
+
+ splx(s);
+ return (0);
+}
+
+int
+sttyread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
+ struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
+ struct tty *tp = sp->sp_tty;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
+}
+
+int
+sttywrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
+ struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
+ struct tty *tp = sp->sp_tty;
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
+}
+
+struct tty *
+sttytty(dev)
+ dev_t dev;
+{
+ struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)];
+ struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)];
+
+ return (sp->sp_tty);
+}
+
+int
+sttystop(tp, flags)
+ struct tty *tp;
+ int flags;
+{
+ struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
+ struct stty_port *sp = &sc->sc_port[SPIF_PORT(tp->t_dev)];
+ int s;
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY)) {
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ SET(sp->sp_flags, STTYF_STOP);
+ }
+ splx(s);
+ return (0);
+}
+
+void
+stty_start(tp)
+ struct tty *tp;
+{
+ struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)];
+ struct stty_port *sp = &stc->sc_port[SPIF_PORT(tp->t_dev)];
+ struct spif_softc *sc = sp->sp_sc;
+ int s;
+
+ s = spltty();
+
+ if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (ISSET(tp->t_state, TS_ASLEEP)) {
+ CLR(tp->t_state, TS_ASLEEP);
+ wakeup(&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ if (tp->t_outq.c_cc) {
+ sp->sp_txc = ndqb(&tp->t_outq, 0);
+ sp->sp_txp = tp->t_outq.c_cf;
+ SET(tp->t_state, TS_BUSY);
+ sc->sc_regs->stc.car = sp->sp_channel;
+ sc->sc_regs->stc.srer |= CD180_SRER_TXD;
+ }
+ }
+
+ splx(s);
+}
+
+int
+spifstcintr(vsc)
+ void *vsc;
+{
+ struct spif_softc *sc = (struct spif_softc *)vsc;
+ struct stty_port *sp;
+ u_int8_t channel, ar, *ptr;
+ int needsoft = 0, r = 0, i;
+
+ /*
+ * Receive data service request
+ * (also Receive error service request)
+ */
+ ar = sc->sc_regs->istc.rrar & 7;
+
+ switch (ar) {
+ case CD180_GSVR_RXGOOD:
+ r = 1;
+ channel = (sc->sc_regs->stc.gscr1 >> 2) & 7;
+ sp = &sc->sc_ttys->sc_port[channel];
+ ptr = sp->sp_rput;
+ for (i = sc->sc_regs->stc.rdcr; i > 0; i--) {
+ *ptr++ = 0;
+ *ptr++ = sc->sc_regs->stc.rdr;
+ if (ptr == sp->sp_rend)
+ ptr = sp->sp_rbuf;
+ if (ptr == sp->sp_rget) {
+ if (ptr == sp->sp_rbuf)
+ ptr = sp->sp_rend;
+ ptr -= 2;
+ SET(sp->sp_flags, STTYF_RING_OVERFLOW);
+ break;
+ }
+ }
+ sp->sp_rput = ptr;
+ needsoft = 1;
+ break;
+ case CD180_GSVR_RXEXCEPTION:
+ r = 1;
+ channel = (sc->sc_regs->stc.gscr1 >> 2) & 7;
+ sp = &sc->sc_ttys->sc_port[channel];
+ ptr = sp->sp_rput;
+ *ptr++ = sc->sc_regs->stc.rcsr;
+ *ptr++ = sc->sc_regs->stc.rdr;
+ if (ptr == sp->sp_rend)
+ ptr = sp->sp_rbuf;
+ if (ptr == sp->sp_rget) {
+ if (ptr == sp->sp_rbuf)
+ ptr = sp->sp_rend;
+ ptr -= 2;
+ SET(sp->sp_flags, STTYF_RING_OVERFLOW);
+ break;
+ }
+ sp->sp_rput = ptr;
+ needsoft = 1;
+ break;
+ }
+ sc->sc_regs->stc.eosrr = 0;
+
+ /*
+ * Transmit service request
+ */
+ ar = sc->sc_regs->istc.trar & 7;
+ if (ar == 2) {
+ int cnt = 0;
+
+ r = 1;
+ channel = (sc->sc_regs->stc.gscr1 >> 2) & 7;
+ sp = &sc->sc_ttys->sc_port[channel];
+
+ if (!ISSET(sp->sp_flags, STTYF_STOP)) {
+ if (ISSET(sp->sp_flags, STTYF_SET_BREAK)) {
+ sc->sc_regs->stc.tdr = 0;
+ sc->sc_regs->stc.tdr = 0x81;
+ CLR(sp->sp_flags, STTYF_SET_BREAK);
+ cnt += 2;
+ }
+ if (ISSET(sp->sp_flags, STTYF_CLR_BREAK)) {
+ sc->sc_regs->stc.tdr = 0;
+ sc->sc_regs->stc.tdr = 0x83;
+ CLR(sp->sp_flags, STTYF_CLR_BREAK);
+ cnt += 2;
+ }
+
+ while (sp->sp_txc > 0 && cnt < (CD180_TX_FIFO_SIZE-1)) {
+ u_int8_t ch;
+
+ ch = *sp->sp_txp;
+ sp->sp_txc--;
+ sp->sp_txp++;
+
+ if (ch == 0) {
+ sc->sc_regs->stc.tdr = ch;
+ cnt++;
+ }
+ sc->sc_regs->stc.tdr = ch;
+ cnt++;
+ }
+
+ if (sp->sp_txc == 0 ||
+ ISSET(sp->sp_flags, STTYF_STOP)) {
+ sc->sc_regs->stc.srer &= ~CD180_SRER_TXD;
+ CLR(sp->sp_flags, STTYF_STOP);
+ SET(sp->sp_flags, STTYF_DONE);
+ needsoft = 1;
+ }
+ }
+ }
+ sc->sc_regs->stc.eosrr = 0;
+
+#if 0
+ /*
+ * Modem signal service request
+ */
+ ar = sc->sc_regs->istc.mrar & 7;
+ sc->sc_regs->stc.eosrr = 0;
+#endif
+
+ if (needsoft) {
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ raise(0, PIL_TTY);
+ else
+#endif
+ ienab_bis(IE_MSOFT);
+ }
+ return (r);
+}
+
+int
+spifsoftintr(vsc)
+ void *vsc;
+{
+ struct spif_softc *sc = (struct spif_softc *)vsc;
+ struct stty_softc *stc = sc->sc_ttys;
+ int r = 0, i, data, s, flags;
+ u_int8_t stat;
+ struct stty_port *sp;
+ struct tty *tp;
+
+ if (stc != NULL) {
+ for (i = 0; i < stc->sc_nports; i++) {
+ sp = &stc->sc_port[i];
+ tp = sp->sp_tty;
+
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ continue;
+
+ while (sp->sp_rget != sp->sp_rput) {
+ stat = sp->sp_rget[0];
+ data = sp->sp_rget[1];
+ if ((sp->sp_rget + 2) == sp->sp_rend)
+ sp->sp_rget = sp->sp_rbuf;
+ else
+ sp->sp_rget = sp->sp_rget + 2;
+
+ if (stat & (CD180_RCSR_BE | CD180_RCSR_FE))
+ data |= TTY_FE;
+
+ if (stat & CD180_RCSR_PE)
+ data |= TTY_PE;
+
+ if (stat & CD180_RCSR_OE)
+ log(LOG_WARNING,
+ "%s%x: fifo overflow\n",
+ stc->sc_dev, i);
+ (*linesw[tp->t_line].l_rint)(data, tp);
+ r = 1;
+ }
+
+ s = splhigh();
+ flags = sp->sp_flags;
+ CLR(sp->sp_flags, STTYF_DONE | STTYF_CDCHG |
+ STTYF_RING_OVERFLOW);
+ splx(s);
+
+ if (ISSET(flags, STTYF_CDCHG)) {
+ (*linesw[tp->t_line].l_modem)(tp,
+ sp->sp_carrier);
+ r = 1;
+ }
+
+ if (ISSET(flags, STTYF_RING_OVERFLOW)) {
+ log(LOG_WARNING, "%s%x: ring overflow\n",
+ stc->sc_dev, i);
+ r = 1;
+ }
+
+ if (ISSET(flags, STTYF_DONE)) {
+ ndflush(&tp->t_outq,
+ sp->sp_txp - tp->t_outq.c_cf);
+ CLR(tp->t_state, TS_BUSY);
+ (*linesw[tp->t_line].l_start)(tp);
+ r = 1;
+ }
+ }
+ }
+
+ return (r);
+}
+
+int
+spif_compute_baud(speed, clock, bprlp, bprhp)
+ speed_t speed;
+ int clock;
+ u_int8_t *bprlp, *bprhp;
+{
+ u_int32_t rate;
+
+ rate = (2 * clock) / (16 * speed);
+ if (rate & 1)
+ rate = (rate >> 1) + 1;
+ else
+ rate = rate >> 1;
+
+ if (rate > 0xffff || rate == 0)
+ return (1);
+
+ *bprlp = rate & 0xff;
+ *bprhp = (rate >> 8) & 0xff;
+ return (0);
+}
+
+int
+sbppmatch(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct spif_softc *sc = (struct spif_softc *)parent;
+
+ return (aux == sbppmatch && sc->sc_bpps == NULL);
+}
+
+void
+sbppattach(parent, dev, aux)
+ struct device *parent, *dev;
+ void *aux;
+{
+ struct spif_softc *sc = (struct spif_softc *)parent;
+ struct sbpp_softc *psc = (struct sbpp_softc *)dev;
+ int port;
+
+ sc->sc_bpps = psc;
+
+ for (port = 0; port < sc->sc_npar; port++) {
+ }
+
+ psc->sc_nports = port;
+ printf(": %d port%s\n", port, port == 1 ? "" : "s");
+}
+
+int
+sbppopen(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ return (ENXIO);
+}
+
+int
+sbppclose(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ return (ENXIO);
+}
+
+int
+spifppcintr(v)
+ void *v;
+{
+ return (0);
+}
+
+int
+sbppread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ return (sbpp_rw(dev, uio));
+}
+
+int
+sbppwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ return (sbpp_rw(dev, uio));
+}
+
+int
+sbpp_rw(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ return (ENXIO);
+}
+
+int
+sbppselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ return (ENODEV);
+}
+
+int
+sbppioctl(dev, cmd, data, flags, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flags;
+ struct proc *p;
+{
+ int error;
+
+ error = ENOTTY;
+
+ return (error);
+}
+
+static __inline void
+spif_write_ccr(stc, val)
+ struct stcregs *stc;
+ u_int8_t val;
+{
+ int tries = 100000;
+
+ while (stc->ccr && tries--);
+ if (tries == 0)
+ printf("CCR: timeout\n");
+ stc->ccr = val;
+}
diff --git a/sys/arch/sparc/dev/spifreg.h b/sys/arch/sparc/dev/spifreg.h
new file mode 100644
index 00000000000..f255bbd367c
--- /dev/null
+++ b/sys/arch/sparc/dev/spifreg.h
@@ -0,0 +1,298 @@
+/* $OpenBSD: spifreg.h,v 1.1 1999/02/01 00:30:42 jason Exp $ */
+
+/*
+ * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
+ * 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 Jason L. Wright
+ * 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.
+ */
+
+#define SERIAL_INTR 0
+#define PARALLEL_INTR 1
+
+struct ppcregs {
+ volatile u_int8_t in_pdata; /* input data reg */
+ volatile u_int8_t in_pstat; /* input status reg */
+ volatile u_int8_t in_pctrl; /* input control reg */
+ volatile u_int8_t in_pweird; /* input weird reg */
+ volatile u_int8_t out_pdata; /* output data reg */
+ volatile u_int8_t out_pstat; /* output status reg */
+ volatile u_int8_t out_pctrl; /* output control reg */
+ volatile u_int8_t out_pweird; /* output weird reg */
+ volatile u_int8_t _unused[500]; /* unused space */
+ volatile u_int8_t iack_pdata; /* intr-ack data reg */
+ volatile u_int8_t iack_pstat; /* intr-ack status reg */
+ volatile u_int8_t iack_pctrl; /* intr-ack control reg */
+ volatile u_int8_t iack_pweird; /* intr-ack weird reg */
+};
+
+struct stcregs {
+ volatile u_int8_t _unused0[1]; /* 0x00 unused */
+ volatile u_int8_t ccr; /* channel command reg */
+ volatile u_int8_t srer; /* service req enable reg */
+ volatile u_int8_t cor1; /* channel option reg 1 */
+ volatile u_int8_t cor2; /* channel option reg 2 */
+ volatile u_int8_t cor3; /* channel option reg 3 */
+ volatile u_int8_t ccsr; /* channel cntrl status reg */
+ volatile u_int8_t rdcr; /* rx data count reg */
+ volatile u_int8_t _unused1[1]; /* 0x08 unused */
+ volatile u_int8_t schr1; /* special char reg 1 */
+ volatile u_int8_t schr2; /* special char reg 2 */
+ volatile u_int8_t schr3; /* special char reg 3 */
+ volatile u_int8_t schr4; /* special char reg 4 */
+ volatile u_int8_t _unused2[3]; /* 0x0d - 0x0f unused */
+
+ volatile u_int8_t mcor1; /* modem change option reg 1 */
+ volatile u_int8_t mcor2; /* modem change option reg 2 */
+ volatile u_int8_t mcr; /* modem change reg */
+ volatile u_int8_t _unused3[5]; /* 0x13 - 0x17 unused */
+ volatile u_int8_t rtpr; /* rx timeout period reg */
+ volatile u_int8_t _unused4[7];
+
+ volatile u_int8_t _unused5[8]; /* 0x19 - 0x27 unused */
+ volatile u_int8_t msvr; /* modem signal value reg */
+ volatile u_int8_t msvrts; /* modem sig value rts reg */
+ volatile u_int8_t msvdtr; /* modem sig value dtr reg */
+ volatile u_int8_t _unused6[5]; /* 0x2b - 0x2f unused */
+
+ volatile u_int8_t _unused7[1]; /* 0x30 unused */
+ volatile u_int8_t rbprh; /* rx bit rate period reg hi */
+ volatile u_int8_t rbprl; /* rx bit rate period reg lo */
+ volatile u_int8_t rbr; /* rx bit reg */
+ volatile u_int8_t _unused8[5]; /* 0x34 - 0x38 unused */
+ volatile u_int8_t tbprh; /* tx bit rate period reg hi */
+ volatile u_int8_t tbprl; /* tx bit rate period reg lo */
+ volatile u_int8_t _unused9[5]; /* 0x34 - 0x38 unused */
+
+ volatile u_int8_t gsvr; /* global service vector reg */
+ volatile u_int8_t gscr1; /* global service chan reg 1 */
+ volatile u_int8_t gscr2; /* global service chan reg 2 */
+ volatile u_int8_t gscr3; /* global service chan reg 3 */
+ volatile u_int8_t _unused10[12]; /* 0x44 - 0x4f unused */
+
+ volatile u_int8_t _unused11[16]; /* 0x50 - 0x5f unused */
+
+ volatile u_int8_t _unused12[1]; /* 0x60 unused */
+ volatile u_int8_t msmr; /* modem service match reg */
+ volatile u_int8_t tsmr; /* tx service match reg */
+ volatile u_int8_t rsmr; /* rx service match reg */
+ volatile u_int8_t car; /* channel access reg */
+ volatile u_int8_t srsr; /* service request stat reg */
+ volatile u_int8_t srcr; /* service request conf reg */
+ volatile u_int8_t _unused13[4]; /* 0x67 - 0x6a unused */
+ volatile u_int8_t gfrcr; /* global firmwr rev code reg */
+ volatile u_int8_t _unused14[4]; /* 0x6c - 0x6f unused */
+
+ volatile u_int8_t pprh; /* prescalar period reg hi */
+ volatile u_int8_t pprl; /* prescalar period reg lo */
+ volatile u_int8_t _unused15[3]; /* 0x72 - 0x74 unused */
+ volatile u_int8_t mrar; /* modem request ack reg */
+ volatile u_int8_t trar; /* tx request ack reg */
+ volatile u_int8_t rrar; /* rx request ack reg */
+ volatile u_int8_t rdr; /* rx data reg */
+ volatile u_int8_t _unused16[1]; /* 0x79 unused */
+ volatile u_int8_t rcsr; /* rx char status reg */
+ volatile u_int8_t tdr; /* tx data reg */
+ volatile u_int8_t _unused17[3]; /* 0x7c - 0x7e unused */
+ volatile u_int8_t eosrr; /* end of service req reg */
+};
+
+/*
+ * The register for the SUNW,spif looks something like:
+ * Offset: Function:
+ * 0000 - 03ff unused
+ * 0400 - 0408 dtr latches (one per port)
+ * 0409 - 07ff unused
+ * 0800 - 087f CD180 registers (normal mapping)
+ * 0880 - 0bff unused
+ * 0c00 - 0c7f CD180 registers (*iack mapping)
+ * 0c80 - 0dff unused
+ * 0e00 - 1fff PPC registers
+ */
+struct spifregs {
+ volatile u_int8_t _unused1[1024]; /* 0x000-0x3ff unused */
+ volatile u_int8_t dtrlatch[8]; /* per port dtr latch */
+ volatile u_int8_t _unused2[1016]; /* 0x409-0x7ff unused */
+ struct stcregs stc; /* regular cd-180 regs */
+ volatile u_int8_t _unused3[896]; /* 0x880-0xbff unused */
+ struct stcregs istc; /* *iack cd-180 regs */
+ volatile u_int8_t _unused4[384]; /* 0xc80-0xdff unused */
+ struct ppcregs ppc; /* parallel port regs */
+};
+
+/* The mapping of minor device number -> card and port is done as
+ * follows by default:
+ *
+ * +---+---+---+---+---+---+---+---+
+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ * +---+---+---+---+---+---+---+---+
+ * | | | | | | | |
+ * | | | | | +---+---+---> port number
+ * | | | | |
+ * | | | | +---------------> unused
+ * | | | |
+ * | | | +-------------------> dialout (on tty ports)
+ * | | |
+ * | | +-----------------------> unused
+ * | |
+ * +---+---------------------------> card number
+ *
+ */
+
+#define CD180_SRCR_PKGTYP 0x80 /* chip package type */
+#define CD180_SRCR_REGACKEN 0x40
+#define CD180_SRCR_DAISYEN 0x20
+#define CD180_SRCR_GLOBPRI 0x10
+#define CD180_SRCR_UNFAIR 0x08
+#define CD180_SRCR_AUTOPRI 0x04
+#define CD180_SRCR_reserved 0x02
+#define CD180_SRCR_PRISEL 0x01
+
+#define CD180_CCR_RESET 0x80 /* chip/channel reset */
+#define CD180_CCR_RESETALL 0x01 /* global reset */
+#define CD180_CCR_RESETCHAN 0x00 /* current channel reset */
+
+#define CD180_CCR_CORCHG 0x40 /* channel option reg has changed */
+#define CD180_CCR_CORCHG1 0x02 /* cor1 has changed */
+#define CD180_CCR_CORCHG2 0x04 /* cor2 has changed */
+#define CD180_CCR_CORCHG3 0x08 /* cor3 has changed */
+
+#define CD180_CCR_SENDSPCHG 0x20
+#define CD180_CCR_SSPC0 0x01
+#define CD180_CCR_SSPC1 0x02
+#define CD180_CCR_SSPC2 0x04
+
+#define CD180_CCR_CHANCTL 0x10 /* channel control command */
+#define CD180_CCR_CHAN_TXEN 0x08 /* enable channel tx */
+#define CD180_CCR_CHAN_TXDIS 0x04 /* disable channel tx */
+#define CD180_CCR_CHAN_RXEN 0x02 /* enable channel rx */
+#define CD180_CCR_CHAN_RXDIS 0x01 /* disable channel rx */
+
+#define CD180_COR1_EVENPAR 0x00 /* even parity */
+#define CD180_COR1_ODDPAR 0x80 /* odd parity */
+#define CD180_COR1_PARMODE_NO 0x00 /* no parity */
+#define CD180_COR1_PARMODE_FORCE 0x20 /* force (odd=1, even=0) */
+#define CD180_COR1_PARMODE_NORMAL 0x40 /* normal parity mode */
+#define CD180_COR1_PARMODE_NA 0x60 /* notused */
+#define CD180_COR1_IGNPAR 0x10 /* ignore parity */
+#define CD180_COR1_STOP1 0x00 /* 1 stop bit */
+#define CD180_COR1_STOP15 0x04 /* 1.5 stop bits */
+#define CD180_COR1_STOP2 0x08 /* 2 stop bits */
+#define CD180_COR1_STOP25 0x0c /* 2.5 stop bits */
+#define CD180_COR1_CS5 0x00 /* 5 bit characters */
+#define CD180_COR1_CS6 0x01 /* 6 bit characters */
+#define CD180_COR1_CS7 0x02 /* 7 bit characters */
+#define CD180_COR1_CS8 0x03 /* 8 bit characters */
+
+#define CD180_COR2_IXM 0x80 /* implied xon mode */
+#define CD180_COR2_TXIBE 0x40 /* tx in-band flow control */
+#define CD180_COR2_ETC 0x20 /* embedded tx command enbl */
+#define CD180_COR2_LLM 0x10 /* local loopback mode */
+#define CD180_COR2_RLM 0x08 /* remote loopback mode */
+#define CD180_COR2_RTSAO 0x04 /* RTS automatic output enbl */
+#define CD180_COR2_CTSAE 0x02 /* CTS automatic enable */
+#define CD180_COR2_DSRAE 0x01 /* DSR automatic enable */
+
+#define CD180_MCOR1_DSRZD 0x80 /* catch 0->1 DSR changes */
+#define CD180_MCOR1_CDZD 0x40 /* catch 0->1 CD changes */
+#define CD180_MCOR1_CTSZD 0x40 /* catch 0->1 CTS changes */
+#define CD180_MCOR1_DTRTHRESH 0x0f /* DTR threshold mask */
+
+#define CD180_MCOR2_DSROD 0x80 /* catch 1->0 DSR changes */
+#define CD180_MCOR2_CDOD 0x40 /* catch 1->0 CD changes */
+#define CD180_MCOR2_CTSOD 0x20 /* catch 1->0 CTS changes */
+
+#define CD180_SRER_DSR 0x80 /* DSR service request */
+#define CD180_SRER_CD 0x40 /* CD service request */
+#define CD180_SRER_CTS 0x20 /* CTS service request */
+#define CD180_SRER_RXD 0x10 /* RXD service request */
+#define CD180_SRER_RXSCD 0x08 /* RX special char request */
+#define CD180_SRER_TXD 0x04 /* TX ready service request */
+#define CD180_SRER_TXE 0x02 /* TX empty service request */
+#define CD180_SRER_NNDT 0x01 /* No new data timeout req */
+
+#define CD180_MSVR_DSR 0x80 /* DSR input state */
+#define CD180_MSVR_CD 0x40 /* CD input state */
+#define CD180_MSVR_CTS 0x20 /* CTS input state */
+#define CD180_MSVR_DTR 0x02 /* DTR output state */
+#define CD180_MSVR_RTS 0x01 /* RTS output state */
+
+#define CD180_GSVR_IMASK 0x07 /* interrupt type mask */
+#define CD180_GSVR_NOREQUEST 0x00 /* no request pending */
+#define CD180_GSVR_STATCHG 0x01 /* modem signal change */
+#define CD180_GSVR_TXDATA 0x02 /* tx service request */
+#define CD180_GSVR_RXGOOD 0x03 /* rx service request */
+#define CD180_GSVR_reserved1 0x04
+#define CD180_GSVR_reserved2 0x05
+#define CD180_GSVR_reserved3 0x06
+#define CD180_GSVR_RXEXCEPTION 0x07 /* rx exception request */
+
+#define STTY_RX_FIFO_THRESHOLD 6
+#define STTY_RX_DTR_THRESHOLD 9
+
+#define CD180_RCSR_TO 0x80 /* time out */
+#define CD180_RCSR_SCD2 0x40 /* special char detect 2 */
+#define CD180_RCSR_SCD1 0x20 /* special char detect 1 */
+#define CD180_RCSR_SCD0 0x10 /* special char detect 0 */
+#define CD180_RCSR_BE 0x08 /* break exception */
+#define CD180_RCSR_PE 0x04 /* parity exception */
+#define CD180_RCSR_FE 0x02 /* framing exception */
+#define CD180_RCSR_OE 0x01 /* overrun exception */
+
+#define CD180_TX_FIFO_SIZE 8 /* 8 chars of fifo */
+/*
+ * These are the offsets of the MRAR,TRAR, and RRAR in *IACK space.
+ * The high bit must be set as per specs for the MSMR, TSMR, and RSMR.
+ */
+#define SPIF_MSMR 0xf5 /* offset of MRAR | 0x80 */
+#define SPIF_TSMR 0xf6 /* offset of TRAR | 0x80 */
+#define SPIF_RSMR 0xf7 /* offset of RRAR | 0x80 */
+
+#define SPIF_MAX_CARDS 4
+#define SPIF_MAX_TTY 8
+#define SPIF_MAX_BPP 1
+
+#define SPIF_CARD(x) ((minor(x) >> 6) & 0x03)
+#define SPIF_PORT(x) (minor(x) & 0x0f)
+
+#define STTY_DIALOUT(x) (minor(x) & 0x10)
+
+/* "verosc" node tells which oscillator we have. */
+#define SPIF_OSC9 1 /* 9.8304 Mhz */
+#define SPIF_OSC10 2 /* 10Mhz */
+
+#define SPIF_PPRH 0xf0
+#define SPIF_PPRL 0x00
+
+#define STTYF_CDCHG 0x01 /* carrier changed */
+#define STTYF_RING_OVERFLOW 0x02 /* ring buffer overflowed */
+#define STTYF_DONE 0x04 /* done... flush buffers */
+#define STTYF_SET_BREAK 0x08 /* set break signal */
+#define STTYF_CLR_BREAK 0x10 /* clear break signal */
+#define STTYF_STOP 0x20 /* stopped */
+
+#define STTY_RBUF_SIZE (2 * 512)
diff --git a/sys/arch/sparc/dev/spifvar.h b/sys/arch/sparc/dev/spifvar.h
new file mode 100644
index 00000000000..1db8c16cab5
--- /dev/null
+++ b/sys/arch/sparc/dev/spifvar.h
@@ -0,0 +1,81 @@
+/* $OpenBSD: spifvar.h,v 1.1 1999/02/01 00:30:42 jason Exp $ */
+
+/*
+ * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
+ * 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 Jason L. Wright
+ * 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.
+ */
+
+#define SPIF_MAX_SERIAL 8
+#define SPIF_MAX_PARALLEL 1
+
+struct stty_port {
+ struct tty *sp_tty; /* tty device */
+ struct spif_softc *sp_sc; /* pointer back to registers */
+ int sp_channel; /* channel number */
+ u_char *sp_rbuf; /* ring buffer start */
+ u_char *sp_rend; /* ring buffer end */
+ u_char *sp_rget; /* ring buffer read pointer */
+ u_char *sp_rput; /* ring buffer write pointer */
+ u_char *sp_txp; /* transmit character pointer */
+ int sp_txc; /* transmit character counter */
+
+ int sp_openflags;
+ int sp_carrier;
+ int sp_flags;
+ char sp_dtr; /* software dtr status */
+};
+
+struct stty_softc {
+ struct device sc_dev; /* base device */
+ int sc_nports; /* number of serial ports */
+ struct stty_port sc_port[SPIF_MAX_SERIAL];
+};
+
+struct sbpp_softc {
+ struct device sc_dev; /* base device */
+ int sc_nports; /* number of parallel ports */
+};
+
+struct spif_softc {
+ struct device sc_dev; /* base device */
+ struct sbusdev sc_sd; /* sbus device */
+ struct intrhand sc_stcih; /* stc interrupt vectoring */
+ struct intrhand sc_ppcih; /* ppc interrupt vectoring */
+ struct intrhand sc_softih; /* hard interrupt vectoring */
+ int sc_rev; /* revision level */
+ int sc_osc; /* oscillator speed (mhz) */
+ int sc_node; /* which sbus node */
+ int sc_nser; /* number of serial ports */
+ int sc_npar; /* number of parallel ports */
+ unsigned sc_rev2; /* onboard chip revision */
+ struct spifregs *sc_regs; /* registers */
+ struct stty_softc *sc_ttys; /* our ttys */
+ struct sbpp_softc *sc_bpps; /* our ttys */
+};
+
diff --git a/sys/arch/sparc/include/conf.h b/sys/arch/sparc/include/conf.h
index f378b2ffdf2..77039f962ca 100644
--- a/sys/arch/sparc/include/conf.h
+++ b/sys/arch/sparc/include/conf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.h,v 1.8 1998/12/29 09:33:36 deraadt Exp $ */
+/* $OpenBSD: conf.h,v 1.9 1999/02/01 00:30:43 jason Exp $ */
/* $NetBSD: conf.h,v 1.8 1996/12/31 07:12:43 mrg Exp $ */
/*
@@ -106,4 +106,7 @@ cdev_decl(bpp);
cdev_decl(mtty);
cdev_decl(mbpp);
+cdev_decl(stty);
+cdev_decl(sbpp);
+
cdev_decl(ksyms);
diff --git a/sys/arch/sparc/sparc/conf.c b/sys/arch/sparc/sparc/conf.c
index e19be3c2471..9860c9de645 100644
--- a/sys/arch/sparc/sparc/conf.c
+++ b/sys/arch/sparc/sparc/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.20 1998/12/29 09:33:36 deraadt Exp $ */
+/* $OpenBSD: conf.c,v 1.21 1999/02/01 00:30:43 jason Exp $ */
/* $NetBSD: conf.c,v 1.40 1996/04/11 19:20:03 thorpej Exp $ */
/*
@@ -83,6 +83,8 @@
#include "xy.h"
#include "bpp.h"
#include "magma.h" /* has NMTTY and NMBPP */
+#include "spif.h" /* has NSTTY and NSBPP */
+
#ifdef XFS
#include <xfs/nxfs.h>
cdev_decl(xfs_dev);
@@ -227,8 +229,8 @@ struct cdevsw cdevsw[] =
cdev_fb_init(NCGFOURTEEN,cgfourteen), /* 99: /dev/cgfourteen */
cdev_tty_init(NMTTY,mtty), /* 100 */
cdev_gen_init(NMBPP,mbpp), /* 101 */
- cdev_notdef(), /* 102 */
- cdev_notdef(), /* 103 */
+ cdev_tty_init(NSTTY,stty), /* 102 */
+ cdev_gen_init(NSBPP,sbpp), /* 103 */
cdev_bpp_init(NBPP,bpp), /* 104: bpp */
cdev_bpftun_init(NBPFILTER,bpf),/* 105: packet filter */
cdev_disk_init(NRD,rd), /* 106: ram disk driver */