1 /* $NetBSD: ms.c,v 1.6 1994/12/01 17:25:29 chopps 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/conf.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/tty.h> 63 64 #include <amiga/dev/event_var.h> 65 #include <amiga/dev/vuid_event.h> 66 67 #include <amiga/amiga/custom.h> 68 #include <amiga/amiga/cia.h> 69 70 #include "mouse.h" 71 #if NMOUSE > 0 72 73 /* there's really no more physical ports on an amiga.. */ 74 #if NMOUSE > 2 75 #undef NMOUSE 76 #define NMOUSE 2 77 #endif 78 79 void msintr __P((void *)); 80 void ms_enable __P((dev_t)); 81 void ms_disable __P((dev_t)); 82 83 int 84 mouseattach(cnt) 85 int cnt; 86 { 87 printf("%d %s configured\n", NMOUSE, NMOUSE == 1 ? "mouse" : "mice"); 88 return(NMOUSE); 89 } 90 91 /* 92 * Amiga mice are hooked up to one of the two "game" ports, where 93 * the main mouse is usually on the first port, and port 2 can 94 * be used by a joystick. Nevertheless, we support two mouse 95 * devices, /dev/mouse0 and /dev/mouse1 (with a link of /dev/mouse to 96 * the device that represents the port of the mouse in use). 97 */ 98 struct ms_softc { 99 u_char ms_horc; /* horizontal counter on last scan */ 100 u_char ms_verc; /* vertical counter on last scan */ 101 char ms_mb; /* mouse button state */ 102 char ms_ub; /* user button state */ 103 int ms_dx; /* delta-x */ 104 int ms_dy; /* delta-y */ 105 volatile int ms_ready; /* event queue is ready */ 106 struct evvar ms_events; /* event queue state */ 107 } ms_softc[NMOUSE]; 108 109 110 /* 111 * enable scanner, called when someone opens the device. 112 * Assume caller already validated range of dev. 113 */ 114 void 115 ms_enable(dev) 116 dev_t dev; 117 { 118 struct ms_softc *ms; 119 120 ms = &ms_softc[minor(dev)]; 121 /* 122 * use this as flag to the "interrupt" to tell it when to 123 * shut off (when it's reset to 0). 124 */ 125 ms->ms_ready = 1; 126 127 timeout(msintr, (void *)minor(dev), 2); 128 } 129 130 /* 131 * disable scanner. Just set ms_ready to 0, and after the next 132 * timeout taken, no further timeouts will be initiated. 133 */ 134 void 135 ms_disable(dev) 136 dev_t dev; 137 { 138 struct ms_softc *ms; 139 int s; 140 141 ms = &ms_softc[minor(dev)]; 142 s = splhigh (); 143 ms->ms_ready = 0; 144 /* 145 * sync with the interrupt 146 */ 147 tsleep(ms, PZERO - 1, "mouse-disable", 0); 148 splx(s); 149 } 150 151 152 /* 153 * we're emulating a mousesystems serial mouse here.. 154 */ 155 void 156 msintr(arg) 157 void *arg; 158 { 159 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; 160 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; 161 struct ms_softc *ms; 162 struct firm_event *fe; 163 int mb, ub, d, get, put, any, unit; 164 u_char pra, *horc, *verc; 165 u_short pot, count; 166 short dx, dy; 167 168 unit = (int)arg; 169 ms = &ms_softc[unit]; 170 horc = ((u_char *) &count) + 1; 171 verc = (u_char *) &count; 172 173 /* 174 * first read the three buttons. 175 */ 176 pot = custom.potgor; 177 pra = ciaa.pra; 178 pot >>= unit == 0 ? 8 : 12; /* contains right and middle button */ 179 pra >>= unit == 0 ? 6 : 7; /* contains left button */ 180 mb = (pot & 4) / 4 + (pot & 1) * 2 + (pra & 1) * 4; 181 mb ^= 0x07; 182 183 /* 184 * read current values of counter registers 185 */ 186 if (unit == 0) 187 count = custom.joy0dat; 188 else 189 count = custom.joy1dat; 190 191 /* 192 * take care of wraparound 193 */ 194 dx = *horc - ms->ms_horc; 195 if (dx < -127) 196 dx += 255; 197 else if (dx > 127) 198 dx -= 255; 199 dy = *verc - ms->ms_verc; 200 if (dy < -127) 201 dy += 255; 202 else if (dy > 127) 203 dy -= 255; 204 205 /* 206 * remember current values for next scan 207 */ 208 ms->ms_horc = *horc; 209 ms->ms_verc = *verc; 210 211 ms->ms_dx = dx; 212 ms->ms_dy = dy; 213 ms->ms_mb = mb; 214 215 if (dx || dy || ms->ms_ub != ms->ms_mb) { 216 /* 217 * We have at least one event (mouse button, delta-X, or 218 * delta-Y; possibly all three, and possibly three separate 219 * button events). Deliver these events until we are out of 220 * changes or out of room. As events get delivered, mark them 221 * `unchanged'. 222 */ 223 any = 0; 224 get = ms->ms_events.ev_get; 225 put = ms->ms_events.ev_put; 226 fe = &ms->ms_events.ev_q[put]; 227 228 mb = ms->ms_mb; 229 ub = ms->ms_ub; 230 while ((d = mb ^ ub) != 0) { 231 /* 232 * Mouse button change. Convert up to three changes 233 * to the `first' change, and drop it into the event 234 * queue. 235 */ 236 if ((++put) % EV_QSIZE == get) { 237 put--; 238 goto out; 239 } 240 241 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ 242 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ 243 fe->value = mb & d ? VKEY_DOWN : VKEY_UP; 244 fe->time = time; 245 fe++; 246 247 if (put >= EV_QSIZE) { 248 put = 0; 249 fe = &ms->ms_events.ev_q[0]; 250 } 251 any = 1; 252 253 ub ^= d; 254 } 255 if (ms->ms_dx) { 256 if ((++put) % EV_QSIZE == get) { 257 put--; 258 goto out; 259 } 260 261 fe->id = LOC_X_DELTA; 262 fe->value = ms->ms_dx; 263 fe->time = time; 264 fe++; 265 266 if (put >= EV_QSIZE) { 267 put = 0; 268 fe = &ms->ms_events.ev_q[0]; 269 } 270 any = 1; 271 272 ms->ms_dx = 0; 273 } 274 if (ms->ms_dy) { 275 if ((++put) % EV_QSIZE == get) { 276 put--; 277 goto out; 278 } 279 280 fe->id = LOC_Y_DELTA; 281 fe->value = ms->ms_dy; 282 fe->time = time; 283 fe++; 284 285 if (put >= EV_QSIZE) { 286 put = 0; 287 fe = &ms->ms_events.ev_q[0]; 288 } 289 any = 1; 290 291 ms->ms_dy = 0; 292 } 293 out: 294 if (any) { 295 ms->ms_ub = ub; 296 ms->ms_events.ev_put = put; 297 EV_WAKEUP(&ms->ms_events); 298 } 299 } 300 301 /* 302 * reschedule handler, or if terminating, 303 * handshake with ms_disable 304 */ 305 if (ms->ms_ready) 306 timeout(msintr, (void *)unit, 2); 307 else 308 wakeup(ms); 309 } 310 311 int 312 msopen(dev, flags, mode, p) 313 dev_t dev; 314 int flags, mode; 315 struct proc *p; 316 { 317 struct ms_softc *ms; 318 int s, error, unit; 319 320 unit = minor(dev); 321 ms = &ms_softc[unit]; 322 323 if (unit >= NMOUSE) 324 return(EXDEV); 325 326 if (ms->ms_events.ev_io) 327 return(EBUSY); 328 329 ms->ms_events.ev_io = p; 330 ev_init(&ms->ms_events); /* may cause sleep */ 331 ms_enable(dev); 332 return(0); 333 } 334 335 int 336 msclose(dev, flags, mode, p) 337 dev_t dev; 338 int flags, mode; 339 struct proc *p; 340 { 341 int unit; 342 struct ms_softc *ms; 343 344 unit = minor (dev); 345 ms = &ms_softc[unit]; 346 347 ms_disable(dev); 348 ev_fini(&ms->ms_events); 349 ms->ms_events.ev_io = NULL; 350 return(0); 351 } 352 353 int 354 msread(dev, uio, flags) 355 dev_t dev; 356 struct uio *uio; 357 int flags; 358 { 359 struct ms_softc *ms; 360 361 ms = &ms_softc[minor(dev)]; 362 return(ev_read(&ms->ms_events, uio, flags)); 363 } 364 365 /* 366 * XXX this routine should not exist, 367 * but is convenient to write here for now 368 */ 369 int 370 mswrite(dev, uio, flags) 371 dev_t dev; 372 struct uio *uio; 373 int flags; 374 { 375 return(EOPNOTSUPP); 376 } 377 378 int 379 msioctl(dev, cmd, data, flag, p) 380 dev_t dev; 381 u_long cmd; 382 register caddr_t data; 383 int flag; 384 struct proc *p; 385 { 386 struct ms_softc *ms; 387 int unit; 388 389 unit = minor(dev); 390 ms = &ms_softc[unit]; 391 392 switch (cmd) { 393 case FIONBIO: /* we will remove this someday (soon???) */ 394 return(0); 395 case FIOASYNC: 396 ms->ms_events.ev_async = *(int *)data != 0; 397 return(0); 398 case TIOCSPGRP: 399 if (*(int *)data != ms->ms_events.ev_io->p_pgid) 400 return(EPERM); 401 return(0); 402 case VUIDGFORMAT: /* we only do firm_events */ 403 *(int *)data = VUID_FIRM_EVENT; 404 return(0); 405 case VUIDSFORMAT: 406 if (*(int *)data != VUID_FIRM_EVENT) 407 return(EINVAL); 408 return(0); 409 } 410 return(ENOTTY); 411 } 412 413 int 414 msselect(dev, rw, p) 415 dev_t dev; 416 int rw; 417 struct proc *p; 418 { 419 struct ms_softc *ms; 420 421 ms = &ms_softc[minor(dev)]; 422 return(ev_select(&ms->ms_events, rw, p)); 423 } 424 #endif /* NMOUSE > 0 */ 425