Add scc(4), a driver for serial communications controllers. These

controllers typically have multiple channels and support a number
of serial communications protocols. The scc(4) driver is itself
an umbrella driver that delegates the control over each channel
and mode to a subordinate driver (like uart(4)).
The scc(4) driver supports the Siemens SAB 82532 and the Zilog
Z8530 and replaces puc(4) for these devices.
This commit is contained in:
Marcel Moolenaar 2006-03-30 18:33:22 +00:00
parent 1d9c4393ff
commit 6174e6ed12
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157299
12 changed files with 1616 additions and 0 deletions

75
share/man/man4/scc.4 Normal file
View File

@ -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 .

153
sys/dev/scc/scc_bfe.h Normal file
View File

@ -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_ */

View File

@ -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);

View File

@ -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);

51
sys/dev/scc/scc_bus.h Normal file
View File

@ -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_ */

542
sys/dev/scc/scc_core.c Normal file
View File

@ -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);
}

View File

@ -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);
}

202
sys/dev/scc/scc_dev_z8530.c Normal file
View File

@ -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);
}

77
sys/dev/scc/scc_if.m Normal file
View File

@ -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;
};

115
sys/dev/uart/uart_bus_scc.c Normal file
View File

@ -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);

79
sys/kern/serdev_if.m Normal file
View File

@ -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;

14
sys/modules/scc/Makefile Normal file
View File

@ -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>