1 1.40 dholland /* $NetBSD: ms.c,v 1.40 2014/07/25 08:10:39 dholland Exp $ */ 2 1.1 gwr 3 1.1 gwr /* 4 1.1 gwr * Copyright (c) 1992, 1993 5 1.1 gwr * The Regents of the University of California. All rights reserved. 6 1.1 gwr * 7 1.1 gwr * This software was developed by the Computer Systems Engineering group 8 1.1 gwr * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 gwr * contributed to Berkeley. 10 1.1 gwr * 11 1.1 gwr * All advertising materials mentioning features or use of this software 12 1.1 gwr * must display the following acknowledgement: 13 1.1 gwr * This product includes software developed by the University of 14 1.1 gwr * California, Lawrence Berkeley Laboratory. 15 1.1 gwr * 16 1.1 gwr * Redistribution and use in source and binary forms, with or without 17 1.1 gwr * modification, are permitted provided that the following conditions 18 1.1 gwr * are met: 19 1.1 gwr * 1. Redistributions of source code must retain the above copyright 20 1.1 gwr * notice, this list of conditions and the following disclaimer. 21 1.1 gwr * 2. Redistributions in binary form must reproduce the above copyright 22 1.1 gwr * notice, this list of conditions and the following disclaimer in the 23 1.1 gwr * documentation and/or other materials provided with the distribution. 24 1.27 agc * 3. Neither the name of the University nor the names of its contributors 25 1.1 gwr * may be used to endorse or promote products derived from this software 26 1.1 gwr * without specific prior written permission. 27 1.1 gwr * 28 1.1 gwr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 1.1 gwr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 1.1 gwr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 1.1 gwr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 1.1 gwr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 1.1 gwr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 1.1 gwr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 1.1 gwr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 1.1 gwr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 1.1 gwr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 1.1 gwr * SUCH DAMAGE. 39 1.1 gwr * 40 1.1 gwr * @(#)ms.c 8.1 (Berkeley) 6/11/93 41 1.1 gwr */ 42 1.1 gwr 43 1.1 gwr /* 44 1.1 gwr * Mouse driver (/dev/mouse) 45 1.1 gwr */ 46 1.1 gwr 47 1.1 gwr /* 48 1.1 gwr * Zilog Z8530 Dual UART driver (mouse interface) 49 1.1 gwr * 50 1.1 gwr * This is the "slave" driver that will be attached to 51 1.1 gwr * the "zsc" driver for a Sun mouse. 52 1.1 gwr */ 53 1.21 lukem 54 1.21 lukem #include <sys/cdefs.h> 55 1.40 dholland __KERNEL_RCSID(0, "$NetBSD: ms.c,v 1.40 2014/07/25 08:10:39 dholland Exp $"); 56 1.1 gwr 57 1.1 gwr #include <sys/param.h> 58 1.1 gwr #include <sys/systm.h> 59 1.11 gwr #include <sys/conf.h> 60 1.1 gwr #include <sys/device.h> 61 1.1 gwr #include <sys/ioctl.h> 62 1.1 gwr #include <sys/kernel.h> 63 1.11 gwr #include <sys/proc.h> 64 1.11 gwr #include <sys/signal.h> 65 1.11 gwr #include <sys/signalvar.h> 66 1.11 gwr #include <sys/time.h> 67 1.1 gwr #include <sys/syslog.h> 68 1.7 mrg #include <sys/select.h> 69 1.7 mrg #include <sys/poll.h> 70 1.1 gwr 71 1.11 gwr #include <machine/vuid_event.h> 72 1.11 gwr 73 1.1 gwr #include <dev/ic/z8530reg.h> 74 1.1 gwr #include <machine/z8530var.h> 75 1.16 mrg #include <dev/sun/event_var.h> 76 1.16 mrg #include <dev/sun/msvar.h> 77 1.1 gwr 78 1.24 petrov #include <dev/wscons/wsconsio.h> 79 1.24 petrov #include <dev/wscons/wsmousevar.h> 80 1.24 petrov 81 1.37 tsutsui #include "ioconf.h" 82 1.12 jtk #include "locators.h" 83 1.24 petrov #include "wsmouse.h" 84 1.1 gwr 85 1.22 gehenna dev_type_open(msopen); 86 1.22 gehenna dev_type_close(msclose); 87 1.22 gehenna dev_type_read(msread); 88 1.22 gehenna dev_type_ioctl(msioctl); 89 1.22 gehenna dev_type_poll(mspoll); 90 1.23 jdolecek dev_type_kqfilter(mskqfilter); 91 1.22 gehenna 92 1.22 gehenna const struct cdevsw ms_cdevsw = { 93 1.39 dholland .d_open = msopen, 94 1.39 dholland .d_close = msclose, 95 1.39 dholland .d_read = msread, 96 1.39 dholland .d_write = nowrite, 97 1.39 dholland .d_ioctl = msioctl, 98 1.39 dholland .d_stop = nostop, 99 1.39 dholland .d_tty = notty, 100 1.39 dholland .d_poll = mspoll, 101 1.39 dholland .d_mmap = nommap, 102 1.39 dholland .d_kqfilter = mskqfilter, 103 1.40 dholland .d_discard = nodiscard, 104 1.39 dholland .d_flag = D_OTHER 105 1.22 gehenna }; 106 1.1 gwr 107 1.1 gwr /**************************************************************** 108 1.1 gwr * Entry points for /dev/mouse 109 1.1 gwr * (open,close,read,write,...) 110 1.1 gwr ****************************************************************/ 111 1.1 gwr 112 1.1 gwr int 113 1.36 tsutsui msopen(dev_t dev, int flags, int mode, struct lwp *l) 114 1.1 gwr { 115 1.1 gwr struct ms_softc *ms; 116 1.1 gwr 117 1.37 tsutsui ms = device_lookup_private(&ms_cd, minor(dev)); 118 1.1 gwr if (ms == NULL) 119 1.37 tsutsui return ENXIO; 120 1.1 gwr 121 1.1 gwr /* This is an exclusive open device. */ 122 1.1 gwr if (ms->ms_events.ev_io) 123 1.37 tsutsui return EBUSY; 124 1.19 eeh 125 1.19 eeh if (ms->ms_deviopen) { 126 1.19 eeh int err; 127 1.36 tsutsui err = (*ms->ms_deviopen)(ms->ms_dev, flags); 128 1.29 perry if (err) 129 1.37 tsutsui return err; 130 1.19 eeh } 131 1.30 christos ms->ms_events.ev_io = l->l_proc; 132 1.1 gwr ev_init(&ms->ms_events); /* may cause sleep */ 133 1.1 gwr 134 1.1 gwr ms->ms_ready = 1; /* start accepting events */ 135 1.37 tsutsui return 0; 136 1.1 gwr } 137 1.1 gwr 138 1.1 gwr int 139 1.36 tsutsui msclose(dev_t dev, int flags, int mode, struct lwp *l) 140 1.1 gwr { 141 1.1 gwr struct ms_softc *ms; 142 1.1 gwr 143 1.37 tsutsui ms = device_lookup_private(&ms_cd, minor(dev)); 144 1.1 gwr ms->ms_ready = 0; /* stop accepting events */ 145 1.1 gwr ev_fini(&ms->ms_events); 146 1.1 gwr 147 1.1 gwr ms->ms_events.ev_io = NULL; 148 1.19 eeh if (ms->ms_deviclose) { 149 1.19 eeh int err; 150 1.36 tsutsui err = (*ms->ms_deviclose)(ms->ms_dev, flags); 151 1.29 perry if (err) 152 1.37 tsutsui return err; 153 1.19 eeh } 154 1.37 tsutsui return 0; 155 1.1 gwr } 156 1.1 gwr 157 1.1 gwr int 158 1.36 tsutsui msread(dev_t dev, struct uio *uio, int flags) 159 1.1 gwr { 160 1.1 gwr struct ms_softc *ms; 161 1.1 gwr 162 1.37 tsutsui ms = device_lookup_private(&ms_cd, minor(dev)); 163 1.37 tsutsui return ev_read(&ms->ms_events, uio, flags); 164 1.1 gwr } 165 1.1 gwr 166 1.1 gwr int 167 1.36 tsutsui msioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 168 1.1 gwr { 169 1.1 gwr struct ms_softc *ms; 170 1.1 gwr 171 1.37 tsutsui ms = device_lookup_private(&ms_cd, minor(dev)); 172 1.1 gwr 173 1.1 gwr switch (cmd) { 174 1.1 gwr 175 1.1 gwr case FIONBIO: /* we will remove this someday (soon???) */ 176 1.37 tsutsui return 0; 177 1.1 gwr 178 1.1 gwr case FIOASYNC: 179 1.1 gwr ms->ms_events.ev_async = *(int *)data != 0; 180 1.37 tsutsui return 0; 181 1.28 jdolecek 182 1.28 jdolecek case FIOSETOWN: 183 1.28 jdolecek if (-*(int *)data != ms->ms_events.ev_io->p_pgid 184 1.28 jdolecek && *(int *)data != ms->ms_events.ev_io->p_pid) 185 1.37 tsutsui return EPERM; 186 1.37 tsutsui return 0; 187 1.1 gwr 188 1.1 gwr case TIOCSPGRP: 189 1.1 gwr if (*(int *)data != ms->ms_events.ev_io->p_pgid) 190 1.37 tsutsui return EPERM; 191 1.37 tsutsui return 0; 192 1.1 gwr 193 1.1 gwr case VUIDGFORMAT: 194 1.1 gwr /* we only do firm_events */ 195 1.1 gwr *(int *)data = VUID_FIRM_EVENT; 196 1.37 tsutsui return 0; 197 1.1 gwr 198 1.1 gwr case VUIDSFORMAT: 199 1.1 gwr if (*(int *)data != VUID_FIRM_EVENT) 200 1.37 tsutsui return EINVAL; 201 1.37 tsutsui return 0; 202 1.1 gwr } 203 1.37 tsutsui return ENOTTY; 204 1.1 gwr } 205 1.1 gwr 206 1.1 gwr int 207 1.36 tsutsui mspoll(dev_t dev, int events, struct lwp *l) 208 1.1 gwr { 209 1.1 gwr struct ms_softc *ms; 210 1.1 gwr 211 1.37 tsutsui ms = device_lookup_private(&ms_cd, minor(dev)); 212 1.37 tsutsui return ev_poll(&ms->ms_events, events, l); 213 1.1 gwr } 214 1.1 gwr 215 1.23 jdolecek int 216 1.36 tsutsui mskqfilter(dev_t dev, struct knote *kn) 217 1.23 jdolecek { 218 1.23 jdolecek struct ms_softc *ms; 219 1.23 jdolecek 220 1.37 tsutsui ms = device_lookup_private(&ms_cd, minor(dev)); 221 1.37 tsutsui return ev_kqfilter(&ms->ms_events, kn); 222 1.23 jdolecek } 223 1.1 gwr 224 1.1 gwr /**************************************************************** 225 1.1 gwr * Middle layer (translator) 226 1.1 gwr ****************************************************************/ 227 1.1 gwr 228 1.1 gwr /* 229 1.1 gwr * Called by our ms_softint() routine on input. 230 1.1 gwr */ 231 1.1 gwr void 232 1.36 tsutsui ms_input(struct ms_softc *ms, int c) 233 1.1 gwr { 234 1.18 augustss struct firm_event *fe; 235 1.18 augustss int mb, ub, d, get, put, any; 236 1.1 gwr static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; 237 1.1 gwr static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; 238 1.1 gwr 239 1.1 gwr /* 240 1.1 gwr * Discard input if not ready. Drop sync on parity or framing 241 1.1 gwr * error; gain sync on button byte. 242 1.1 gwr */ 243 1.1 gwr if (ms->ms_ready == 0) 244 1.1 gwr return; 245 1.1 gwr if (c == -1) { 246 1.1 gwr ms->ms_byteno = -1; 247 1.1 gwr return; 248 1.1 gwr } 249 1.31 macallan if ((c & 0xb0) == 0x80) { /* if in 0x80..0x8f of 0xc0..0xcf */ 250 1.17 matt if (c & 8) { 251 1.17 matt ms->ms_byteno = 1; /* short form (3 bytes) */ 252 1.17 matt } else { 253 1.17 matt ms->ms_byteno = 0; /* long form (5 bytes) */ 254 1.17 matt } 255 1.17 matt } 256 1.1 gwr 257 1.1 gwr /* 258 1.1 gwr * Run the decode loop, adding to the current information. 259 1.1 gwr * We add, rather than replace, deltas, so that if the event queue 260 1.1 gwr * fills, we accumulate data for when it opens up again. 261 1.1 gwr */ 262 1.1 gwr switch (ms->ms_byteno) { 263 1.1 gwr 264 1.1 gwr case -1: 265 1.1 gwr return; 266 1.1 gwr 267 1.1 gwr case 0: 268 1.17 matt /* buttons (long form) */ 269 1.17 matt ms->ms_byteno = 2; 270 1.1 gwr ms->ms_mb = (~c) & 0x7; 271 1.1 gwr return; 272 1.1 gwr 273 1.1 gwr case 1: 274 1.17 matt /* buttons (short form) */ 275 1.17 matt ms->ms_byteno = 4; 276 1.17 matt ms->ms_mb = (~c) & 0x7; 277 1.17 matt return; 278 1.17 matt 279 1.17 matt case 2: 280 1.1 gwr /* first delta-x */ 281 1.17 matt ms->ms_byteno = 3; 282 1.1 gwr ms->ms_dx += (char)c; 283 1.1 gwr return; 284 1.1 gwr 285 1.17 matt case 3: 286 1.1 gwr /* first delta-y */ 287 1.17 matt ms->ms_byteno = 4; 288 1.1 gwr ms->ms_dy += (char)c; 289 1.1 gwr return; 290 1.1 gwr 291 1.17 matt case 4: 292 1.1 gwr /* second delta-x */ 293 1.17 matt ms->ms_byteno = 5; 294 1.1 gwr ms->ms_dx += (char)c; 295 1.1 gwr return; 296 1.1 gwr 297 1.17 matt case 5: 298 1.17 matt /* second delta-y */ 299 1.1 gwr ms->ms_byteno = -1; /* wait for button-byte again */ 300 1.1 gwr ms->ms_dy += (char)c; 301 1.1 gwr break; 302 1.1 gwr 303 1.1 gwr default: 304 1.1 gwr panic("ms_rint"); 305 1.1 gwr /* NOTREACHED */ 306 1.1 gwr } 307 1.1 gwr 308 1.24 petrov #if NWSMOUSE > 0 309 1.24 petrov if (ms->ms_wsmousedev != NULL && ms->ms_ready == 2) { 310 1.24 petrov mb = ((ms->ms_mb & 4) >> 2) | 311 1.24 petrov (ms->ms_mb & 2) | 312 1.24 petrov ((ms->ms_mb & 1) << 2); 313 1.24 petrov wsmouse_input(ms->ms_wsmousedev, 314 1.34 plunky mb, 315 1.34 plunky ms->ms_dx, ms->ms_dy, 0, 0, 316 1.34 plunky WSMOUSE_INPUT_DELTA); 317 1.24 petrov ms->ms_dx = 0; 318 1.24 petrov ms->ms_dy = 0; 319 1.24 petrov return; 320 1.24 petrov } 321 1.24 petrov #endif 322 1.1 gwr /* 323 1.1 gwr * We have at least one event (mouse button, delta-X, or 324 1.1 gwr * delta-Y; possibly all three, and possibly three separate 325 1.1 gwr * button events). Deliver these events until we are out 326 1.1 gwr * of changes or out of room. As events get delivered, 327 1.1 gwr * mark them `unchanged'. 328 1.1 gwr */ 329 1.1 gwr any = 0; 330 1.1 gwr get = ms->ms_events.ev_get; 331 1.1 gwr put = ms->ms_events.ev_put; 332 1.1 gwr fe = &ms->ms_events.ev_q[put]; 333 1.1 gwr 334 1.1 gwr /* NEXT prepares to put the next event, backing off if necessary */ 335 1.1 gwr #define NEXT \ 336 1.1 gwr if ((++put) % EV_QSIZE == get) { \ 337 1.1 gwr put--; \ 338 1.1 gwr goto out; \ 339 1.1 gwr } 340 1.1 gwr /* ADVANCE completes the `put' of the event */ 341 1.1 gwr #define ADVANCE \ 342 1.1 gwr fe++; \ 343 1.1 gwr if (put >= EV_QSIZE) { \ 344 1.1 gwr put = 0; \ 345 1.1 gwr fe = &ms->ms_events.ev_q[0]; \ 346 1.1 gwr } \ 347 1.1 gwr any = 1 348 1.1 gwr 349 1.1 gwr mb = ms->ms_mb; 350 1.1 gwr ub = ms->ms_ub; 351 1.1 gwr while ((d = mb ^ ub) != 0) { 352 1.1 gwr /* 353 1.1 gwr * Mouse button change. Convert up to three changes 354 1.1 gwr * to the `first' change, and drop it into the event queue. 355 1.1 gwr */ 356 1.1 gwr NEXT; 357 1.1 gwr d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ 358 1.1 gwr fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ 359 1.1 gwr fe->value = mb & d ? VKEY_DOWN : VKEY_UP; 360 1.38 christos firm_gettime(fe); 361 1.1 gwr ADVANCE; 362 1.1 gwr ub ^= d; 363 1.1 gwr } 364 1.1 gwr if (ms->ms_dx) { 365 1.1 gwr NEXT; 366 1.1 gwr fe->id = LOC_X_DELTA; 367 1.1 gwr fe->value = ms->ms_dx; 368 1.38 christos firm_gettime(fe); 369 1.1 gwr ADVANCE; 370 1.1 gwr ms->ms_dx = 0; 371 1.1 gwr } 372 1.1 gwr if (ms->ms_dy) { 373 1.1 gwr NEXT; 374 1.1 gwr fe->id = LOC_Y_DELTA; 375 1.1 gwr fe->value = ms->ms_dy; 376 1.38 christos firm_gettime(fe); 377 1.1 gwr ADVANCE; 378 1.1 gwr ms->ms_dy = 0; 379 1.1 gwr } 380 1.1 gwr out: 381 1.1 gwr if (any) { 382 1.1 gwr ms->ms_ub = ub; 383 1.1 gwr ms->ms_events.ev_put = put; 384 1.1 gwr EV_WAKEUP(&ms->ms_events); 385 1.1 gwr } 386 1.1 gwr } 387