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