summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/scc.475
-rw-r--r--sys/dev/scc/scc_bfe.h153
-rw-r--r--sys/dev/scc/scc_bfe_ebus.c87
-rw-r--r--sys/dev/scc/scc_bfe_sbus.c84
-rw-r--r--sys/dev/scc/scc_bus.h51
-rw-r--r--sys/dev/scc/scc_core.c542
-rw-r--r--sys/dev/scc/scc_dev_sab82532.c137
-rw-r--r--sys/dev/scc/scc_dev_z8530.c202
-rw-r--r--sys/dev/scc/scc_if.m77
-rw-r--r--sys/dev/uart/uart_bus_scc.c115
-rw-r--r--sys/kern/serdev_if.m79
-rw-r--r--sys/modules/scc/Makefile14
12 files changed, 1616 insertions, 0 deletions
diff --git a/share/man/man4/scc.4 b/share/man/man4/scc.4
new file mode 100644
index 0000000..b08b3f8
--- /dev/null
+++ b/share/man/man4/scc.4
@@ -0,0 +1,75 @@
+.\"
+.\" Copyright (c) 2006 Marcel Moolenaar
+.\" 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.
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 29, 2006
+.Dt SCC 4
+.Os
+.\"
+.Sh NAME
+.Nm scc
+.Nd driver for Serial Communications Controllers (SCC) devices
+.\"
+.Sh SYNOPSIS
+.Cd "device scc"
+.Cd "device uart"
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+device driver provides support for various classes of SCCs.
+It is an umbrella driver that delegates control of each independent
+communication channel to subordinate drivers.
+These subordinate drivers, like
+.Xr uart 4 ,
+take care of the details of the communication itself.
+.\"
+.Sh HARDWARE
+The
+.Nm
+driver supports the following classes of SCCs:
+.Pp
+.Bl -bullet -compact
+.It
+SAB82532: Siemens SAB 82532 based serial communications controllers.
+.It
+Z8530: Zilog 8530 based serial communications controllers.
+.El
+.\"
+.Sh SEE ALSO
+.Xr puc 4 ,
+.Xr uart 4
+.\"
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+The
+.Nm
+driver and this manual page were written by
+.An Marcel Moolenaar Aq marcel@xcllnt.net .
diff --git a/sys/dev/scc/scc_bfe.h b/sys/dev/scc/scc_bfe.h
new file mode 100644
index 0000000..f1e85a1
--- /dev/null
+++ b/sys/dev/scc/scc_bfe.h
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_SCC_BFE_H_
+#define _DEV_SCC_BFE_H_
+
+#include <sys/serial.h>
+
+/*
+ * Bus access structure. This structure holds the minimum information needed
+ * to access the SCC. The rclk field, although not important to actually
+ * access the SCC, is important for baudrate programming, delay loops and
+ * other timing related computations.
+ */
+struct scc_bas {
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ u_int range;
+ u_int rclk;
+ u_int regshft;
+};
+
+#define scc_regofs(bas, reg) ((reg) << (bas)->regshft)
+
+#define scc_getreg(bas, reg) \
+ bus_space_read_1((bas)->bst, (bas)->bsh, scc_regofs(bas, reg))
+#define scc_setreg(bas, reg, value) \
+ bus_space_write_1((bas)->bst, (bas)->bsh, scc_regofs(bas, reg), value)
+
+#define scc_barrier(bas) \
+ bus_space_barrier((bas)->bst, (bas)->bsh, 0, (bas)->range, \
+ BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
+
+/*
+ * SCC mode (child) and channel control structures.
+ */
+
+#define SCC_NMODES 3
+#define SCC_ISRCCNT 5
+
+struct scc_chan;
+
+struct scc_mode {
+ struct scc_chan *m_chan;
+ device_t m_dev;
+
+ u_int m_mode;
+ int m_attached:1;
+ int m_fastintr:1;
+ int m_hasintr:1;
+ int m_probed:1;
+ int m_sysdev:1;
+
+ driver_intr_t *ih;
+ serdev_intr_t *ih_src[SCC_ISRCCNT];
+ void *ih_arg;
+};
+
+struct scc_chan {
+ struct resource ch_rres;
+ struct resource_list ch_rlist;
+
+ struct scc_mode ch_mode[SCC_NMODES];
+
+ u_int ch_nr;
+ int ch_sysdev:1;
+
+ uint32_t ch_ipend;
+ uint32_t ch_hwsig;
+};
+
+/*
+ * SCC class & instance (=softc)
+ */
+struct scc_class {
+ KOBJ_CLASS_FIELDS;
+ u_int cl_channels; /* Number of independent channels. */
+ u_int cl_class; /* SCC bus class ID. */
+ u_int cl_modes; /* Supported modes (bitset). */
+ int cl_range;
+ u_int cl_rclk;
+ u_int cl_regshft;
+};
+
+extern struct scc_class scc_sab82532_class;
+extern struct scc_class scc_z8530_class;
+
+struct scc_softc {
+ KOBJ_FIELDS;
+ struct scc_class *sc_class;
+ struct scc_bas sc_bas;
+ device_t sc_dev;
+
+ struct mtx sc_hwmtx; /* Spinlock protecting hardware. */
+
+ struct resource *sc_rres; /* Register resource. */
+ int sc_rrid;
+ int sc_rtype; /* SYS_RES_{IOPORT|MEMORY}. */
+ struct resource *sc_ires; /* Interrupt resource. */
+ void *sc_icookie;
+ int sc_irid;
+
+ struct scc_chan *sc_chan;
+
+ int sc_fastintr:1;
+ int sc_leaving:1;
+ int sc_polled:1;
+
+ uint32_t sc_hwsig; /* Signal state. Used by HW driver. */
+};
+
+extern devclass_t scc_devclass;
+extern char scc_driver_name[];
+
+int scc_bfe_attach(device_t dev);
+int scc_bfe_detach(device_t dev);
+int scc_bfe_probe(device_t dev);
+
+struct resource *scc_bus_alloc_resource(device_t, device_t, int, int *,
+ u_long, u_long, u_long, u_int);
+int scc_bus_get_resource(device_t, device_t, int, int, u_long *, u_long *);
+int scc_bus_read_ivar(device_t, device_t, int, uintptr_t *);
+int scc_bus_release_resource(device_t, device_t, int, int, struct resource *);
+int scc_bus_setup_intr(device_t, device_t, struct resource *, int,
+ void (*)(void *), void *, void **);
+int scc_bus_teardown_intr(device_t, device_t, struct resource *, void *);
+
+#endif /* _DEV_SCC_BFE_H_ */
diff --git a/sys/dev/scc/scc_bfe_ebus.c b/sys/dev/scc/scc_bfe_ebus.c
new file mode 100644
index 0000000..4e5d2ef
--- /dev/null
+++ b/sys/dev/scc/scc_bfe_ebus.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/ofw/ofw_bus.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/scc/scc_bfe.h>
+
+static int
+scc_ebus_probe(device_t dev)
+{
+ struct scc_softc *sc;
+ const char *cmpt, *nm;
+
+ sc = device_get_softc(dev);
+ nm = ofw_bus_get_name(dev);
+ cmpt = ofw_bus_get_compat(dev);
+ if (cmpt == NULL)
+ cmpt = "";
+ if (!strcmp(nm, "se") || !strcmp(cmpt, "sab82532")) {
+ device_set_desc(dev, "Siemens SAB 82532 dual channel SCC");
+ sc->sc_class = &scc_sab82532_class;
+ return (scc_bfe_probe(dev));
+ }
+ return (ENXIO);
+}
+
+static device_method_t scc_ebus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, scc_ebus_probe),
+ DEVMETHOD(device_attach, scc_bfe_attach),
+ DEVMETHOD(device_detach, scc_bfe_detach),
+
+ DEVMETHOD(bus_alloc_resource, scc_bus_alloc_resource),
+ DEVMETHOD(bus_release_resource, scc_bus_release_resource),
+ DEVMETHOD(bus_get_resource, scc_bus_get_resource),
+ DEVMETHOD(bus_read_ivar, scc_bus_read_ivar),
+ DEVMETHOD(bus_setup_intr, scc_bus_setup_intr),
+ DEVMETHOD(bus_teardown_intr, scc_bus_teardown_intr),
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ { 0, 0 }
+};
+
+static driver_t scc_ebus_driver = {
+ scc_driver_name,
+ scc_ebus_methods,
+ sizeof(struct scc_softc),
+};
+
+DRIVER_MODULE(scc, ebus, scc_ebus_driver, scc_devclass, 0, 0);
diff --git a/sys/dev/scc/scc_bfe_sbus.c b/sys/dev/scc/scc_bfe_sbus.c
new file mode 100644
index 0000000..0843f2d
--- /dev/null
+++ b/sys/dev/scc/scc_bfe_sbus.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/ofw/ofw_bus.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/scc/scc_bfe.h>
+
+static int
+scc_sbus_probe(device_t dev)
+{
+ struct scc_softc *sc;
+ const char *nm;
+
+ sc = device_get_softc(dev);
+ nm = ofw_bus_get_name(dev);
+ if (!strcmp(nm, "zs")) {
+ device_set_desc(dev, "Zilog Z8530 dual channel SCC");
+ sc->sc_class = &scc_z8530_class;
+ return (scc_bfe_probe(dev));
+ }
+ return (ENXIO);
+}
+
+static device_method_t scc_sbus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, scc_sbus_probe),
+ DEVMETHOD(device_attach, scc_bfe_attach),
+ DEVMETHOD(device_detach, scc_bfe_detach),
+
+ DEVMETHOD(bus_alloc_resource, scc_bus_alloc_resource),
+ DEVMETHOD(bus_release_resource, scc_bus_release_resource),
+ DEVMETHOD(bus_get_resource, scc_bus_get_resource),
+ DEVMETHOD(bus_read_ivar, scc_bus_read_ivar),
+ DEVMETHOD(bus_setup_intr, scc_bus_setup_intr),
+ DEVMETHOD(bus_teardown_intr, scc_bus_teardown_intr),
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ { 0, 0 }
+};
+
+static driver_t scc_sbus_driver = {
+ scc_driver_name,
+ scc_sbus_methods,
+ sizeof(struct scc_softc),
+};
+
+DRIVER_MODULE(scc, sbus, scc_sbus_driver, scc_devclass, 0, 0);
diff --git a/sys/dev/scc/scc_bus.h b/sys/dev/scc/scc_bus.h
new file mode 100644
index 0000000..ed16309
--- /dev/null
+++ b/sys/dev/scc/scc_bus.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_SCC_BUS_H_
+#define _DEV_SCC_BUS_H_
+
+#include <sys/serial.h>
+#include <serdev_if.h>
+
+#define SCC_IVAR_CHANNEL 0
+#define SCC_IVAR_CLASS 1
+#define SCC_IVAR_CLOCK 2
+#define SCC_IVAR_MODE 3
+#define SCC_IVAR_REGSHFT 4
+#define SCC_IVAR_HWMTX 5
+
+/* Hardware class -- the SCC type. */
+#define SCC_CLASS_SAB82532 0
+#define SCC_CLASS_Z8530 1
+
+/* The possible modes supported by the SCC. */
+#define SCC_MODE_ASYNC 0x01
+#define SCC_MODE_BISYNC 0x02
+#define SCC_MODE_HDLC 0x04
+
+#endif /* _DEV_SCC_BUS_H_ */
diff --git a/sys/dev/scc/scc_core.c b/sys/dev/scc/scc_core.c
new file mode 100644
index 0000000..a407986
--- /dev/null
+++ b/sys/dev/scc/scc_core.c
@@ -0,0 +1,542 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/serial.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/scc/scc_bfe.h>
+#include <dev/scc/scc_bus.h>
+
+#include "scc_if.h"
+
+devclass_t scc_devclass;
+char scc_driver_name[] = "scc";
+
+MALLOC_DEFINE(M_SCC, "SCC", "SCC driver");
+
+static void
+scc_bfe_intr(void *arg)
+{
+ struct scc_softc *sc = arg;
+ struct scc_chan *ch;
+ struct scc_class *cl;
+ struct scc_mode *m;
+ int c, i, ipend, isrc;
+
+ cl = sc->sc_class;
+ while (!sc->sc_leaving && (ipend = SCC_IPEND(sc)) != 0) {
+ i = 0, isrc = SER_INT_OVERRUN;
+ while (ipend) {
+ while (i < SCC_ISRCCNT && !(ipend & isrc))
+ i++, isrc <<= 1;
+ KASSERT(i < SCC_ISRCCNT, ("%s", __func__));
+ ipend &= ~isrc;
+ for (c = 0; c < cl->cl_channels; c++) {
+ ch = &sc->sc_chan[c];
+ if (!(ch->ch_ipend & isrc))
+ continue;
+ m = &ch->ch_mode[0];
+ if (m->ih_src[i] == NULL)
+ continue;
+ if ((*m->ih_src[i])(m->ih_arg))
+ ch->ch_ipend &= ~isrc;
+ }
+ }
+ for (c = 0; c < cl->cl_channels; c++) {
+ ch = &sc->sc_chan[c];
+ if (!ch->ch_ipend)
+ continue;
+ m = &ch->ch_mode[0];
+ if (m->ih != NULL)
+ (*m->ih)(m->ih_arg);
+ else
+ SCC_ICLEAR(sc, ch);
+ }
+ }
+}
+
+int
+scc_bfe_attach(device_t dev)
+{
+ struct resource_list_entry *rle;
+ struct scc_chan *ch;
+ struct scc_class *cl;
+ struct scc_mode *m;
+ struct scc_softc *sc, *sc0;
+ const char *sep;
+ bus_space_handle_t bh;
+ u_long base, size, start;
+ int c, error, mode, sysdev;
+
+ /*
+ * The sc_class field defines the type of SCC we're going to work
+ * with and thus the size of the softc. Replace the generic softc
+ * with one that matches the SCC now that we're certain we handle
+ * the device.
+ */
+ sc0 = device_get_softc(dev);
+ cl = sc0->sc_class;
+ if (cl->size > sizeof(*sc)) {
+ sc = malloc(cl->size, M_SCC, M_WAITOK|M_ZERO);
+ bcopy(sc0, sc, sizeof(*sc));
+ device_set_softc(dev, sc);
+ } else
+ sc = sc0;
+
+ size = abs(cl->cl_range);
+
+ mtx_init(&sc->sc_hwmtx, "scc_hwmtx", NULL, MTX_SPIN);
+
+ /*
+ * Re-allocate. We expect that the softc contains the information
+ * collected by scc_bfe_probe() intact.
+ */
+ sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
+ 0, ~0, cl->cl_channels * size, RF_ACTIVE);
+ if (sc->sc_rres == NULL)
+ return (ENXIO);
+ sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
+ sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
+
+ sc->sc_irid = 0;
+ sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ /*
+ * Create the control structures for our children. Probe devices
+ * and query them to see if we can reset the hardware.
+ */
+ sysdev = 0;
+ sc->sc_chan = malloc(sizeof(struct scc_chan) * cl->cl_channels,
+ M_SCC, M_WAITOK | M_ZERO);
+ base = rman_get_start(sc->sc_rres);
+ start = base + ((cl->cl_range < 0) ? size * (cl->cl_channels - 1) : 0);
+ for (c = 0; c < cl->cl_channels; c++) {
+ ch = &sc->sc_chan[c];
+ resource_list_init(&ch->ch_rlist);
+ ch->ch_nr = c + 1;
+
+ resource_list_add(&ch->ch_rlist, sc->sc_rtype, 0, start,
+ start + size - 1, size);
+ rle = resource_list_find(&ch->ch_rlist, sc->sc_rtype, 0);
+ rle->res = &ch->ch_rres;
+ bus_space_subregion(rman_get_bustag(sc->sc_rres),
+ rman_get_bushandle(sc->sc_rres), start - base, size, &bh);
+ rman_set_bushandle(rle->res, bh);
+ rman_set_bustag(rle->res, rman_get_bustag(sc->sc_rres));
+
+ resource_list_add(&ch->ch_rlist, SYS_RES_IRQ, 0, c, c, 1);
+ rle = resource_list_find(&ch->ch_rlist, SYS_RES_IRQ, 0);
+ rle->res = sc->sc_ires;
+
+ for (mode = 0; mode < SCC_NMODES; mode++) {
+ m = &ch->ch_mode[mode];
+ m->m_chan = ch;
+ m->m_mode = 1U << mode;
+ if ((cl->cl_modes & m->m_mode) == 0 || ch->ch_sysdev)
+ continue;
+ m->m_dev = device_add_child(dev, NULL, -1);
+ device_set_ivars(m->m_dev, (void *)m);
+ error = device_probe_child(dev, m->m_dev);
+ if (!error) {
+ m->m_probed = 1;
+ m->m_sysdev = SERDEV_SYSDEV(m->m_dev) ? 1 : 0;
+ ch->ch_sysdev |= m->m_sysdev;
+ }
+ }
+
+ start += (cl->cl_range < 0) ? -size : size;
+ sysdev |= ch->ch_sysdev;
+ }
+
+ /*
+ * Have the hardware driver initialize the hardware. Tell it
+ * whether or not a hardware reset should be performed.
+ */
+ if (bootverbose) {
+ device_printf(dev, "%sresetting hardware\n",
+ (sysdev) ? "not " : "");
+ }
+ error = SCC_ATTACH(sc, !sysdev);
+ if (error)
+ goto fail;
+
+ /*
+ * Setup our interrupt handler. Make it FAST under the assumption
+ * that our children's are fast as well. We make it MPSAFE as soon
+ * as a child sets up a MPSAFE interrupt handler.
+ * Of course, if we can't setup a fast handler, we make it MPSAFE
+ * right away.
+ */
+ if (sc->sc_ires != NULL) {
+ error = bus_setup_intr(dev, sc->sc_ires,
+ INTR_TYPE_TTY | INTR_FAST, scc_bfe_intr, sc,
+ &sc->sc_icookie);
+ if (error) {
+ error = bus_setup_intr(dev, sc->sc_ires,
+ INTR_TYPE_TTY | INTR_MPSAFE, scc_bfe_intr, sc,
+ &sc->sc_icookie);
+ } else
+ sc->sc_fastintr = 1;
+
+ if (error) {
+ device_printf(dev, "could not activate interrupt\n");
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
+ sc->sc_ires);
+ sc->sc_ires = NULL;
+ }
+ }
+ if (sc->sc_ires == NULL) {
+ /* XXX no interrupt resource. Force polled mode. */
+ sc->sc_polled = 1;
+ }
+
+ /*
+ * Attach all child devices that were probed successfully.
+ */
+ for (c = 0; c < cl->cl_channels; c++) {
+ ch = &sc->sc_chan[c];
+ for (mode = 0; mode < SCC_NMODES; mode++) {
+ m = &ch->ch_mode[mode];
+ if (!m->m_probed)
+ continue;
+ error = device_attach(m->m_dev);
+ if (error)
+ continue;
+ m->m_attached = 1;
+ }
+ }
+
+ if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
+ sep = "";
+ device_print_prettyname(dev);
+ if (sc->sc_fastintr) {
+ printf("%sfast interrupt", sep);
+ sep = ", ";
+ }
+ if (sc->sc_polled) {
+ printf("%spolled mode", sep);
+ sep = ", ";
+ }
+ printf("\n");
+ }
+
+ return (0);
+
+ fail:
+ if (sc->sc_ires != NULL) {
+ bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
+ sc->sc_ires);
+ }
+ bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
+ return (error);
+}
+
+int
+scc_bfe_detach(device_t dev)
+{
+ struct scc_chan *ch;
+ struct scc_class *cl;
+ struct scc_mode *m;
+ struct scc_softc *sc;
+ int chan, error, mode;
+
+ sc = device_get_softc(dev);
+ cl = sc->sc_class;
+
+ /* Detach our children. */
+ error = 0;
+ for (chan = 0; chan < cl->cl_channels; chan++) {
+ ch = &sc->sc_chan[chan];
+ for (mode = 0; mode < SCC_NMODES; mode++) {
+ m = &ch->ch_mode[mode];
+ if (!m->m_attached)
+ continue;
+ if (device_detach(m->m_dev) != 0)
+ error = ENXIO;
+ else
+ m->m_attached = 0;
+ }
+ }
+
+ if (error)
+ return (error);
+
+ if (sc->sc_ires != NULL) {
+ bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
+ sc->sc_ires);
+ }
+ bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
+
+ free(sc->sc_chan, M_SCC);
+
+ mtx_destroy(&sc->sc_hwmtx);
+ return (0);
+}
+
+int
+scc_bfe_probe(device_t dev)
+{
+ struct scc_softc *sc;
+ struct scc_class *cl;
+ u_long size;
+ int error;
+
+ /*
+ * Initialize the instance. Note that the instance (=softc) does
+ * not necessarily match the hardware specific softc. We can't do
+ * anything about it now, because we may not attach to the device.
+ * Hardware drivers cannot use any of the class specific fields
+ * while probing.
+ */
+ sc = device_get_softc(dev);
+ cl = sc->sc_class;
+ kobj_init((kobj_t)sc, (kobj_class_t)cl);
+ sc->sc_dev = dev;
+ if (device_get_desc(dev) == NULL)
+ device_set_desc(dev, cl->name);
+
+ size = abs(cl->cl_range);
+
+ /*
+ * Allocate the register resource. We assume that all SCCs have a
+ * single register window in either I/O port space or memory mapped
+ * I/O space. Any SCC that needs multiple windows will consequently
+ * not be supported by this driver as-is.
+ */
+ sc->sc_rrid = 0;
+ sc->sc_rtype = SYS_RES_MEMORY;
+ sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
+ 0, ~0, cl->cl_channels * size, RF_ACTIVE);
+ if (sc->sc_rres == NULL) {
+ sc->sc_rrid = 0;
+ sc->sc_rtype = SYS_RES_IOPORT;
+ sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype,
+ &sc->sc_rrid, 0, ~0, cl->cl_channels * size, RF_ACTIVE);
+ if (sc->sc_rres == NULL)
+ return (ENXIO);
+ }
+
+ /*
+ * Fill in the bus access structure and call the hardware specific
+ * probe method.
+ */
+ sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
+ sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
+ sc->sc_bas.range = size;
+ sc->sc_bas.rclk = sc->sc_class->cl_rclk;
+ sc->sc_bas.regshft = sc->sc_class->cl_regshft;
+
+ error = SCC_PROBE(sc);
+ bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
+ return ((error == 0) ? BUS_PROBE_DEFAULT : error);
+}
+
+struct resource *
+scc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource_list_entry *rle;
+ struct scc_chan *ch;
+ struct scc_mode *m;
+
+ if (device_get_parent(child) != dev)
+ return (NULL);
+
+ /* We only support default allocations. */
+ if (start != 0UL || end != ~0UL)
+ return (NULL);
+
+ m = device_get_ivars(child);
+ ch = m->m_chan;
+ rle = resource_list_find(&ch->ch_rlist, type, 0);
+ if (rle == NULL)
+ return (NULL);
+ *rid = 0;
+ return (rle->res);
+}
+
+int
+scc_bus_get_resource(device_t dev, device_t child, int type, int rid,
+ u_long *startp, u_long *countp)
+{
+ struct resource_list_entry *rle;
+ struct scc_chan *ch;
+ struct scc_mode *m;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ m = device_get_ivars(child);
+ ch = m->m_chan;
+ rle = resource_list_find(&ch->ch_rlist, type, rid);
+ if (rle == NULL)
+ return (EINVAL);
+
+ if (startp != NULL)
+ *startp = rle->start;
+ if (countp != NULL)
+ *countp = rle->count;
+ return (0);
+}
+
+int
+scc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
+{
+ struct scc_chan *ch;
+ struct scc_class *cl;
+ struct scc_mode *m;
+ struct scc_softc *sc;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ cl = sc->sc_class;
+ m = device_get_ivars(child);
+ ch = m->m_chan;
+
+ switch (index) {
+ case SCC_IVAR_CHANNEL:
+ *result = ch->ch_nr;
+ break;
+ case SCC_IVAR_CLASS:
+ *result = cl->cl_class;
+ break;
+ case SCC_IVAR_CLOCK:
+ *result = cl->cl_rclk;
+ break;
+ case SCC_IVAR_MODE:
+ *result = m->m_mode;
+ break;
+ case SCC_IVAR_REGSHFT:
+ *result = cl->cl_regshft;
+ break;
+ case SCC_IVAR_HWMTX:
+ *result = (uintptr_t)&sc->sc_hwmtx;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+int
+scc_bus_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *res)
+{
+ struct resource_list_entry *rle;
+ struct scc_chan *ch;
+ struct scc_mode *m;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ m = device_get_ivars(child);
+ ch = m->m_chan;
+ rle = resource_list_find(&ch->ch_rlist, type, rid);
+ return ((rle == NULL) ? EINVAL : 0);
+}
+
+int
+scc_bus_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
+ void (*ihand)(void *), void *arg, void **cookiep)
+{
+ struct scc_mode *m;
+ struct scc_softc *sc;
+ int i, isrc;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ /* Interrupt handlers must be FAST or MPSAFE. */
+ if ((flags & (INTR_FAST|INTR_MPSAFE)) == 0)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ if (sc->sc_polled)
+ return (ENXIO);
+
+ if (sc->sc_fastintr && !(flags & INTR_FAST)) {
+ sc->sc_fastintr = 0;
+ bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
+ bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE,
+ scc_bfe_intr, sc, &sc->sc_icookie);
+ }
+
+ m = device_get_ivars(child);
+ m->m_hasintr = 1;
+ m->m_fastintr = (flags & INTR_FAST) ? 1 : 0;
+ m->ih = ihand;
+ m->ih_arg = arg;
+
+ i = 0, isrc = SER_INT_OVERRUN;
+ while (i < SCC_ISRCCNT) {
+ m->ih_src[i] = SERDEV_IHAND(child, isrc);
+ if (m->ih_src[i] != NULL)
+ m->ih = NULL;
+ i++, isrc <<= 1;
+ }
+ return (0);
+}
+
+int
+scc_bus_teardown_intr(device_t dev, device_t child, struct resource *r,
+ void *cookie)
+{
+ struct scc_mode *m;
+ int i;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ m = device_get_ivars(child);
+ if (!m->m_hasintr)
+ return (EINVAL);
+
+ m->m_hasintr = 0;
+ m->m_fastintr = 0;
+ m->ih = NULL;
+ m->ih_arg = NULL;
+ for (i = 0; i < SCC_ISRCCNT; i++)
+ m->ih_src[i] = NULL;
+ return (0);
+}
diff --git a/sys/dev/scc/scc_dev_sab82532.c b/sys/dev/scc/scc_dev_sab82532.c
new file mode 100644
index 0000000..e7393ed
--- /dev/null
+++ b/sys/dev/scc/scc_dev_sab82532.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/serial.h>
+
+#include <dev/scc/scc_bfe.h>
+#include <dev/scc/scc_bus.h>
+
+#include <dev/ic/sab82532.h>
+
+#include "scc_if.h"
+
+#define DEFAULT_RCLK 29491200
+
+static int sab82532_bfe_attach(struct scc_softc *, int);
+static int sab82532_bfe_iclear(struct scc_softc *, struct scc_chan *);
+static int sab82532_bfe_ipend(struct scc_softc *);
+static int sab82532_bfe_probe(struct scc_softc *);
+
+static kobj_method_t sab82532_methods[] = {
+ KOBJMETHOD(scc_attach, sab82532_bfe_attach),
+ KOBJMETHOD(scc_iclear, sab82532_bfe_iclear),
+ KOBJMETHOD(scc_ipend, sab82532_bfe_ipend),
+ KOBJMETHOD(scc_probe, sab82532_bfe_probe),
+ { 0, 0 }
+};
+
+struct scc_class scc_sab82532_class = {
+ "sab82532 class",
+ sab82532_methods,
+ sizeof(struct scc_softc),
+ .cl_channels = SAB_NCHAN,
+ .cl_class = SCC_CLASS_SAB82532,
+ .cl_modes = SCC_MODE_ASYNC | SCC_MODE_BISYNC | SCC_MODE_HDLC,
+ .cl_range = SAB_CHANLEN,
+ .cl_rclk = DEFAULT_RCLK,
+ .cl_regshft = 0
+};
+
+static int
+sab82532_bfe_attach(struct scc_softc *sc, int reset)
+{
+ struct scc_bas *bas;
+
+ bas = &sc->sc_bas;
+ return (0);
+}
+
+static int
+sab82532_bfe_iclear(struct scc_softc *sc, struct scc_chan *ch)
+{
+
+ return (0);
+}
+
+static int
+sab82532_bfe_ipend(struct scc_softc *sc)
+{
+ struct scc_bas *bas;
+ struct scc_chan *ch;
+ int ipend;
+ int c, ofs;
+ uint8_t isr0, isr1;
+
+ bas = &sc->sc_bas;
+ ipend = 0;
+ for (c = 0; c < SAB_NCHAN; c++) {
+ ch = &sc->sc_chan[c];
+ ofs = c * SAB_CHANLEN;
+ mtx_lock_spin(&sc->sc_hwmtx);
+ isr0 = scc_getreg(bas, ofs + SAB_ISR0);
+ isr1 = scc_getreg(bas, ofs + SAB_ISR1);
+ scc_barrier(bas);
+ if (isr0 & SAB_ISR0_TIME) {
+ while (scc_getreg(bas, ofs + SAB_STAR) & SAB_STAR_CEC)
+ ;
+ scc_setreg(bas, ofs + SAB_CMDR, SAB_CMDR_RFRD);
+ scc_barrier(bas);
+ }
+ mtx_unlock_spin(&sc->sc_hwmtx);
+
+ ch->ch_ipend = 0;
+ if (isr1 & SAB_ISR1_BRKT)
+ ch->ch_ipend |= SER_INT_BREAK;
+ if (isr0 & SAB_ISR0_RFO)
+ ch->ch_ipend |= SER_INT_OVERRUN;
+ if (isr0 & (SAB_ISR0_TCD|SAB_ISR0_RPF))
+ ch->ch_ipend |= SER_INT_RXREADY;
+ if ((isr0 & SAB_ISR0_CDSC) || (isr1 & SAB_ISR1_CSC))
+ ch->ch_ipend |= SER_INT_SIGCHG;
+ if (isr1 & SAB_ISR1_ALLS)
+ ch->ch_ipend |= SER_INT_TXIDLE;
+ ipend |= ch->ch_ipend;
+ }
+ return (ipend);
+}
+
+static int
+sab82532_bfe_probe(struct scc_softc *sc)
+{
+ struct scc_bas *bas;
+
+ bas = &sc->sc_bas;
+ return (0);
+}
diff --git a/sys/dev/scc/scc_dev_z8530.c b/sys/dev/scc/scc_dev_z8530.c
new file mode 100644
index 0000000..1af8880
--- /dev/null
+++ b/sys/dev/scc/scc_dev_z8530.c
@@ -0,0 +1,202 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/serial.h>
+
+#include <dev/scc/scc_bfe.h>
+#include <dev/scc/scc_bus.h>
+
+#include <dev/ic/z8530.h>
+
+#include "scc_if.h"
+
+#define DEFAULT_RCLK 307200
+
+static int z8530_bfe_attach(struct scc_softc *, int);
+static int z8530_bfe_iclear(struct scc_softc *, struct scc_chan *);
+static int z8530_bfe_ipend(struct scc_softc *);
+static int z8530_bfe_probe(struct scc_softc *);
+
+static kobj_method_t z8530_methods[] = {
+ KOBJMETHOD(scc_attach, z8530_bfe_attach),
+ KOBJMETHOD(scc_iclear, z8530_bfe_iclear),
+ KOBJMETHOD(scc_ipend, z8530_bfe_ipend),
+ KOBJMETHOD(scc_probe, z8530_bfe_probe),
+ { 0, 0 }
+};
+
+struct scc_class scc_z8530_class = {
+ "z8530 class",
+ z8530_methods,
+ sizeof(struct scc_softc),
+ .cl_channels = 2,
+ .cl_class = SCC_CLASS_Z8530,
+ .cl_modes = SCC_MODE_ASYNC | SCC_MODE_BISYNC | SCC_MODE_HDLC,
+ .cl_range = (CHAN_B - CHAN_A) << 1,
+ .cl_rclk = DEFAULT_RCLK,
+ .cl_regshft = 1,
+};
+
+/* Multiplexed I/O. */
+static __inline void
+scc_setmreg(struct scc_bas *bas, int ch, int reg, int val)
+{
+
+ scc_setreg(bas, ch + REG_CTRL, reg);
+ scc_barrier(bas);
+ scc_setreg(bas, ch + REG_CTRL, val);
+}
+
+static __inline uint8_t
+scc_getmreg(struct scc_bas *bas, int ch, int reg)
+{
+
+ scc_setreg(bas, ch + REG_CTRL, reg);
+ scc_barrier(bas);
+ return (scc_getreg(bas, ch + REG_CTRL));
+}
+
+static int
+z8530_bfe_attach(struct scc_softc *sc, int reset)
+{
+ struct scc_bas *bas;
+
+ bas = &sc->sc_bas;
+ return (0);
+}
+
+static int
+z8530_bfe_iclear(struct scc_softc *sc, struct scc_chan *ch)
+{
+ struct scc_bas *bas;
+ int c;
+
+ bas = &sc->sc_bas;
+ c = (ch->ch_nr == 1) ? CHAN_A : CHAN_B;
+ mtx_lock_spin(&sc->sc_hwmtx);
+ if (ch->ch_ipend & SER_INT_TXIDLE) {
+ scc_setreg(bas, c + REG_CTRL, CR_RSTTXI);
+ scc_barrier(bas);
+ }
+ if (ch->ch_ipend & SER_INT_RXREADY) {
+ scc_getreg(bas, c + REG_DATA);
+ scc_barrier(bas);
+ }
+ if (ch->ch_ipend & (SER_INT_OVERRUN|SER_INT_BREAK))
+ scc_setreg(bas, c + REG_CTRL, CR_RSTERR);
+ mtx_unlock_spin(&sc->sc_hwmtx);
+ return (0);
+}
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+static int
+z8530_bfe_ipend(struct scc_softc *sc)
+{
+ struct scc_bas *bas;
+ struct scc_chan *ch[2];
+ uint32_t sig;
+ uint8_t bes, ip, src;
+
+ bas = &sc->sc_bas;
+ ch[0] = &sc->sc_chan[0];
+ ch[1] = &sc->sc_chan[1];
+ ch[0]->ch_ipend = 0;
+ ch[1]->ch_ipend = 0;
+
+ mtx_lock_spin(&sc->sc_hwmtx);
+ ip = scc_getmreg(bas, CHAN_A, RR_IP);
+ if (ip & IP_RIA)
+ ch[0]->ch_ipend |= SER_INT_RXREADY;
+ if (ip & IP_RIB)
+ ch[1]->ch_ipend |= SER_INT_RXREADY;
+ if (ip & IP_TIA)
+ ch[0]->ch_ipend |= SER_INT_TXIDLE;
+ if (ip & IP_TIB)
+ ch[1]->ch_ipend |= SER_INT_TXIDLE;
+ if (ip & IP_SIA) {
+ scc_setreg(bas, CHAN_A + REG_CTRL, CR_RSTXSI);
+ scc_barrier(bas);
+ bes = scc_getreg(bas, CHAN_A + REG_CTRL);
+ if (bes & BES_BRK)
+ ch[0]->ch_ipend |= SER_INT_BREAK;
+ sig = ch[0]->ch_hwsig;
+ SIGCHG(bes & BES_CTS, sig, SER_CTS, SER_DCTS);
+ SIGCHG(bes & BES_DCD, sig, SER_DCD, SER_DDCD);
+ SIGCHG(bes & BES_SYNC, sig, SER_DSR, SER_DDSR);
+ if (sig & SER_MASK_DELTA) {
+ ch[0]->ch_hwsig = sig;
+ ch[0]->ch_ipend |= SER_INT_SIGCHG;
+ }
+ src = scc_getmreg(bas, CHAN_A, RR_SRC);
+ if (src & SRC_OVR)
+ ch[0]->ch_ipend |= SER_INT_OVERRUN;
+ }
+ if (ip & IP_SIB) {
+ scc_setreg(bas, CHAN_B + REG_CTRL, CR_RSTXSI);
+ scc_barrier(bas);
+ bes = scc_getreg(bas, CHAN_B + REG_CTRL);
+ if (bes & BES_BRK)
+ ch[1]->ch_ipend |= SER_INT_BREAK;
+ sig = ch[1]->ch_hwsig;
+ SIGCHG(bes & BES_CTS, sig, SER_CTS, SER_DCTS);
+ SIGCHG(bes & BES_DCD, sig, SER_DCD, SER_DDCD);
+ SIGCHG(bes & BES_SYNC, sig, SER_DSR, SER_DDSR);
+ if (sig & SER_MASK_DELTA) {
+ ch[1]->ch_hwsig = sig;
+ ch[1]->ch_ipend |= SER_INT_SIGCHG;
+ }
+ src = scc_getmreg(bas, CHAN_B, RR_SRC);
+ if (src & SRC_OVR)
+ ch[1]->ch_ipend |= SER_INT_OVERRUN;
+ }
+ mtx_unlock_spin(&sc->sc_hwmtx);
+
+ return (ch[0]->ch_ipend | ch[1]->ch_ipend);
+}
+
+static int
+z8530_bfe_probe(struct scc_softc *sc)
+{
+ struct scc_bas *bas;
+
+ bas = &sc->sc_bas;
+ return (0);
+}
diff --git a/sys/dev/scc/scc_if.m b/sys/dev/scc/scc_if.m
new file mode 100644
index 0000000..8aa30a4
--- /dev/null
+++ b/sys/dev/scc/scc_if.m
@@ -0,0 +1,77 @@
+#-
+# Copyright (c) 2004-2006 Marcel Moolenaar
+# 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.
+#
+# 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.
+#
+# $FreeBSD$
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <dev/scc/scc_bfe.h>
+
+# The SCC hardware interface. The core SCC code is hardware independent.
+# The details of the hardware are abstracted by the SCC hardware interface.
+
+INTERFACE scc;
+
+# attach() - attach hardware.
+# This method is called when the device is being attached. All resources
+# have been allocated. The intend of this method is to setup the hardware
+# for normal operation.
+# The reset parameter informs the hardware driver whether a full device
+# reset is allowed or not. This is important when one of the channels can
+# be used as system console and a hardware reset would disrupt output.
+METHOD int attach {
+ struct scc_softc *this;
+ int reset;
+};
+
+METHOD void iclear {
+ struct scc_softc *this;
+ struct scc_chan *chan;
+};
+
+# ipend() - query SCC for pending interrupts.
+# When an interrupt is signalled, the handler will call this method to find
+# out which of the interrupt sources needs attention. The handler will use
+# this information to dispatch service routines that deal with each of the
+# interrupt sources. An advantage of this approach is that it allows multi-
+# port drivers (like puc(4)) to query multiple devices concurrently and
+# service them on an interrupt priority basis. If the hardware cannot provide
+# the information reliably, it is free to service the interrupt and return 0,
+# meaning that no attention is required.
+METHOD int ipend {
+ struct scc_softc *this;
+}
+
+# probe() - detect hardware.
+# This method is called as part of the bus probe to make sure the
+# hardware exists. This function should also set the device description
+# to something that represents the hardware.
+METHOD int probe {
+ struct scc_softc *this;
+};
diff --git a/sys/dev/uart/uart_bus_scc.c b/sys/dev/uart/uart_bus_scc.c
new file mode 100644
index 0000000..9fdcb8b
--- /dev/null
+++ b/sys/dev/uart/uart_bus_scc.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2004-2006 Marcel Moolenaar
+ * 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.
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/scc/scc_bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+
+static int uart_scc_attach(device_t dev);
+static int uart_scc_probe(device_t dev);
+
+static device_method_t uart_scc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_scc_probe),
+ DEVMETHOD(device_attach, uart_scc_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ /* Serdev interface */
+ DEVMETHOD(serdev_ihand, uart_bus_ihand),
+ DEVMETHOD(serdev_sysdev, uart_bus_sysdev),
+ { 0, 0 }
+};
+
+static driver_t uart_scc_driver = {
+ uart_driver_name,
+ uart_scc_methods,
+ sizeof(struct uart_softc),
+};
+
+static int
+uart_scc_attach(device_t dev)
+{
+ device_t parent;
+ struct uart_softc *sc;
+ uintptr_t mtx;
+
+ parent = device_get_parent(dev);
+ sc = device_get_softc(dev);
+
+ if (BUS_READ_IVAR(parent, dev, SCC_IVAR_HWMTX, &mtx))
+ return (ENXIO);
+ sc->sc_hwmtx = (struct mtx *)(void *)mtx;
+ return (uart_bus_attach(dev));
+}
+
+static int
+uart_scc_probe(device_t dev)
+{
+ device_t parent;
+ struct uart_softc *sc;
+ uintptr_t ch, cl, md, rs;
+
+ parent = device_get_parent(dev);
+ sc = device_get_softc(dev);
+
+ if (BUS_READ_IVAR(parent, dev, SCC_IVAR_MODE, &md) ||
+ BUS_READ_IVAR(parent, dev, SCC_IVAR_CLASS, &cl))
+ return (ENXIO);
+ if (md != SCC_MODE_ASYNC)
+ return (ENXIO);
+ switch (cl) {
+ case SCC_CLASS_SAB82532:
+ sc->sc_class = &uart_sab82532_class;
+ break;
+ case SCC_CLASS_Z8530:
+ sc->sc_class = &uart_z8530_class;
+ break;
+ default:
+ return (ENXIO);
+ }
+ if (BUS_READ_IVAR(parent, dev, SCC_IVAR_CHANNEL, &ch) ||
+ BUS_READ_IVAR(parent, dev, SCC_IVAR_CLOCK, &cl) ||
+ BUS_READ_IVAR(parent, dev, SCC_IVAR_REGSHFT, &rs))
+ return (ENXIO);
+
+ return (uart_bus_probe(dev, rs, cl, 0, ch));
+}
+
+DRIVER_MODULE(uart, scc, uart_scc_driver, uart_devclass, 0, 0);
diff --git a/sys/kern/serdev_if.m b/sys/kern/serdev_if.m
new file mode 100644
index 0000000..ce7f572
--- /dev/null
+++ b/sys/kern/serdev_if.m
@@ -0,0 +1,79 @@
+#-
+# Copyright (c) 2006 Marcel Moolenaar
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <sys/serial.h>
+
+# The serdev interface is used by umbrella drivers and children thereof to
+# establish a more intimate relationship, necessary for efficient handling
+# of multiple (concurrent) serial communication channels. Examples include
+# serial communications controller (SCC) drivers, multi-I/O adapter drivers
+# and intelligent multi-port serial drivers. Methods specifically deal
+# with interrupt handling and configuration. Conceptually, the umbrella
+# driver is responsible for the overall operation of the hardware and uses
+# child drivers to handle each individual channel.
+# The serdev interface is intended to inherit the device interface.
+
+INTERFACE serdev;
+
+# Default implementations of some methods.
+CODE {
+ static serdev_intr_t *
+ default_ihand(device_t dev, int ipend)
+ {
+ return (NULL);
+ }
+
+ static int
+ default_sysdev(device_t dev)
+ {
+ return (0);
+ }
+};
+
+# ihand() - Query serial device interrupt handler.
+# This method is called by the umbrella driver to obtain function pointers
+# to interrupt handlers for each individual interrupt source. This allows
+# the umbralla driver to control the servicing of interrupts between the
+# different channels in the most flexible way.
+METHOD serdev_intr_t* ihand {
+ device_t dev;
+ int ipend;
+} DEFAULT default_ihand;
+
+# sysdev() - Query system device status
+# This method may be called by the umbrella driver for each child driver
+# to establish if a particular channel and mode is currently being used
+# for system specific usage. If this is the case, the hardware is not
+# reset and the channel will not change its operation mode.
+# The return value is !0 if the channel and mode are used for a system
+# device and 0 otherwise.
+METHOD int sysdev {
+ device_t dev;
+} DEFAULT default_sysdev;
+
diff --git a/sys/modules/scc/Makefile b/sys/modules/scc/Makefile
new file mode 100644
index 0000000..df3d95e
--- /dev/null
+++ b/sys/modules/scc/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/scc
+
+KMOD= scc
+SRCS= scc_bfe_ebus.c scc_bfe_sbus.c \
+ scc_core.c scc_if.c scc_if.h \
+ scc_dev_sab82532.c scc_dev_z8530.c
+SRCS+= bus_if.h device_if.h ofw_bus_if.h serdev_if.c serdev_if.h
+
+MFILES= dev/ofw/ofw_bus_if.m dev/scc/scc_if.m \
+ kern/bus_if.m kern/device_if.m kern/serdev_if.m
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud