summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sbus/files.sbus10
-rw-r--r--sys/dev/sbus/spif.c1149
-rw-r--r--sys/dev/sbus/spifreg.h380
-rw-r--r--sys/dev/sbus/spifvar.h87
4 files changed, 1625 insertions, 1 deletions
diff --git a/sys/dev/sbus/files.sbus b/sys/dev/sbus/files.sbus
index 10b90ecc57a..861257f4418 100644
--- a/sys/dev/sbus/files.sbus
+++ b/sys/dev/sbus/files.sbus
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sbus,v 1.11 2002/01/12 20:19:40 jason Exp $
+# $OpenBSD: files.sbus,v 1.12 2002/01/13 02:06:45 jason Exp $
# $NetBSD: files.sbus,v 1.16 2000/12/08 17:29:12 martin Exp $
#
# Config file and device description for machine-independent SBUS code.
@@ -67,3 +67,11 @@ attach mtty at magma
device mbpp
attach mbpp at magma
file dev/sbus/magma.c magma | mtty | mbpp needs-flag
+
+device spif {}
+attach spif at sbus
+device stty
+attach stty at spif
+device sbpp
+attach sbpp at spif
+file dev/sbus/spif.c spif | stty | sbpp needs-flag
diff --git a/sys/dev/sbus/spif.c b/sys/dev/sbus/spif.c
new file mode 100644
index 00000000000..4c8496ba528
--- /dev/null
+++ b/sys/dev/sbus/spif.c
@@ -0,0 +1,1149 @@
+/* $OpenBSD: spif.c,v 1.1 2002/01/13 02:06:45 jason Exp $ */
+
+/*
+ * Copyright (c) 1999-2002 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 cards
+ */
+
+#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 <dev/sbus/sbusvar.h>
+#include <dev/sbus/spifreg.h>
+#include <dev/sbus/spifvar.h>
+
+/*
+ * 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 spifstcintr_mx __P((struct spif_softc *, int *));
+int spifstcintr_tx __P((struct spif_softc *, int *));
+int spifstcintr_rx __P((struct spif_softc *, int *));
+int spifstcintr_rxexception __P((struct spif_softc *, int *));
+void 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));
+void stty_write_ccr __P((struct spif_softc *, u_int8_t));
+int stty_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_DULL
+};
+
+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
+};
+
+/* normal STC access */
+#define STC_WRITE(sc,r,v) \
+ bus_space_write_1((sc)->sc_bustag, (sc)->sc_stch, (r), (v))
+#define STC_READ(sc,r) \
+ bus_space_read_1((sc)->sc_bustag, (sc)->sc_stch, (r))
+
+/* IACK STC access */
+#define ISTC_WRITE(sc,r,v) \
+ bus_space_write_1((sc)->sc_bustag, (sc)->sc_istch, (r), (v))
+#define ISTC_READ(sc,r) \
+ bus_space_read_1((sc)->sc_bustag, (sc)->sc_istch, (r))
+
+/* PPC access */
+#define PPC_WRITE(sc,r,v) \
+ bus_space_write_1((sc)->sc_bustag, (sc)->sc_ppch, (r), (v))
+#define PPC_READ(sc,r) \
+ bus_space_read_1((sc)->sc_bustag, (sc)->sc_ppch, (r))
+
+#define DTR_WRITE(sc,port,v) \
+ do { \
+ sc->sc_ttys->sc_port[(port)].sp_dtr = v; \
+ bus_space_write_1((sc)->sc_bustag, \
+ sc->sc_dtrh, port, (v == 0) ? 1 : 0); \
+ } while (0)
+
+#define DTR_READ(sc,port) ((sc)->sc_ttys->sc_port[(port)].sp_dtr)
+
+int
+spifmatch(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct cfdata *cf = vcf;
+ struct sbus_attach_args *sa = aux;
+
+ if (strcmp(cf->cf_driver->cd_name, sa->sa_name) &&
+ strcmp("SUNW,spif", sa->sa_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 sbus_attach_args *sa = aux;
+
+ if (sa->sa_nintr != 2) {
+ printf(": expected 2 interrupts, got %d\n",
+ sa->sa_nintr);
+ return;
+ }
+
+ if (sa->sa_nreg != 1) {
+ printf(": expected %d registers, got %d\n",
+ 1, sa->sa_nreg);
+ return;
+ }
+
+ sc->sc_bustag = sa->sa_bustag;
+ if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
+ sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size,
+ BUS_SPACE_MAP_LINEAR, 0, &sc->sc_regh) != 0) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
+ DTR_REG_OFFSET, DTR_REG_LEN, &sc->sc_dtrh) != 0) {
+ printf(": can't map dtr regs\n");
+ return;
+ }
+
+ if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
+ STC_REG_OFFSET, STC_REG_LEN, &sc->sc_stch) != 0) {
+ printf(": can't map dtr regs\n");
+ return;
+ }
+
+ if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
+ ISTC_REG_OFFSET, ISTC_REG_LEN, &sc->sc_istch) != 0) {
+ printf(": can't map dtr regs\n");
+ return;
+ }
+
+ if (bus_space_subregion(sc->sc_bustag, sc->sc_regh,
+ PPC_REG_OFFSET, PPC_REG_LEN, &sc->sc_ppch) != 0) {
+ printf(": can't map dtr regs\n");
+ return;
+ }
+
+ sc->sc_ppcih = bus_intr_establish(sa->sa_bustag,
+ sa->sa_intr[PARALLEL_INTR].sbi_pri, IPL_TTY, 0, spifppcintr, sc);
+ if (sc->sc_ppcih == NULL) {
+ printf(": failed to establish ppc interrupt\n");
+ return;
+ }
+
+ sc->sc_stcih = bus_intr_establish(sa->sa_bustag,
+ sa->sa_intr[SERIAL_INTR].sbi_pri, IPL_TTY, 0, spifstcintr, sc);
+ if (sc->sc_stcih == NULL) {
+ printf(": failed to establish stc interrupt\n");
+ return;
+ }
+
+ sc->sc_softih = softintr_establish(IPL_TTY, spifsoftintr, sc);
+ if (sc->sc_softih == NULL) {
+ printf(": can't get soft intr\n");
+ return;
+ }
+
+ sc->sc_node = sa->sa_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 = 10000000;
+ break;
+ case SPIF_OSC9:
+ default:
+ sc->sc_osc = 9830400;
+ break;
+ }
+
+ sc->sc_nser = 8;
+ sc->sc_npar = 1;
+
+ sc->sc_rev2 = STC_READ(sc, STC_GFRCR);
+ STC_WRITE(sc, STC_GSVR, 0);
+
+ stty_write_ccr(sc, CD180_CCR_CMD_RESET | CD180_CCR_RESETALL);
+ while (STC_READ(sc, STC_GSVR) != 0xff);
+ while (STC_READ(sc, STC_GFRCR) != sc->sc_rev2);
+
+ STC_WRITE(sc, STC_PPRH, CD180_PPRH);
+ STC_WRITE(sc, STC_PPRL, CD180_PPRL);
+ STC_WRITE(sc, STC_MSMR, SPIF_MSMR);
+ STC_WRITE(sc, STC_TSMR, SPIF_TSMR);
+ STC_WRITE(sc, STC_RSMR, SPIF_RSMR);
+ STC_WRITE(sc, STC_GSVR, 0);
+ STC_WRITE(sc, STC_GSCR1, 0);
+ STC_WRITE(sc, STC_GSCR2, 0);
+ STC_WRITE(sc, STC_GSCR3, 0);
+
+ printf(": rev %x chiprev %x osc %sMhz\n",
+ sc->sc_rev, sc->sc_rev2, clockfreq(sc->sc_osc));
+
+ (void)config_found(self, sttymatch, NULL);
+ (void)config_found(self, sbppmatch, NULL);
+}
+
+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;
+
+ DTR_WRITE(sc, port, 0);
+
+ 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();
+
+ STC_WRITE(csc, STC_CAR, sp->sp_channel);
+ stty_write_ccr(csc, CD180_CCR_CMD_RESET|CD180_CCR_RESETCHAN);
+ STC_WRITE(csc, STC_CAR, sp->sp_channel);
+
+ stty_param(tp, &tp->t_termios);
+
+ ttsetwater(tp);
+
+ STC_WRITE(csc, STC_SRER, CD180_SRER_CD | 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)) {
+ stty_modem_control(sp, 0, DMSET);
+ STC_WRITE(csc, STC_CAR, port);
+ STC_WRITE(csc, STC_CCR,
+ CD180_CCR_CMD_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);
+ STC_WRITE(sc, STC_CAR, sp->sp_channel);
+ STC_WRITE(sc, STC_SRER,
+ STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
+ break;
+ case TIOCCBRK:
+ SET(sp->sp_flags, STTYF_CLR_BREAK);
+ STC_WRITE(sc, STC_CAR, sp->sp_channel);
+ STC_WRITE(sc, STC_SRER,
+ STC_READ(sc, 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 TIOCMSET:
+ stty_modem_control(sp, *((int *)data), DMSET);
+ 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();
+ STC_WRITE(csc, STC_CAR, sp->sp_channel);
+
+ switch (how) {
+ case DMGET:
+ bits = TIOCM_LE;
+ if (DTR_READ(csc, sp->sp_channel))
+ bits |= TIOCM_DTR;
+ msvr = STC_READ(csc, 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:
+ DTR_WRITE(csc, sp->sp_channel, ISSET(bits, TIOCM_DTR) ? 1 : 0);
+ if (ISSET(bits, TIOCM_RTS))
+ STC_WRITE(csc, STC_MSVR,
+ STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS));
+ else
+ STC_WRITE(csc, STC_MSVR,
+ STC_READ(csc, STC_MSVR) | CD180_MSVR_RTS);
+ break;
+ case DMBIS:
+ if (ISSET(bits, TIOCM_DTR))
+ DTR_WRITE(csc, sp->sp_channel, 1);
+ if (ISSET(bits, TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS))
+ STC_WRITE(csc, STC_MSVR,
+ STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS));
+ break;
+ case DMBIC:
+ if (ISSET(bits, TIOCM_DTR))
+ DTR_WRITE(csc, sp->sp_channel, 0);
+ if (ISSET(bits, TIOCM_RTS))
+ STC_WRITE(csc, STC_MSVR,
+ STC_READ(csc, 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 &&
+ stty_compute_baud(t->c_ospeed, sc->sc_osc, &tbprl, &tbprh))
+ return (EINVAL);
+
+ if (t->c_ispeed &&
+ stty_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));
+
+ STC_WRITE(sc, 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;
+ }
+ STC_WRITE(sc, STC_COR1, opt);
+ stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG1);
+
+ opt = CD180_COR2_ETC;
+ if (ISSET(t->c_cflag, CRTSCTS))
+ opt |= CD180_COR2_CTSAE;
+ STC_WRITE(sc, STC_COR2, opt);
+ stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG2);
+
+ STC_WRITE(sc, STC_COR3, STTY_RX_FIFO_THRESHOLD);
+ stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG3);
+
+ STC_WRITE(sc, STC_SCHR1, 0x11);
+ STC_WRITE(sc, STC_SCHR2, 0x13);
+ STC_WRITE(sc, STC_SCHR3, 0x11);
+ STC_WRITE(sc, STC_SCHR4, 0x13);
+ STC_WRITE(sc, STC_RTPR, 0x12);
+
+ STC_WRITE(sc, STC_MCOR1, CD180_MCOR1_CDZD | STTY_RX_DTR_THRESHOLD);
+ STC_WRITE(sc, STC_MCOR2, CD180_MCOR2_CDOD);
+ STC_WRITE(sc, STC_MCR, 0);
+
+ if (t->c_ospeed) {
+ STC_WRITE(sc, STC_TBPRH, tbprh);
+ STC_WRITE(sc, STC_TBPRL, tbprl);
+ }
+
+ if (t->c_ispeed) {
+ STC_WRITE(sc, STC_RBPRH, rbprh);
+ STC_WRITE(sc, STC_RBPRL, rbprl);
+ }
+
+ stty_write_ccr(sc, CD180_CCR_CMD_CHAN |
+ CD180_CCR_CHAN_TXEN | CD180_CCR_CHAN_RXEN);
+
+ sp->sp_carrier = STC_READ(sc, STC_MSVR) & CD180_MSVR_CD;
+
+ 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);
+ STC_WRITE(sc, STC_CAR, sp->sp_channel);
+ STC_WRITE(sc, STC_SRER,
+ STC_READ(sc, STC_SRER) | CD180_SRER_TXD);
+ }
+ }
+
+ splx(s);
+}
+
+int
+spifstcintr_rxexception(sc, needsoftp)
+ struct spif_softc *sc;
+ int *needsoftp;
+{
+ struct stty_port *sp;
+ u_int8_t channel, *ptr;
+ int cnt;
+
+ channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
+ sp = &sc->sc_ttys->sc_port[channel];
+ ptr = sp->sp_rput;
+ *ptr++ = STC_READ(sc, STC_RCSR);
+ *ptr++ = STC_READ(sc, 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);
+ }
+ STC_WRITE(sc, STC_EOSRR, 0);
+ if (cnt) {
+ *needsoftp = 1;
+ sp->sp_rput = ptr;
+ }
+ return (1);
+}
+
+int
+spifstcintr_rx(sc, needsoftp)
+ struct spif_softc *sc;
+ int *needsoftp;
+{
+ struct stty_port *sp;
+ u_int8_t channel, *ptr, cnt, rcsr;
+ int i;
+
+ channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
+ sp = &sc->sc_ttys->sc_port[channel];
+ ptr = sp->sp_rput;
+ cnt = STC_READ(sc, STC_RDCR);
+ for (i = 0; i < cnt; i++) {
+ *ptr++ = 0;
+ rcsr = STC_READ(sc, STC_RCSR);
+ *ptr++ = STC_READ(sc, 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;
+ }
+ }
+ STC_WRITE(sc, STC_EOSRR, 0);
+ if (cnt) {
+ *needsoftp = 1;
+ sp->sp_rput = ptr;
+ }
+ return (1);
+}
+
+int
+spifstcintr_tx(sc, needsoftp)
+ struct spif_softc *sc;
+ int *needsoftp;
+{
+ struct stty_port *sp;
+ u_int8_t channel, ch;
+ int cnt = 0;
+
+ channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
+ sp = &sc->sc_ttys->sc_port[channel];
+ if (!ISSET(sp->sp_flags, STTYF_STOP)) {
+ if (ISSET(sp->sp_flags, STTYF_SET_BREAK)) {
+ STC_WRITE(sc, STC_TDR, 0);
+ STC_WRITE(sc, STC_TDR, 0x81);
+ CLR(sp->sp_flags, STTYF_SET_BREAK);
+ cnt += 2;
+ }
+ if (ISSET(sp->sp_flags, STTYF_CLR_BREAK)) {
+ STC_WRITE(sc, STC_TDR, 0);
+ STC_WRITE(sc, STC_TDR, 0x83);
+ CLR(sp->sp_flags, STTYF_CLR_BREAK);
+ cnt += 2;
+ }
+
+ while (sp->sp_txc > 0 && cnt < (CD180_TX_FIFO_SIZE-1)) {
+ ch = *sp->sp_txp;
+ sp->sp_txc--;
+ sp->sp_txp++;
+
+ if (ch == 0) {
+ STC_WRITE(sc, STC_TDR, ch);
+ cnt++;
+ }
+ STC_WRITE(sc, STC_TDR, ch);
+ cnt++;
+ }
+ }
+
+ if (sp->sp_txc == 0 ||
+ ISSET(sp->sp_flags, STTYF_STOP)) {
+ STC_WRITE(sc, STC_SRER, STC_READ(sc, STC_SRER) &
+ (~CD180_SRER_TXD));
+ CLR(sp->sp_flags, STTYF_STOP);
+ SET(sp->sp_flags, STTYF_DONE);
+ *needsoftp = 1;
+ }
+
+ STC_WRITE(sc, STC_EOSRR, 0);
+
+ return (1);
+}
+
+int
+spifstcintr_mx(sc, needsoftp)
+ struct spif_softc *sc;
+ int *needsoftp;
+{
+ struct stty_port *sp;
+ u_int8_t channel, mcr;
+
+ channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1));
+ sp = &sc->sc_ttys->sc_port[channel];
+ mcr = STC_READ(sc, STC_MCR);
+ if (mcr & CD180_MCR_CD) {
+ SET(sp->sp_flags, STTYF_CDCHG);
+ *needsoftp = 1;
+ }
+ STC_WRITE(sc, STC_MCR, 0);
+ STC_WRITE(sc, STC_EOSRR, 0);
+ return (1);
+}
+
+int
+spifstcintr(vsc)
+ void *vsc;
+{
+ struct spif_softc *sc = (struct spif_softc *)vsc;
+ int needsoft = 0, r = 0, i;
+ u_int8_t ar;
+
+ for (i = 0; i < 8; i++) {
+ ar = ISTC_READ(sc, STC_RRAR) & CD180_GSVR_IMASK;
+ if (ar == CD180_GSVR_RXGOOD)
+ r |= spifstcintr_rx(sc, &needsoft);
+ else if (ar == CD180_GSVR_RXEXCEPTION)
+ r |= spifstcintr_rxexception(sc, &needsoft);
+ }
+
+ for (i = 0; i < 8; i++) {
+ ar = ISTC_READ(sc, STC_TRAR) & CD180_GSVR_IMASK;
+ if (ar == CD180_GSVR_TXDATA)
+ r |= spifstcintr_tx(sc, &needsoft);
+ }
+
+ for (i = 0; i < 8; i++) {
+ ar = ISTC_READ(sc, STC_MRAR) & CD180_GSVR_IMASK;
+ if (ar == CD180_GSVR_STATCHG)
+ r |= spifstcintr_mx(sc, &needsoft);
+ }
+
+ if (needsoft)
+ softintr_schedule(sc->sc_softih);
+ return (r);
+}
+
+void
+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, msvr;
+ 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];
+ sp->sp_rget += 2;
+ if (sp->sp_rget == sp->sp_rend)
+ sp->sp_rget = sp->sp_rbuf;
+
+ if (stat & (CD180_RCSR_BE | CD180_RCSR_FE))
+ data |= TTY_FE;
+
+ if (stat & CD180_RCSR_PE)
+ data |= TTY_PE;
+
+ (*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)) {
+ s = spltty();
+ STC_WRITE(sc, STC_CAR, i);
+ msvr = STC_READ(sc, STC_MSVR);
+ splx(s);
+
+ sp->sp_carrier = msvr & CD180_MSVR_CD;
+ (*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.dv_xname, 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;
+ }
+ }
+ }
+}
+
+void
+stty_write_ccr(sc, val)
+ struct spif_softc *sc;
+ u_int8_t val;
+{
+ int tries = 100000;
+
+ while (STC_READ(sc, STC_CCR) && tries--)
+ /*EMPTY*/;
+ if (tries == 0)
+ printf("%s: ccr timeout\n", sc->sc_dev.dv_xname);
+ STC_WRITE(sc, STC_CCR, val);
+}
+
+int
+stty_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);
+}
diff --git a/sys/dev/sbus/spifreg.h b/sys/dev/sbus/spifreg.h
new file mode 100644
index 00000000000..1bf5d44b7fe
--- /dev/null
+++ b/sys/dev/sbus/spifreg.h
@@ -0,0 +1,380 @@
+/* $OpenBSD: spifreg.h,v 1.1 2002/01/13 02:06:46 jason Exp $ */
+
+/*
+ * Copyright (c) 1999-2002 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 PPC_IN_PDATA 0x000 /* input data */
+#define PPC_IN_PSTAT 0x001 /* input status */
+#define PPC_IN_CTRL 0x002 /* input control */
+#define PPC_IN_PWEIRD 0x003 /* input weird */
+#define PPC_OUT_PDATA 0x000 /* output data */
+#define PPC_OUT_PSTAT 0x001 /* output status */
+#define PPC_OUT_PCTRL 0x002 /* output control */
+#define PPC_OUT_PWEIRD 0x003 /* output weird */
+#define PPC_IACK_PDATA 0x1fc /* iack data */
+#define PPC_IACK_PSTAT 0x1fd /* iack status */
+#define PPC_IACK_PCTRL 0x1fe /* iack control */
+#define PPC_IACK_PWEIRD 0x1ff /* iack weird */
+
+/* Parallel Status: read only */
+#define PPC_PSTAT_ERROR 0x08 /* error */
+#define PPC_PSTAT_SELECT 0x10 /* select */
+#define PPC_PSTAT_PAPER 0x20 /* paper out */
+#define PPC_PSTAT_ACK 0x40 /* ack */
+#define PPC_PSTAT_BUSY 0x80 /* busy */
+
+/* Parallel Control: read/write */
+#define PPC_CTRL_STROBE 0x01 /* strobe, 1=drop strobe */
+#define PPC_CTRL_AFX 0x02 /* auto form-feed */
+#define PPC_CTRL_INIT 0x04 /* init, 1=enable printer */
+#define PPC_CTRL_SLCT 0x08 /* SLC, 1=select printer */
+#define PPC_CTRL_IRQE 0x10 /* IRQ, 1=enable intrs */
+#define PPC_CTRL_OUTPUT 0x20 /* direction: 1=ppc out */
+
+/*
+ * The 'stc' is a Cirrus Logic CL-CD180 (either revision B or revision C)
+ */
+#define STC_CCR 0x01 /* channel command */
+#define STC_SRER 0x02 /* service request enable */
+#define STC_COR1 0x03 /* channel option 1 */
+#define STC_COR2 0x04 /* channel option 2 */
+#define STC_COR3 0x05 /* channel option 3 */
+#define STC_CCSR 0x06 /* channel control status */
+#define STC_RDCR 0x07 /* rx data count */
+#define STC_SCHR1 0x09 /* special character 1 */
+#define STC_SCHR2 0x0a /* special character 2 */
+#define STC_SCHR3 0x0b /* special character 3 */
+#define STC_SCHR4 0x0c /* special character 4 */
+#define STC_MCOR1 0x10 /* modem change option 1 */
+#define STC_MCOR2 0x11 /* modem change option 2 */
+#define STC_MCR 0x12 /* modem change */
+#define STC_RTPR 0x18 /* rx timeout period */
+#define STC_MSVR 0x28 /* modem signal value */
+#define STC_MSVRTS 0x29 /* modem signal value rts */
+#define STC_MSVDTR 0x2a /* modem signal value dtr */
+#define STC_RBPRH 0x31 /* rx bit rate period high */
+#define STC_RBPRL 0x32 /* rx bit rate period low */
+#define STC_RBR 0x33 /* rx bit */
+#define STC_TBPRH 0x39 /* tx bit rate period high */
+#define STC_TBPRL 0x3a /* tx bit rate period low */
+#define STC_GSVR 0x40 /* global service vector */
+#define STC_GSCR1 0x41 /* global service channel 1 */
+#define STC_GSCR2 0x42 /* global service channel 2 */
+#define STC_GSCR3 0x43 /* global service channel 3 */
+#define STC_MSMR 0x61 /* modem service match */
+#define STC_TSMR 0x62 /* tx service match */
+#define STC_RSMR 0x63 /* rx service match */
+#define STC_CAR 0x64 /* channel access */
+#define STC_SRSR 0x65 /* service request status */
+#define STC_SRCR 0x66 /* service request config */
+#define STC_GFRCR 0x6b /* global firmware rev code */
+#define STC_PPRH 0x70 /* prescalar period high */
+#define STC_PPRL 0x71 /* prescalar period low */
+#define STC_MRAR 0x75 /* modem request ack */
+#define STC_TRAR 0x76 /* tx request ack */
+#define STC_RRAR 0x77 /* rx request ack */
+#define STC_RDR 0x78 /* rx data */
+#define STC_RCSR 0x7a /* rx character status */
+#define STC_TDR 0x7b /* tx data */
+#define STC_EOSRR 0x7f /* end of service */
+
+#define STC_REGMAPSIZE 0x80
+
+/* Global Firmware Revision Code Register (rw) */
+#define CD180_GFRCR_REV_B 0x81 /* CL-CD180B */
+#define CD180_GFRCR_REV_C 0x82 /* CL-CD180C */
+
+/* Service Request Configuration Register (rw) (CD180C or higher) */
+#define CD180_SRCR_PKGTYP 0x80 /* pkg type,0=PLCC,1=PQFP */
+#define CD180_SRCR_REGACKEN 0x40 /* register ack enable */
+#define CD180_SRCR_DAISYEN 0x20 /* daisy chain enable */
+#define CD180_SRCR_GLOBPRI 0x10 /* global priority */
+#define CD180_SRCR_UNFAIR 0x08 /* use unfair interrupts */
+#define CD180_SRCR_AUTOPRI 0x02 /* automatic priority */
+#define CD180_SRCR_PRISEL 0x01 /* select rx/tx as high pri */
+
+/* Prescalar Period Register High (rw) */
+#define CD180_PPRH 0xf0 /* high byte */
+#define CD180_PPRL 0x00 /* low byte */
+
+/* Global Service Vector Register (rw) */
+/* Modem Request Acknowledgement Register (ro) (and IACK equivalent) */
+/* Receive Request Acknowledgement Register (ro) (and IACK equivalent) */
+/* Transmit Request Acknowledgement Register (ro) (and IACK equivalent) */
+#define CD180_GSVR_USERMASK 0xf8 /* user defined bits */
+#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 /* reserved */
+#define CD180_GSVR_reserved2 0x05 /* reserved */
+#define CD180_GSVR_reserved3 0x06 /* reserved */
+#define CD180_GSVR_RXEXCEPTION 0x07 /* rx exception request */
+
+/* Service Request Status Register (ro) (CD180C and higher) */
+#define CD180_SRSR_MREQINT 0x01 /* modem request internal */
+#define CD180_SRSR_MREQEXT 0x02 /* modem request external */
+#define CD180_SRSR_TREQINT 0x04 /* tx request internal */
+#define CD180_SRSR_TREQEXT 0x08 /* tx request external */
+#define CD180_SRSR_RREQINT 0x10 /* rx request internal */
+#define CD180_SRSR_RREQEXT 0x20 /* rx request external */
+#define CD180_SRSR_ILV_MASK 0xc0 /* internal service context */
+#define CD180_SRSR_ILV_NONE 0x00 /* not in service context */
+#define CD180_SRSR_ILV_RX 0xc0 /* in rx service context */
+#define CD180_SRSR_ILV_TX 0x80 /* in tx service context */
+#define CD180_SRSR_ILV_MODEM 0x40 /* in modem service context */
+
+/* Global Service Channel Register 1,2,3 (rw) */
+#define CD180_GSCR_CHANNEL(gscr) (((gscr) >> 2) & 7)
+
+/* Receive Data Count Register (ro) */
+#define CD180_RDCR_MASK 0x0f /* mask for fifo length */
+
+/* Receive Character Status Register (ro) */
+#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 */
+
+/* Service Request Enable Register (rw) */
+#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 */
+
+/* Channel Command Register (rw) */
+/* Reset Channel Command */
+#define CD180_CCR_CMD_RESET 0x80 /* chip/channel reset */
+#define CD180_CCR_RESETALL 0x01 /* global reset */
+#define CD180_CCR_RESETCHAN 0x00 /* current channel reset */
+/* Channel Option Register Command */
+#define CD180_CCR_CMD_COR 0x40 /* channel opt reg 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 */
+/* Send Special Character Command */
+#define CD180_CCR_CMD_SPC 0x20 /* send special chars changed */
+#define CD180_CCR_SSPC0 0x01 /* send special char 0 change */
+#define CD180_CCR_SSPC1 0x02 /* send special char 1 change */
+#define CD180_CCR_SSPC2 0x04 /* send special char 2 change */
+/* Channel Control Command */
+#define CD180_CCR_CMD_CHAN 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 */
+
+/* Channel Option Register 1 (rw) */
+#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 */
+
+/* Channel Option Register 2 (rw) */
+#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 */
+
+/* Channel Option Register 3 (rw) */
+#define CD180_COR3_XON2 0x80 /* XON char in spc1&3 */
+#define CD180_COR3_XON1 0x00 /* XON char in spc1 */
+#define CD180_COR3_XOFF2 0x40 /* XOFF char in spc2&4 */
+#define CD180_COR3_XOFF1 0x00 /* XOFF char in spc2 */
+#define CD180_COR3_FCT 0x20 /* flow control transparency */
+#define CD180_COR3_SCDE 0x10 /* special char recognition */
+#define CD180_COR3_RXFIFO_MASK 0x0f /* rx fifo threshold */
+
+/* Channel Control Status Register (ro) */
+#define CD180_CCSR_RXEN 0x80 /* rx is enabled */
+#define CD180_CCSR_RXFLOFF 0x40 /* rx flow-off */
+#define CD180_CCSR_RXFLON 0x20 /* rx flow-on */
+#define CD180_CCSR_TXEN 0x08 /* tx is enabled */
+#define CD180_CCSR_TXFLOFF 0x04 /* tx flow-off */
+#define CD180_CCSR_TXFLON 0x02 /* tx flow-on */
+
+/* Receiver Bit Register (ro) */
+#define CD180_RBR_RXD 0x40 /* state of RxD pin */
+#define CD180_RBR_STARTHUNT 0x20 /* looking for start bit */
+
+/* Modem Change Register (rw) */
+#define CD180_MCR_DSR 0x80 /* DSR changed */
+#define CD180_MCR_CD 0x40 /* CD changed */
+#define CD180_MCR_CTS 0x20 /* CTS changed */
+
+/* Modem Change Option Register 1 (rw) */
+#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 */
+
+/* Modem Change Option Register 2 (rw) */
+#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 */
+
+/* Modem Signal Value Register (rw) */
+#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 */
+
+/* Modem Signal Value Register - Request To Send (w) (CD180C and higher) */
+#define CD180_MSVRTS_RTS 0x01 /* RTS signal value */
+
+/* Modem Signal Value Register - Data Terminal Ready (w) (CD180C and higher) */
+#define CD180_MSVDTR_DTR 0x02 /* DTR signal value */
+
+/*
+ * The register map for the SUNW,spif looks something like:
+ * Offset: Function:
+ * 0000 - 03ff Boot ROM
+ * 0400 - 0407 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
+ *
+ * One note about the DTR latches: The values stored there are reversed.
+ * By writing a 1 to the latch, DTR is lowered, and by writing a 0, DTR
+ * is raised. The latches cannot be read, and no other value can be written
+ * there or the system will crash due to "excessive bus loading (see
+ * SBus loading and capacitance spec)"
+ *
+ * The *iack registers are read/written with the IACK bit set. When
+ * the interrupt routine starts, it reads the MRAR, TRAR, and RRAR registers
+ * from this mapping. This signals an interrupt acknowlegement cycle.
+ * (NOTE: these are not really the MRAR, TRAR, and RRAR... They are copies
+ * of the GSVR, I just mapped them to the same location as the mrar, trar,
+ * and rrar because it seemed appropriate).
+ */
+#define DTR_REG_OFFSET 0x400 /* DTR latches */
+#define DTR_REG_LEN 0x8
+#define STC_REG_OFFSET 0x800 /* normal cd180 access */
+#define STC_REG_LEN 0x80
+#define ISTC_REG_OFFSET 0xc00 /* IACK cd180 access */
+#define ISTC_REG_LEN STC_REG_LEN
+#define PPC_REG_OFFSET 0xe00 /* PPC registers */
+#define PPC_REG_LEN 0x200
+
+/*
+ * 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 SPIF_MAX_CARDS 4
+#define SPIF_MAX_TTY 8
+#define SPIF_MAX_BPP 1
+
+/*
+ * device selectors
+ */
+#define SPIF_CARD(x) ((minor(x) >> 6) & 0x03)
+#define SPIF_PORT(x) (minor(x) & 0x07)
+#define STTY_DIALOUT(x) (minor(x) & 0x10)
+
+#define STTY_RX_FIFO_THRESHOLD 4
+#define STTY_RX_DTR_THRESHOLD 7
+#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 (0x80 | STC_MRAR) /* offset of MRAR | 0x80 */
+#define SPIF_TSMR (0x80 | STC_TRAR) /* offset of TRAR | 0x80 */
+#define SPIF_RSMR (0x80 | STC_RRAR) /* offset of RRAR | 0x80 */
+
+/*
+ * "verosc" node tells which oscillator we have.
+ */
+#define SPIF_OSC9 1 /* 9.8304 Mhz */
+#define SPIF_OSC10 2 /* 10Mhz */
+
+/*
+ * There are two interrupts, serial gets interrupt[0], and parallel
+ * gets interrupt[1]
+ */
+#define SERIAL_INTR 0
+#define PARALLEL_INTR 1
+
+/*
+ * spif tty flags
+ */
+#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/dev/sbus/spifvar.h b/sys/dev/sbus/spifvar.h
new file mode 100644
index 00000000000..54fe9ae6d1b
--- /dev/null
+++ b/sys/dev/sbus/spifvar.h
@@ -0,0 +1,87 @@
+/* $OpenBSD: spifvar.h,v 1.1 2002/01/13 02:06:46 jason Exp $ */
+
+/*
+ * Copyright (c) 1999-2002 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; /* open flags */
+ int sp_carrier; /* software carrier status */
+ int sp_flags; /* software state */
+ 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 */
+ void *sc_stcih; /* stc interrupt vector */
+ void *sc_ppcih; /* ppc interrut vector */
+ void *sc_softih; /* soft interrupt vector */
+ int sc_rev; /* revision level */
+ int sc_osc; /* oscillator speed (hz) */
+ int sc_node; /* which sbus node */
+ int sc_nser; /* number of serial ports */
+ int sc_npar; /* number of parallel ports */
+ int sc_rev2; /* cd180 chip revision */
+ bus_space_tag_t sc_bustag; /* our bus tag */
+ bus_space_handle_t sc_regh; /* whole register map */
+ bus_space_handle_t sc_stch; /* STC registers */
+ bus_space_handle_t sc_istch; /* IACK STC registers */
+ bus_space_handle_t sc_dtrh; /* DTR registers */
+ bus_space_handle_t sc_ppch; /* PPC registers */
+ struct spifregs *sc_regs; /* registers */
+ struct stty_softc *sc_ttys; /* our ttys */
+ struct sbpp_softc *sc_bpps; /* our ttys */
+};
+