diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-05-20 18:22:34 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-05-20 18:22:34 +0000 |
commit | ae4392e18d464ca5c9974696dfc309c032c0830c (patch) | |
tree | 7b7ddb329ff1c5e9062099a6d93d1211543e3a3e /sys/dev/sun/z8530ms.c | |
parent | c18b8a1b0101be40280a8fa45d190b4d7dfa3dba (diff) |
Add code to attach sun mice on sparc and sparc64 as wsmouse devices. Since
not all Sun mice run at the canonical 1200 bps, hop between 1200, 4800 and
9600 bps by paying attention to breaks on the line.
Attachement and engine code written 7 years ago for OpenBSD/sparc, except for
sparc64 com(4) attachment. Speed hop idea borrowed from Opensolaris.
This allows sparc and sparc64 users to run X11 without needing a configuration
file anymore, as it was in the XFree86 3.x days. Multihead configurations
will still need a minimal configuration file, though.
Diffstat (limited to 'sys/dev/sun/z8530ms.c')
-rw-r--r-- | sys/dev/sun/z8530ms.c | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/sys/dev/sun/z8530ms.c b/sys/dev/sun/z8530ms.c new file mode 100644 index 00000000000..c3e23c9d92d --- /dev/null +++ b/sys/dev/sun/z8530ms.c @@ -0,0 +1,473 @@ +/* $OpenBSD: z8530ms.c,v 1.1 2009/05/20 18:22:33 miod Exp $ */ +/* $NetBSD: ms.c,v 1.12 1997/07/17 01:17:47 jtk Exp $ */ + +/* + * Copyright (c) 2002, 2009, Miodrag Vallat + * 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. + * + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)ms.c 8.1 (Berkeley) 6/11/93 + */ + +/* + * Zilog Z8530 Dual UART driver (mouse interface) + * + * This is the "slave" driver that will be attached to + * the "zsc" driver for a Sun mouse. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/syslog.h> + +#ifndef __sparc64__ /* until zs driver is unified... */ +#include <sparc/dev/z8530reg.h> +#else +#include <sparc64/dev/z8530reg.h> +#endif +#include <machine/z8530var.h> + +#include <dev/wscons/wsmousevar.h> +#include <dev/sun/sunmsvar.h> + +/* + * How many input characters we can buffer. + * Note: must be a power of two! + */ +#define MS_RX_RING_SIZE 256 +#define MS_RX_RING_MASK (MS_RX_RING_SIZE-1) + +struct zsms_softc { + struct sunms_softc sc_base; + struct zs_chanstate *sc_cs; + + /* Flags to communicate with zsms_softint() */ + volatile int sc_intr_flags; +#define INTR_RX_OVERRUN 0x01 +#define INTR_TX_EMPTY 0x02 +#define INTR_ST_CHECK 0x04 +#define INTR_BPS_CHANGE 0x08 + + /* + * The receive ring buffer. + */ + uint sc_rbget; /* ring buffer `get' index */ + volatile uint sc_rbput; /* ring buffer `put' index */ + uint16_t sc_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */ +}; + +/* + * autoconf glue. + */ + +int zsms_match(struct device *, void *, void *); +void zsms_attach(struct device *, struct device *, void *); + +const struct cfattach zsms_ca = { + sizeof(struct zsms_softc), zsms_match, zsms_attach +}; + +struct cfdriver zsms_cd = { + NULL, "zsms", DV_DULL +}; + +/* + * wsmouse accessops. + */ + +void zsms_disable(void *); +int zsms_enable(void *); + +const struct wsmouse_accessops zsms_accessops = { + zsms_enable, + sunms_ioctl, + zsms_disable +}; + +/* + * zs glue. + */ + +void zsms_rxint(struct zs_chanstate *); +void zsms_softint(struct zs_chanstate *); +void zsms_stint(struct zs_chanstate *, int); +void zsms_txint(struct zs_chanstate *); + +struct zsops zsops_ms = { + zsms_rxint, /* receive char available */ + zsms_stint, /* external/status */ + zsms_txint, /* xmit buffer empty */ + zsms_softint /* process software interrupt */ +}; + +void zsms_speed_change(void *, uint); + +/* + * autoconf glue. + */ + +int +zsms_match(struct device *parent, void *vcf, void *aux) +{ + struct cfdata *cf = vcf; + struct zsc_attach_args *args = aux; + int rc; + + /* If we're not looking for a mouse, just exit */ + if (strcmp(args->type, "mouse") != 0) + return 0; + + rc = 10; + + /* Exact match is better than wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) + rc += 2; + + /* This driver accepts wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) + rc += 1; + + return rc; +} + +void +zsms_attach(struct device *parent, struct device *self, void *aux) +{ + struct zsc_softc *zsc = (struct zsc_softc *)parent; + struct zsms_softc *sc = (struct zsms_softc *)self; + struct zsc_attach_args *args = aux; + struct zs_chanstate *cs; + int channel; + int s; + + channel = args->channel; +#ifndef __sparc64__ /* until driver is unified... */ + cs = &zsc->zsc_cs[channel]; +#else + cs = zsc->zsc_cs[channel]; +#endif + cs->cs_private = sc; + cs->cs_ops = &zsops_ms; + sc->sc_cs = cs; + + /* Initialize hardware. */ + s = splzs(); + zs_write_reg(cs, 9, channel == 0 ? ZSWR9_A_RESET : ZSWR9_B_RESET); + /* disable interrupts until the mouse is enabled */ + CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE | ZSWR1_TIE); + /* 8 data bits is already our default */ + /* no parity, 2 stop bits */ + CLR(cs->cs_preg[4], ZSWR4_SBMASK | ZSWR4_PARMASK); + SET(cs->cs_preg[4], ZSWR4_TWOSB); + (void)zs_set_speed(cs, INIT_SPEED); + zs_loadchannelregs(cs); + splx(s); + + sc->sc_base.sc_speed_change = zsms_speed_change; + + sunms_attach(&sc->sc_base, &zsms_accessops); +} + +/* + * wsmouse accessops. + */ + +void +zsms_disable(void *v) +{ + struct zsms_softc *sc = v; + struct zs_chanstate *cs = sc->sc_cs; + int s; + + s = splzs(); + /* disable RX and status change interrupts */ + CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + zs_loadchannelregs(cs); + splx(s); +} + +int +zsms_enable(void *v) +{ + struct zsms_softc *sc = v; + struct zs_chanstate *cs = sc->sc_cs; + int s; + + s = splzs(); + /* enable RX and status change interrupts */ + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + zs_loadchannelregs(cs); + splx(s); + + return 0; +} + +/* + * zs glue. + */ + +void +zsms_rxint(struct zs_chanstate *cs) +{ + struct zsms_softc *sc = cs->cs_private; + int put, put_next; + u_char rr0, rr1, c; + + put = sc->sc_rbput; + + for (;;) { + /* + * First read the status, because reading the received char + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + /* + * Note that we do not try to change speed upon encountering + * framing errors, as this is not as reliable as breaks. + */ + if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + + if (sc->sc_base.sc_state != STATE_RATE_CHANGE) { + sc->sc_rbuf[put] = (c << 8) | rr1; + put_next = (put + 1) & MS_RX_RING_MASK; + + /* Would overrun if increment makes (put==get). */ + if (put_next == sc->sc_rbget) { + sc->sc_intr_flags |= INTR_RX_OVERRUN; + break; + } else { + /* OK, really increment. */ + put = put_next; + } + } + + rr0 = zs_read_csr(cs); + if (!ISSET(rr0, ZSRR0_RX_READY)) + break; + } + + /* Done reading. */ + sc->sc_rbput = put; + + cs->cs_softreq = 1; +} + +void +zsms_txint(struct zs_chanstate *cs) +{ + /* + * This function should never be invoked as we don't accept TX + * interrupts. If someone alters our configuration behind our + * back, just disable TX interrupts again. + */ + zs_write_csr(cs, ZSWR0_RESET_TXINT); + + /* disable tx interrupts */ + CLR(cs->cs_preg[1], ZSWR1_TIE); + zs_loadchannelregs(cs); +} + +void +zsms_stint(struct zs_chanstate *cs, int force) +{ + struct zsms_softc *sc = cs->cs_private; + uint8_t rr0, delta; + + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); + + /* + * A break can occur if the speed is not correct. + * However, we do not change speed until we get the second + * break, for switching speed when the mouse is unplugged + * will trigger a break and thus we'd loop changing speeds + * until the mouse is plugged again. + */ + if (!force && ISSET(rr0, ZSRR0_BREAK)) { + if (sc->sc_base.sc_state != STATE_RATE_CHANGE && + ++sc->sc_base.sc_brk > 1) { + sc->sc_intr_flags |= INTR_BPS_CHANGE; + sc->sc_base.sc_state = STATE_RATE_CHANGE; + cs->cs_softreq = 1; +#ifdef DEBUG + printf("%s: break detected, changing speed\n", + sc->sc_base.sc_dev.dv_xname); +#endif + } + } + + if (!force) + delta = rr0 ^ cs->cs_rr0; + else + delta = cs->cs_rr0_mask; + cs->cs_rr0 = rr0; + + if (ISSET(delta, cs->cs_rr0_mask)) { + SET(cs->cs_rr0_delta, delta); + + sc->sc_intr_flags |= INTR_ST_CHECK; + cs->cs_softreq = 1; + } +} + +void +zsms_softint(struct zs_chanstate *cs) +{ + struct zsms_softc *sc; + int get, c, s, s2; + int intr_flags; + u_short ring_data; + + sc = cs->cs_private; + + /* Atomically get and clear flags. */ + s = spltty(); + s2 = splzs(); + intr_flags = sc->sc_intr_flags; + sc->sc_intr_flags = 0; + /* Now lower to spltty for the rest. */ + splx(s2); + + /* + * If we have a baud rate change pending, do it now. + * This will reset the rx ring, so we can proceed safely. + */ + if (ISSET(intr_flags, INTR_BPS_CHANGE)) { + CLR(intr_flags, INTR_RX_OVERRUN); + sunms_speed_change(&sc->sc_base); + splx(s); + } + + /* + * Copy data from the receive ring, if any, to the event layer. + */ + get = sc->sc_rbget; + while (get != sc->sc_rbput) { + ring_data = sc->sc_rbuf[get]; + get = (get + 1) & MS_RX_RING_MASK; + + /* low byte of ring_data is rr1 */ + c = (ring_data >> 8) & 0xff; + + if (ring_data & ZSRR1_DO) + SET(intr_flags, INTR_RX_OVERRUN); + + /* Pass this up to the "middle" layer. */ + sunms_input(&sc->sc_base, c); + } + if (ISSET(intr_flags, INTR_RX_OVERRUN)) + log(LOG_ERR, "%s: input overrun\n", + sc->sc_base.sc_dev.dv_xname); + sc->sc_rbget = get; + + /* + * Status line change. Not expected except for break conditions. + */ + if (ISSET(intr_flags, INTR_ST_CHECK)) { + cs->cs_rr0_delta = 0; + } + + splx(s); +} + +/* + * Reinitialize the line to a different speed. Invoked at spltty(). + */ +void +zsms_speed_change(void *v, uint bps) +{ + struct zsms_softc *sc = v; + struct zs_chanstate *cs = sc->sc_cs; + uint8_t rr0; + int s; + + s = splzs(); + + /* + * Eat everything on the line. + */ + for (;;) { + rr0 = zs_read_csr(cs); + if (!ISSET(rr0, ZSRR0_RX_READY)) + break; + (void)zs_read_data(cs); + } + + (void)zs_set_speed(cs, sc->sc_base.sc_bps); + zs_loadchannelregs(cs); + zsms_stint(cs, 1); + + sc->sc_rbget = sc->sc_rbput = 0; + + splx(s); +} |