summaryrefslogtreecommitdiff
path: root/sys/arch/i386/isa/mms.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/i386/isa/mms.c')
-rw-r--r--sys/arch/i386/isa/mms.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/sys/arch/i386/isa/mms.c b/sys/arch/i386/isa/mms.c
new file mode 100644
index 00000000000..41e8b6b435e
--- /dev/null
+++ b/sys/arch/i386/isa/mms.c
@@ -0,0 +1,253 @@
+/* $OpenBSD: mms.c,v 1.14 2001/02/20 23:53:27 jbm Exp $ */
+/* $NetBSD: mms.c,v 1.35 2000/01/08 02:57:25 takemura Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994 Charles M. Hannum.
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/isa/isavar.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+#define MMS_ADDR 0 /* offset for register select */
+#define MMS_DATA 1 /* offset for InPort data */
+#define MMS_IDENT 2 /* offset for identification register */
+#define MMS_NPORTS 4
+
+struct mms_softc { /* driver status information */
+ struct device sc_dev;
+ void *sc_ih;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ int sc_enabled; /* device is open */
+
+ struct device *sc_wsmousedev;
+};
+
+int mmsprobe __P((struct device *, void *, void *));
+void mmsattach __P((struct device *, struct device *, void *));
+int mmsintr __P((void *));
+
+struct cfattach mms_ca = {
+ sizeof(struct mms_softc), mmsprobe, mmsattach
+};
+
+int mms_enable __P((void *));
+int mms_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
+void mms_disable __P((void *));
+
+const struct wsmouse_accessops mms_accessops = {
+ mms_enable,
+ mms_ioctl,
+ mms_disable,
+};
+
+int
+mmsprobe(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ bus_space_tag_t iot = ia->ia_iot;
+ bus_space_handle_t ioh;
+ int rv;
+
+ /* Disallow wildcarded i/o address. */
+ if (ia->ia_iobase == IOBASEUNK)
+ return 0;
+
+ /* Map the i/o space. */
+ if (bus_space_map(iot, ia->ia_iobase, MMS_NPORTS, 0, &ioh))
+ return 0;
+
+ rv = 0;
+
+ /* Read identification register to see if present */
+ if (bus_space_read_1(iot, ioh, MMS_IDENT) != 0xde)
+ goto out;
+
+ /* Seems it was there; reset. */
+ bus_space_write_1(iot, ioh, MMS_ADDR, 0x87);
+
+ rv = 1;
+ ia->ia_iosize = MMS_NPORTS;
+ ia->ia_msize = 0;
+
+out:
+ bus_space_unmap(iot, ioh, MMS_NPORTS);
+ return rv;
+}
+
+void
+mmsattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct mms_softc *sc = (void *)self;
+ struct isa_attach_args *ia = aux;
+ bus_space_tag_t iot = ia->ia_iot;
+ bus_space_handle_t ioh;
+ struct wsmousedev_attach_args a;
+
+ printf("\n");
+
+ if (bus_space_map(iot, ia->ia_iobase, MMS_NPORTS, 0, &ioh)) {
+ printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /* Other initialization was done by mmsprobe. */
+ sc->sc_iot = iot;
+ sc->sc_ioh = ioh;
+ sc->sc_enabled = 0;
+
+ sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_PULSE,
+ IPL_TTY, mmsintr, sc, sc->sc_dev.dv_xname);
+
+ a.accessops = &mms_accessops;
+ a.accesscookie = sc;
+
+ /*
+ * Attach the wsmouse, saving a handle to it.
+ * Note that we don't need to check this pointer against NULL
+ * here or in psmintr, because if this fails lms_enable() will
+ * never be called, so lmsintr() will never be called.
+ */
+ sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
+}
+
+int
+mms_enable(v)
+ void *v;
+{
+ struct mms_softc *sc = v;
+
+ if (sc->sc_enabled)
+ return EBUSY;
+
+ sc->sc_enabled = 1;
+
+ /* Enable interrupts. */
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_ADDR, 0x07);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_DATA, 0x09);
+
+ return 0;
+}
+
+void
+mms_disable(v)
+ void *v;
+{
+ struct mms_softc *sc = v;
+
+ /* Disable interrupts. */
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_ADDR, 0x87);
+
+ sc->sc_enabled = 0;
+}
+
+int
+mms_ioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+#if 0
+ struct mms_softc *sc = v;
+#endif
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_MMS;
+ return (0);
+ }
+ return (-1);
+}
+
+int
+mmsintr(arg)
+ void *arg;
+{
+ struct mms_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_char status;
+ signed char dx, dy;
+ u_int buttons;
+ int changed;
+
+ if (!sc->sc_enabled)
+ /* Interrupts are not expected. */
+ return 0;
+
+ /* Freeze InPort registers (disabling interrupts). */
+ bus_space_write_1(iot, ioh, MMS_ADDR, 0x07);
+ bus_space_write_1(iot, ioh, MMS_DATA, 0x29);
+
+ bus_space_write_1(iot, ioh, MMS_ADDR, 0x00);
+ status = bus_space_read_1(iot, ioh, MMS_DATA);
+
+ if (status & 0x40) {
+ bus_space_write_1(iot, ioh, MMS_ADDR, 1);
+ dx = bus_space_read_1(iot, ioh, MMS_DATA);
+ /* Bounding at -127 avoids a bug in XFree86. */
+ dx = (dx == -128) ? -127 : dx;
+
+ bus_space_write_1(iot, ioh, MMS_ADDR, 2);
+ dy = bus_space_read_1(iot, ioh, MMS_DATA);
+ dy = (dy == -128) ? 127 : -dy;
+ } else
+ dx = dy = 0;
+
+ /* Unfreeze InPort registers (reenabling interrupts). */
+ bus_space_write_1(iot, ioh, MMS_ADDR, 0x07);
+ bus_space_write_1(iot, ioh, MMS_DATA, 0x09);
+
+ buttons = ((status & 0x04) ? 0x1 : 0) |
+ ((status & 0x02) ? 0x2 : 0) |
+ ((status & 0x01) ? 0x4 : 0);
+ changed = status & 0x38;
+
+ if (dx || dy || changed)
+ wsmouse_input(sc->sc_wsmousedev,
+ buttons, dx, dy, 0, WSMOUSE_INPUT_DELTA);
+
+ return -1;
+}
+
+struct cfdriver mms_cd = {
+ NULL, "mms", DV_DULL
+};