1 /* $NetBSD: ms.c,v 1.18 2000/05/18 19:58:30 is Exp $ */ 2 3 /* 4 * based on: 5 * 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This software was developed by the Computer Systems Engineering group 10 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 11 * contributed to Berkeley. 12 * 13 * All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Lawrence Berkeley Laboratory. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 3. All advertising materials mentioning features or use of this software 27 * must display the following acknowledgement: 28 * This product includes software developed by the University of 29 * California, Berkeley and its contributors. 30 * 4. Neither the name of the University nor the names of its contributors 31 * may be used to endorse or promote products derived from this software 32 * without specific prior written permission. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 * 46 * @(#)ms.c 8.1 (Berkeley) 6/11/93 47 * 48 * Header: ms.c,v 1.5 92/11/26 01:28:47 torek Exp (LBL) 49 */ 50 51 /* 52 * Mouse driver. 53 */ 54 55 #include <sys/param.h> 56 #include <sys/device.h> 57 #include <sys/ioctl.h> 58 #include <sys/kernel.h> 59 #include <sys/proc.h> 60 #include <sys/syslog.h> 61 #include <sys/systm.h> 62 #include <sys/callout.h> 63 #include <sys/tty.h> 64 #include <sys/signalvar.h> 65 66 #include <amiga/dev/event_var.h> 67 #include <amiga/dev/vuid_event.h> 68 69 #include <amiga/amiga/custom.h> 70 #include <amiga/amiga/cia.h> 71 #include <amiga/amiga/device.h> 72 73 #include <sys/conf.h> 74 #include <machine/conf.h> 75 76 void msattach __P((struct device *, struct device *, void *)); 77 int msmatch __P((struct device *, struct cfdata *, void *)); 78 79 /* per-port state */ 80 struct ms_port { 81 int ms_portno; /* which hardware port, for msintr() */ 82 83 struct callout ms_intr_ch; 84 85 u_char ms_horc; /* horizontal counter on last scan */ 86 u_char ms_verc; /* vertical counter on last scan */ 87 char ms_mb; /* mouse button state */ 88 char ms_ub; /* user button state */ 89 int ms_dx; /* delta-x */ 90 int ms_dy; /* delta-y */ 91 volatile int ms_ready; /* event queue is ready */ 92 struct evvar ms_events; /* event queue state */ 93 }; 94 95 #define MS_NPORTS 2 96 97 struct ms_softc { 98 struct device sc_dev; /* base device */ 99 struct ms_port sc_ports[MS_NPORTS]; 100 }; 101 102 struct cfattach ms_ca = { 103 sizeof(struct ms_softc), msmatch, msattach 104 }; 105 106 void msintr __P((void *)); 107 void ms_enable __P((struct ms_port *)); 108 void ms_disable __P((struct ms_port *)); 109 110 extern struct cfdriver ms_cd; 111 112 #define MS_UNIT(d) ((minor(d) & ~0x1) >> 1) 113 #define MS_PORT(d) (minor(d) & 0x1) 114 115 /* 116 * Given a dev_t, return a pointer to the port's hardware state. 117 * Assumes the unit to be valid, so do *not* utilize this in msopen(). 118 */ 119 #define MS_DEV2MSPORT(d) \ 120 (&(((struct ms_softc *)getsoftc(ms_cd, MS_UNIT(d)))->sc_ports[MS_PORT(d)])) 121 122 int 123 msmatch(pdp, cfp, auxp) 124 struct device *pdp; 125 struct cfdata *cfp; 126 void *auxp; 127 { 128 static int ms_matched = 0; 129 130 /* Allow only one instance. */ 131 if (!matchname((char *)auxp, "ms") || ms_matched) 132 return 0; 133 134 ms_matched = 1; 135 return 1; 136 } 137 138 void 139 msattach(pdp, dp, auxp) 140 struct device *pdp, *dp; 141 void *auxp; 142 { 143 struct ms_softc *sc = (void *) dp; 144 int i; 145 146 printf("\n"); 147 for (i = 0; i < MS_NPORTS; i++) { 148 sc->sc_ports[i].ms_portno = i; 149 callout_init(&sc->sc_ports[i].ms_intr_ch); 150 } 151 } 152 153 /* 154 * Amiga mice are hooked up to one of the two "game" ports, where 155 * the main mouse is usually on the first port, and port 2 can 156 * be used by a joystick. Nevertheless, we support two mouse 157 * devices, /dev/mouse0 and /dev/mouse1 (with a link of /dev/mouse to 158 * the device that represents the port of the mouse in use). 159 */ 160 161 /* 162 * enable scanner, called when someone opens the port. 163 */ 164 void 165 ms_enable(ms) 166 struct ms_port *ms; 167 { 168 169 /* 170 * use this as flag to the "interrupt" to tell it when to 171 * shut off (when it's reset to 0). 172 */ 173 ms->ms_ready = 1; 174 175 callout_reset(&ms->ms_intr_ch, 2, msintr, ms); 176 } 177 178 /* 179 * disable scanner. Just set ms_ready to 0, and after the next 180 * timeout taken, no further timeouts will be initiated. 181 */ 182 void 183 ms_disable(ms) 184 struct ms_port *ms; 185 { 186 int s; 187 188 s = splhigh (); 189 ms->ms_ready = 0; 190 /* 191 * sync with the interrupt 192 */ 193 tsleep(ms, PZERO - 1, "mouse-disable", 0); 194 splx(s); 195 } 196 197 198 /* 199 * we're emulating a mousesystems serial mouse here.. 200 */ 201 void 202 msintr(arg) 203 void *arg; 204 { 205 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; 206 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; 207 struct ms_port *ms = arg; 208 struct firm_event *fe; 209 int mb, ub, d, get, put, any, port; 210 u_char pra, *horc, *verc; 211 u_short pot, count; 212 short dx, dy; 213 214 port = ms->ms_portno; 215 216 horc = ((u_char *) &count) + 1; 217 verc = (u_char *) &count; 218 219 /* 220 * first read the three buttons. 221 */ 222 pot = custom.potgor; 223 pra = ciaa.pra; 224 pot >>= port == 0 ? 8 : 12; /* contains right and middle button */ 225 pra >>= port == 0 ? 6 : 7; /* contains left button */ 226 mb = (pot & 4) / 4 + (pot & 1) * 2 + (pra & 1) * 4; 227 mb ^= 0x07; 228 229 /* 230 * read current values of counter registers 231 */ 232 if (port == 0) 233 count = custom.joy0dat; 234 else 235 count = custom.joy1dat; 236 237 /* 238 * take care of wraparound 239 */ 240 dx = *horc - ms->ms_horc; 241 if (dx < -127) 242 dx += 255; 243 else if (dx > 127) 244 dx -= 255; 245 dy = *verc - ms->ms_verc; 246 if (dy < -127) 247 dy += 255; 248 else if (dy > 127) 249 dy -= 255; 250 251 /* 252 * remember current values for next scan 253 */ 254 ms->ms_horc = *horc; 255 ms->ms_verc = *verc; 256 257 ms->ms_dx = dx; 258 ms->ms_dy = dy; 259 ms->ms_mb = mb; 260 261 if (dx || dy || ms->ms_ub != ms->ms_mb) { 262 /* 263 * We have at least one event (mouse button, delta-X, or 264 * delta-Y; possibly all three, and possibly three separate 265 * button events). Deliver these events until we are out of 266 * changes or out of room. As events get delivered, mark them 267 * `unchanged'. 268 */ 269 any = 0; 270 get = ms->ms_events.ev_get; 271 put = ms->ms_events.ev_put; 272 fe = &ms->ms_events.ev_q[put]; 273 274 mb = ms->ms_mb; 275 ub = ms->ms_ub; 276 while ((d = mb ^ ub) != 0) { 277 /* 278 * Mouse button change. Convert up to three changes 279 * to the `first' change, and drop it into the event 280 * queue. 281 */ 282 if ((++put) % EV_QSIZE == get) { 283 put--; 284 goto out; 285 } 286 287 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ 288 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ 289 fe->value = mb & d ? VKEY_DOWN : VKEY_UP; 290 fe->time = time; 291 fe++; 292 293 if (put >= EV_QSIZE) { 294 put = 0; 295 fe = &ms->ms_events.ev_q[0]; 296 } 297 any = 1; 298 299 ub ^= d; 300 } 301 if (ms->ms_dx) { 302 if ((++put) % EV_QSIZE == get) { 303 put--; 304 goto out; 305 } 306 307 fe->id = LOC_X_DELTA; 308 fe->value = ms->ms_dx; 309 fe->time = time; 310 fe++; 311 312 if (put >= EV_QSIZE) { 313 put = 0; 314 fe = &ms->ms_events.ev_q[0]; 315 } 316 any = 1; 317 318 ms->ms_dx = 0; 319 } 320 if (ms->ms_dy) { 321 if ((++put) % EV_QSIZE == get) { 322 put--; 323 goto out; 324 } 325 326 fe->id = LOC_Y_DELTA; 327 fe->value = ms->ms_dy; 328 fe->time = time; 329 fe++; 330 331 if (put >= EV_QSIZE) { 332 put = 0; 333 fe = &ms->ms_events.ev_q[0]; 334 } 335 any = 1; 336 337 ms->ms_dy = 0; 338 } 339 out: 340 if (any) { 341 ms->ms_ub = ub; 342 ms->ms_events.ev_put = put; 343 EV_WAKEUP(&ms->ms_events); 344 } 345 } 346 347 /* 348 * reschedule handler, or if terminating, 349 * handshake with ms_disable 350 */ 351 if (ms->ms_ready) 352 callout_reset(&ms->ms_intr_ch, 2, msintr, ms); 353 else 354 wakeup(ms); 355 } 356 357 int 358 msopen(dev, flags, mode, p) 359 dev_t dev; 360 int flags, mode; 361 struct proc *p; 362 { 363 struct ms_softc *sc; 364 struct ms_port *ms; 365 int unit, port; 366 367 unit = MS_UNIT(dev); 368 sc = (struct ms_softc *)getsoftc(ms_cd, unit); 369 370 if (sc == NULL) 371 return(EXDEV); 372 373 port = MS_PORT(dev); 374 ms = &sc->sc_ports[port]; 375 376 if (ms->ms_events.ev_io) 377 return(EBUSY); 378 379 /* initialize potgo bits for mouse mode */ 380 custom.potgo = custom.potgor | (0xf00 << (port * 4)); 381 382 ms->ms_events.ev_io = p; 383 ev_init(&ms->ms_events); /* may cause sleep */ 384 ms_enable(ms); 385 return(0); 386 } 387 388 int 389 msclose(dev, flags, mode, p) 390 dev_t dev; 391 int flags, mode; 392 struct proc *p; 393 { 394 struct ms_port *ms; 395 396 ms = MS_DEV2MSPORT(dev); 397 398 ms_disable(ms); 399 ev_fini(&ms->ms_events); 400 ms->ms_events.ev_io = NULL; 401 return(0); 402 } 403 404 int 405 msread(dev, uio, flags) 406 dev_t dev; 407 struct uio *uio; 408 int flags; 409 { 410 struct ms_port *ms; 411 412 ms = MS_DEV2MSPORT(dev); 413 414 return(ev_read(&ms->ms_events, uio, flags)); 415 } 416 417 int 418 msioctl(dev, cmd, data, flag, p) 419 dev_t dev; 420 u_long cmd; 421 register caddr_t data; 422 int flag; 423 struct proc *p; 424 { 425 struct ms_port *ms; 426 427 ms = MS_DEV2MSPORT(dev); 428 429 switch (cmd) { 430 case FIONBIO: /* we will remove this someday (soon???) */ 431 return(0); 432 case FIOASYNC: 433 ms->ms_events.ev_async = *(int *)data != 0; 434 return(0); 435 case TIOCSPGRP: 436 if (*(int *)data != ms->ms_events.ev_io->p_pgid) 437 return(EPERM); 438 return(0); 439 case VUIDGFORMAT: /* we only do firm_events */ 440 *(int *)data = VUID_FIRM_EVENT; 441 return(0); 442 case VUIDSFORMAT: 443 if (*(int *)data != VUID_FIRM_EVENT) 444 return(EINVAL); 445 return(0); 446 } 447 return(ENOTTY); 448 } 449 450 int 451 mspoll(dev, events, p) 452 dev_t dev; 453 int events; 454 struct proc *p; 455 { 456 struct ms_port *ms; 457 458 ms = MS_DEV2MSPORT(dev); 459 460 return(ev_poll(&ms->ms_events, events, p)); 461 } 462