1 1.58 thorpej /* $NetBSD: lms.c,v 1.58 2021/08/07 16:18:55 thorpej Exp $ */ 2 1.14 cgd 3 1.1 andrew /*- 4 1.35 mycroft * Copyright (c) 1993, 1994 Charles M. Hannum. 5 1.1 andrew * Copyright (c) 1992, 1993 Erik Forsberg. 6 1.1 andrew * All rights reserved. 7 1.1 andrew * 8 1.1 andrew * Redistribution and use in source and binary forms, with or without 9 1.1 andrew * modification, are permitted provided that the following conditions 10 1.1 andrew * are met: 11 1.1 andrew * 1. Redistributions of source code must retain the above copyright 12 1.1 andrew * notice, this list of conditions and the following disclaimer. 13 1.1 andrew * 14 1.1 andrew * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 1.1 andrew * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 1.1 andrew * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 17 1.1 andrew * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 1.1 andrew * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 1.1 andrew * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 1.1 andrew * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 1.1 andrew * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 1.1 andrew * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 1.1 andrew * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 1.1 andrew */ 25 1.39 lukem 26 1.39 lukem #include <sys/cdefs.h> 27 1.58 thorpej __KERNEL_RCSID(0, "$NetBSD: lms.c,v 1.58 2021/08/07 16:18:55 thorpej Exp $"); 28 1.1 andrew 29 1.7 mycroft #include <sys/param.h> 30 1.7 mycroft #include <sys/systm.h> 31 1.7 mycroft #include <sys/ioctl.h> 32 1.8 mycroft #include <sys/device.h> 33 1.7 mycroft 34 1.56 dyoung #include <sys/bus.h> 35 1.26 mycroft #include <machine/intr.h> 36 1.1 andrew 37 1.19 cgd #include <dev/isa/isavar.h> 38 1.1 andrew 39 1.37 drochner #include <dev/wscons/wsconsio.h> 40 1.37 drochner #include <dev/wscons/wsmousevar.h> 41 1.37 drochner 42 1.8 mycroft #define LMS_DATA 0 /* offset for data port, read-only */ 43 1.8 mycroft #define LMS_SIGN 1 /* offset for signature port, read-write */ 44 1.8 mycroft #define LMS_INTR 2 /* offset for interrupt port, read-only */ 45 1.8 mycroft #define LMS_CNTRL 2 /* offset for control port, write-only */ 46 1.8 mycroft #define LMS_CONFIG 3 /* for configuration port, read-write */ 47 1.8 mycroft #define LMS_NPORTS 4 48 1.8 mycroft 49 1.8 mycroft struct lms_softc { /* driver status information */ 50 1.19 cgd void *sc_ih; 51 1.8 mycroft 52 1.30 thorpej bus_space_tag_t sc_iot; /* bus i/o space identifier */ 53 1.30 thorpej bus_space_handle_t sc_ioh; /* bus i/o handle */ 54 1.23 thorpej 55 1.37 drochner int sc_enabled; /* device is open */ 56 1.37 drochner int oldbuttons; /* mouse button status */ 57 1.37 drochner 58 1.55 cegger device_t sc_wsmousedev; 59 1.10 mycroft }; 60 1.1 andrew 61 1.54 joerg static int lmsprobe(device_t, cfdata_t, void *); 62 1.54 joerg static void lmsattach(device_t, device_t, void *); 63 1.54 joerg static int lmsintr(void *); 64 1.1 andrew 65 1.54 joerg CFATTACH_DECL_NEW(lms, sizeof(struct lms_softc), 66 1.44 thorpej lmsprobe, lmsattach, NULL, NULL); 67 1.22 thorpej 68 1.54 joerg static int lms_enable(void *); 69 1.54 joerg static int lms_ioctl(void *, u_long, void *, int, struct lwp *); 70 1.54 joerg static void lms_disable(void *); 71 1.37 drochner 72 1.54 joerg static const struct wsmouse_accessops lms_accessops = { 73 1.37 drochner lms_enable, 74 1.37 drochner lms_ioctl, 75 1.37 drochner lms_disable, 76 1.37 drochner }; 77 1.8 mycroft 78 1.54 joerg static int 79 1.54 joerg lmsprobe(device_t parent, cfdata_t match, void *aux) 80 1.1 andrew { 81 1.10 mycroft struct isa_attach_args *ia = aux; 82 1.30 thorpej bus_space_tag_t iot = ia->ia_iot; 83 1.30 thorpej bus_space_handle_t ioh; 84 1.23 thorpej int rv; 85 1.40 thorpej 86 1.40 thorpej if (ia->ia_nio < 1) 87 1.40 thorpej return (0); 88 1.40 thorpej if (ia->ia_nirq < 1) 89 1.40 thorpej return (0); 90 1.40 thorpej 91 1.40 thorpej if (ISA_DIRECT_CONFIG(ia)) 92 1.40 thorpej return (0); 93 1.40 thorpej 94 1.31 thorpej /* Disallow wildcarded i/o base. */ 95 1.45 drochner if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 96 1.40 thorpej return 0; 97 1.45 drochner if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ) 98 1.31 thorpej return 0; 99 1.31 thorpej 100 1.23 thorpej /* Map the i/o space. */ 101 1.40 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, LMS_NPORTS, 0, &ioh)) 102 1.23 thorpej return 0; 103 1.23 thorpej 104 1.23 thorpej rv = 0; 105 1.1 andrew 106 1.8 mycroft /* Configure and check for port present. */ 107 1.30 thorpej bus_space_write_1(iot, ioh, LMS_CONFIG, 0x91); 108 1.9 mycroft delay(10); 109 1.30 thorpej bus_space_write_1(iot, ioh, LMS_SIGN, 0x0c); 110 1.9 mycroft delay(10); 111 1.30 thorpej if (bus_space_read_1(iot, ioh, LMS_SIGN) != 0x0c) 112 1.23 thorpej goto out; 113 1.30 thorpej bus_space_write_1(iot, ioh, LMS_SIGN, 0x50); 114 1.9 mycroft delay(10); 115 1.30 thorpej if (bus_space_read_1(iot, ioh, LMS_SIGN) != 0x50) 116 1.23 thorpej goto out; 117 1.1 andrew 118 1.8 mycroft /* Disable interrupts. */ 119 1.30 thorpej bus_space_write_1(iot, ioh, LMS_CNTRL, 0x10); 120 1.1 andrew 121 1.23 thorpej rv = 1; 122 1.40 thorpej ia->ia_nio = 1; 123 1.40 thorpej ia->ia_io[0].ir_size = LMS_NPORTS; 124 1.40 thorpej 125 1.40 thorpej ia->ia_nirq = 1; 126 1.40 thorpej 127 1.40 thorpej ia->ia_niomem = 0; 128 1.40 thorpej ia->ia_ndrq = 0; 129 1.23 thorpej 130 1.23 thorpej out: 131 1.30 thorpej bus_space_unmap(iot, ioh, LMS_NPORTS); 132 1.23 thorpej return rv; 133 1.1 andrew } 134 1.1 andrew 135 1.54 joerg static void 136 1.54 joerg lmsattach(device_t parent, device_t self, void *aux) 137 1.1 andrew { 138 1.54 joerg struct lms_softc *sc = device_private(self); 139 1.10 mycroft struct isa_attach_args *ia = aux; 140 1.32 mycroft bus_space_tag_t iot = ia->ia_iot; 141 1.32 mycroft bus_space_handle_t ioh; 142 1.37 drochner struct wsmousedev_attach_args a; 143 1.11 mycroft 144 1.48 thorpej aprint_naive(": Mouse\n"); 145 1.48 thorpej aprint_normal(": Logitech Mouse\n"); 146 1.1 andrew 147 1.40 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, LMS_NPORTS, 0, &ioh)) { 148 1.54 joerg aprint_error_dev(self, "can't map i/o space\n"); 149 1.32 mycroft return; 150 1.32 mycroft } 151 1.32 mycroft 152 1.8 mycroft /* Other initialization was done by lmsprobe. */ 153 1.32 mycroft sc->sc_iot = iot; 154 1.32 mycroft sc->sc_ioh = ioh; 155 1.37 drochner sc->sc_enabled = 0; 156 1.12 mycroft 157 1.40 thorpej sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, 158 1.40 thorpej IST_PULSE, IPL_TTY, lmsintr, sc); 159 1.37 drochner 160 1.37 drochner a.accessops = &lms_accessops; 161 1.37 drochner a.accesscookie = sc; 162 1.37 drochner 163 1.37 drochner /* 164 1.37 drochner * Attach the wsmouse, saving a handle to it. 165 1.37 drochner * Note that we don't need to check this pointer against NULL 166 1.37 drochner * here or in psmintr, because if this fails lms_enable() will 167 1.37 drochner * never be called, so lmsintr() will never be called. 168 1.37 drochner */ 169 1.58 thorpej sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE); 170 1.1 andrew } 171 1.1 andrew 172 1.54 joerg static int 173 1.46 perry lms_enable(void *v) 174 1.1 andrew { 175 1.37 drochner struct lms_softc *sc = v; 176 1.1 andrew 177 1.37 drochner if (sc->sc_enabled) 178 1.8 mycroft return EBUSY; 179 1.1 andrew 180 1.37 drochner sc->sc_enabled = 1; 181 1.37 drochner sc->oldbuttons = 0; 182 1.1 andrew 183 1.8 mycroft /* Enable interrupts. */ 184 1.30 thorpej bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMS_CNTRL, 0); 185 1.1 andrew 186 1.8 mycroft return 0; 187 1.1 andrew } 188 1.1 andrew 189 1.54 joerg static void 190 1.46 perry lms_disable(void *v) 191 1.1 andrew { 192 1.37 drochner struct lms_softc *sc = v; 193 1.1 andrew 194 1.8 mycroft /* Disable interrupts. */ 195 1.30 thorpej bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMS_CNTRL, 0x10); 196 1.1 andrew 197 1.37 drochner sc->sc_enabled = 0; 198 1.1 andrew } 199 1.1 andrew 200 1.54 joerg static int 201 1.52 christos lms_ioctl(void *v, u_long cmd, void *data, int flag, 202 1.51 christos struct lwp *l) 203 1.1 andrew { 204 1.37 drochner #if 0 205 1.37 drochner struct lms_softc *sc = v; 206 1.37 drochner #endif 207 1.1 andrew 208 1.1 andrew switch (cmd) { 209 1.37 drochner case WSMOUSEIO_GTYPE: 210 1.37 drochner *(u_int *)data = WSMOUSE_TYPE_LMS; 211 1.37 drochner return (0); 212 1.8 mycroft } 213 1.41 atatat return (EPASSTHROUGH); 214 1.1 andrew } 215 1.1 andrew 216 1.54 joerg static int 217 1.46 perry lmsintr(void *arg) 218 1.1 andrew { 219 1.19 cgd struct lms_softc *sc = arg; 220 1.30 thorpej bus_space_tag_t iot = sc->sc_iot; 221 1.30 thorpej bus_space_handle_t ioh = sc->sc_ioh; 222 1.37 drochner u_char hi, lo; 223 1.37 drochner signed char dx, dy; 224 1.37 drochner u_int buttons; 225 1.37 drochner int changed; 226 1.8 mycroft 227 1.37 drochner if (!sc->sc_enabled) 228 1.8 mycroft /* Interrupts are not expected. */ 229 1.8 mycroft return 0; 230 1.8 mycroft 231 1.30 thorpej bus_space_write_1(iot, ioh, LMS_CNTRL, 0xab); 232 1.30 thorpej hi = bus_space_read_1(iot, ioh, LMS_DATA); 233 1.30 thorpej bus_space_write_1(iot, ioh, LMS_CNTRL, 0x90); 234 1.30 thorpej lo = bus_space_read_1(iot, ioh, LMS_DATA); 235 1.8 mycroft dx = ((hi & 0x0f) << 4) | (lo & 0x0f); 236 1.8 mycroft /* Bounding at -127 avoids a bug in XFree86. */ 237 1.3 mycroft dx = (dx == -128) ? -127 : dx; 238 1.3 mycroft 239 1.30 thorpej bus_space_write_1(iot, ioh, LMS_CNTRL, 0xf0); 240 1.30 thorpej hi = bus_space_read_1(iot, ioh, LMS_DATA); 241 1.30 thorpej bus_space_write_1(iot, ioh, LMS_CNTRL, 0xd0); 242 1.30 thorpej lo = bus_space_read_1(iot, ioh, LMS_DATA); 243 1.8 mycroft dy = ((hi & 0x0f) << 4) | (lo & 0x0f); 244 1.1 andrew dy = (dy == -128) ? 127 : -dy; 245 1.3 mycroft 246 1.30 thorpej bus_space_write_1(iot, ioh, LMS_CNTRL, 0); 247 1.8 mycroft 248 1.37 drochner buttons = ((hi & 0x80) ? 0 : 0x1) | 249 1.37 drochner ((hi & 0x40) ? 0 : 0x2) | 250 1.37 drochner ((hi & 0x20) ? 0 : 0x4); 251 1.37 drochner changed = (buttons ^ sc->oldbuttons); 252 1.37 drochner sc->oldbuttons = buttons; 253 1.37 drochner 254 1.37 drochner if (dx || dy || changed) 255 1.37 drochner wsmouse_input(sc->sc_wsmousedev, 256 1.50 plunky buttons, 257 1.50 plunky dx, dy, 0, 0, 258 1.50 plunky WSMOUSE_INPUT_DELTA); 259 1.8 mycroft 260 1.12 mycroft return -1; 261 1.1 andrew } 262