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:
parent
1d9c4393ff
commit
6174e6ed12
75
share/man/man4/scc.4
Normal file
75
share/man/man4/scc.4
Normal 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
153
sys/dev/scc/scc_bfe.h
Normal 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_ */
|
87
sys/dev/scc/scc_bfe_ebus.c
Normal file
87
sys/dev/scc/scc_bfe_ebus.c
Normal 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);
|
84
sys/dev/scc/scc_bfe_sbus.c
Normal file
84
sys/dev/scc/scc_bfe_sbus.c
Normal 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
51
sys/dev/scc/scc_bus.h
Normal 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
542
sys/dev/scc/scc_core.c
Normal 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);
|
||||
}
|
137
sys/dev/scc/scc_dev_sab82532.c
Normal file
137
sys/dev/scc/scc_dev_sab82532.c
Normal 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
202
sys/dev/scc/scc_dev_z8530.c
Normal 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
77
sys/dev/scc/scc_if.m
Normal 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
115
sys/dev/uart/uart_bus_scc.c
Normal 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
79
sys/kern/serdev_if.m
Normal 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
14
sys/modules/scc/Makefile
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user