diff options
Diffstat (limited to 'sys/dev/scc/scc_dev_z8530.c')
| -rw-r--r-- | sys/dev/scc/scc_dev_z8530.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/sys/dev/scc/scc_dev_z8530.c b/sys/dev/scc/scc_dev_z8530.c new file mode 100644 index 000000000000..3d63c227b248 --- /dev/null +++ b/sys/dev/scc/scc_dev_z8530.c @@ -0,0 +1,198 @@ +/*- + * 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" + +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, +}; + +/* 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); +} |
