1 /* $NetBSD: ms.c,v 1.24 2002/10/23 09:10:34 jdolecek 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 #include <sys/cdefs.h> 52 __KERNEL_RCSID(0, "$NetBSD: ms.c,v 1.24 2002/10/23 09:10:34 jdolecek Exp $"); 53 54 /* 55 * Mouse driver. 56 */ 57 58 #include <sys/param.h> 59 #include <sys/device.h> 60 #include <sys/ioctl.h> 61 #include <sys/kernel.h> 62 #include <sys/proc.h> 63 #include <sys/syslog.h> 64 #include <sys/systm.h> 65 #include <sys/callout.h> 66 #include <sys/tty.h> 67 #include <sys/signalvar.h> 68 #include <sys/conf.h> 69 70 #include <amiga/dev/event_var.h> 71 #include <amiga/dev/vuid_event.h> 72 73 #include <amiga/amiga/custom.h> 74 #include <amiga/amiga/cia.h> 75 #include <amiga/amiga/device.h> 76 77 void msattach(struct device *, struct device *, void *); 78 int msmatch(struct device *, struct cfdata *, void *); 79 80 /* per-port state */ 81 struct ms_port { 82 int ms_portno; /* which hardware port, for msintr() */ 83 84 struct callout ms_intr_ch; 85 86 u_char ms_horc; /* horizontal counter on last scan */ 87 u_char ms_verc; /* vertical counter on last scan */ 88 char ms_mb; /* mouse button state */ 89 char ms_ub; /* user button state */ 90 int ms_dx; /* delta-x */ 91 int ms_dy; /* delta-y */ 92 volatile int ms_ready; /* event queue is ready */ 93 struct evvar ms_events; /* event queue state */ 94 }; 95 96 #define MS_NPORTS 2 97 98 struct ms_softc { 99 struct device sc_dev; /* base device */ 100 struct ms_port sc_ports[MS_NPORTS]; 101 }; 102 103 CFATTACH_DECL(ms, sizeof(struct ms_softc), 104 msmatch, msattach, NULL, NULL); 105 106 void msintr(void *); 107 void ms_enable(struct ms_port *); 108 void ms_disable(struct ms_port *); 109 110 extern struct cfdriver ms_cd; 111 112 dev_type_open(msopen); 113 dev_type_close(msclose); 114 dev_type_read(msread); 115 dev_type_ioctl(msioctl); 116 dev_type_poll(mspoll); 117 dev_type_kqfilter(mskqfilter); 118 119 const struct cdevsw ms_cdevsw = { 120 msopen, msclose, msread, nowrite, msioctl, 121 nostop, notty, mspoll, nommap, mskqfilter, 122 }; 123 124 #define MS_UNIT(d) ((minor(d) & ~0x1) >> 1) 125 #define MS_PORT(d) (minor(d) & 0x1) 126 127 /* 128 * Given a dev_t, return a pointer to the port's hardware state. 129 * Assumes the unit to be valid, so do *not* utilize this in msopen(). 130 */ 131 #define MS_DEV2MSPORT(d) \ 132 (&(((struct ms_softc *)getsoftc(ms_cd, MS_UNIT(d)))->sc_ports[MS_PORT(d)])) 133 134 int 135 msmatch(struct device *pdp, struct cfdata *cfp, void *auxp) 136 { 137 static int ms_matched = 0; 138 139 /* Allow only one instance. */ 140 if (!matchname((char *)auxp, "ms") || ms_matched) 141 return 0; 142 143 ms_matched = 1; 144 return 1; 145 } 146 147 void 148 msattach(struct device *pdp, struct device *dp, void *auxp) 149 { 150 struct ms_softc *sc = (void *) dp; 151 int i; 152 153 printf("\n"); 154 for (i = 0; i < MS_NPORTS; i++) { 155 sc->sc_ports[i].ms_portno = i; 156 callout_init(&sc->sc_ports[i].ms_intr_ch); 157 } 158 } 159 160 /* 161 * Amiga mice are hooked up to one of the two "game" ports, where 162 * the main mouse is usually on the first port, and port 2 can 163 * be used by a joystick. Nevertheless, we support two mouse 164 * devices, /dev/mouse0 and /dev/mouse1 (with a link of /dev/mouse to 165 * the device that represents the port of the mouse in use). 166 */ 167 168 /* 169 * enable scanner, called when someone opens the port. 170 */ 171 void 172 ms_enable(struct ms_port *ms) 173 { 174 175 /* 176 * use this as flag to the "interrupt" to tell it when to 177 * shut off (when it's reset to 0). 178 */ 179 ms->ms_ready = 1; 180 181 callout_reset(&ms->ms_intr_ch, 2, msintr, ms); 182 } 183 184 /* 185 * disable scanner. Just set ms_ready to 0, and after the next 186 * timeout taken, no further timeouts will be initiated. 187 */ 188 void 189 ms_disable(struct ms_port *ms) 190 { 191 int s; 192 193 s = splhigh (); 194 ms->ms_ready = 0; 195 /* 196 * sync with the interrupt 197 */ 198 tsleep(ms, PZERO - 1, "mouse-disable", 0); 199 splx(s); 200 } 201 202 203 /* 204 * we're emulating a mousesystems serial mouse here.. 205 */ 206 void 207 msintr(void *arg) 208 { 209 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; 210 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; 211 struct ms_port *ms = arg; 212 struct firm_event *fe; 213 int mb, ub, d, get, put, any, port; 214 u_char pra, *horc, *verc; 215 u_short pot, count; 216 short dx, dy; 217 218 port = ms->ms_portno; 219 220 horc = ((u_char *) &count) + 1; 221 verc = (u_char *) &count; 222 223 /* 224 * first read the three buttons. 225 */ 226 pot = custom.potgor; 227 pra = ciaa.pra; 228 pot >>= port == 0 ? 8 : 12; /* contains right and middle button */ 229 pra >>= port == 0 ? 6 : 7; /* contains left button */ 230 mb = (pot & 4) / 4 + (pot & 1) * 2 + (pra & 1) * 4; 231 mb ^= 0x07; 232 233 /* 234 * read current values of counter registers 235 */ 236 if (port == 0) 237 count = custom.joy0dat; 238 else 239 count = custom.joy1dat; 240 241 /* 242 * take care of wraparound 243 */ 244 dx = *horc - ms->ms_horc; 245 if (dx < -127) 246 dx += 255; 247 else if (dx > 127) 248 dx -= 255; 249 dy = *verc - ms->ms_verc; 250 if (dy < -127) 251 dy += 255; 252 else if (dy > 127) 253 dy -= 255; 254 255 /* 256 * remember current values for next scan 257 */ 258 ms->ms_horc = *horc; 259 ms->ms_verc = *verc; 260 261 ms->ms_dx = dx; 262 ms->ms_dy = dy; 263 ms->ms_mb = mb; 264 265 if (dx || dy || ms->ms_ub != ms->ms_mb) { 266 /* 267 * We have at least one event (mouse button, delta-X, or 268 * delta-Y; possibly all three, and possibly three separate 269 * button events). Deliver these events until we are out of 270 * changes or out of room. As events get delivered, mark them 271 * `unchanged'. 272 */ 273 any = 0; 274 get = ms->ms_events.ev_get; 275 put = ms->ms_events.ev_put; 276 fe = &ms->ms_events.ev_q[put]; 277 278 mb = ms->ms_mb; 279 ub = ms->ms_ub; 280 while ((d = mb ^ ub) != 0) { 281 /* 282 * Mouse button change. Convert up to three changes 283 * to the `first' change, and drop it into the event 284 * queue. 285 */ 286 if ((++put) % EV_QSIZE == get) { 287 put--; 288 goto out; 289 } 290 291 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ 292 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ 293 fe->value = mb & d ? VKEY_DOWN : VKEY_UP; 294 fe->time = time; 295 fe++; 296 297 if (put >= EV_QSIZE) { 298 put = 0; 299 fe = &ms->ms_events.ev_q[0]; 300 } 301 any = 1; 302 303 ub ^= d; 304 } 305 if (ms->ms_dx) { 306 if ((++put) % EV_QSIZE == get) { 307 put--; 308 goto out; 309 } 310 311 fe->id = LOC_X_DELTA; 312 fe->value = ms->ms_dx; 313 fe->time = time; 314 fe++; 315 316 if (put >= EV_QSIZE) { 317 put = 0; 318 fe = &ms->ms_events.ev_q[0]; 319 } 320 any = 1; 321 322 ms->ms_dx = 0; 323 } 324 if (ms->ms_dy) { 325 if ((++put) % EV_QSIZE == get) { 326 put--; 327 goto out; 328 } 329 330 fe->id = LOC_Y_DELTA; 331 fe->value = ms->ms_dy; 332 fe->time = time; 333 fe++; 334 335 if (put >= EV_QSIZE) { 336 put = 0; 337 fe = &ms->ms_events.ev_q[0]; 338 } 339 any = 1; 340 341 ms->ms_dy = 0; 342 } 343 out: 344 if (any) { 345 ms->ms_ub = ub; 346 ms->ms_events.ev_put = put; 347 EV_WAKEUP(&ms->ms_events); 348 } 349 } 350 351 /* 352 * reschedule handler, or if terminating, 353 * handshake with ms_disable 354 */ 355 if (ms->ms_ready) 356 callout_reset(&ms->ms_intr_ch, 2, msintr, ms); 357 else 358 wakeup(ms); 359 } 360 361 int 362 msopen(dev_t dev, int flags, int mode, struct proc *p) 363 { 364 struct ms_softc *sc; 365 struct ms_port *ms; 366 int unit, port; 367 368 unit = MS_UNIT(dev); 369 sc = (struct ms_softc *)getsoftc(ms_cd, unit); 370 371 if (sc == NULL) 372 return(EXDEV); 373 374 port = MS_PORT(dev); 375 ms = &sc->sc_ports[port]; 376 377 if (ms->ms_events.ev_io) 378 return(EBUSY); 379 380 /* initialize potgo bits for mouse mode */ 381 custom.potgo = custom.potgor | (0xf00 << (port * 4)); 382 383 ms->ms_events.ev_io = p; 384 ev_init(&ms->ms_events); /* may cause sleep */ 385 ms_enable(ms); 386 return(0); 387 } 388 389 int 390 msclose(dev_t dev, int flags, int mode, struct proc *p) 391 { 392 struct ms_port *ms; 393 394 ms = MS_DEV2MSPORT(dev); 395 396 ms_disable(ms); 397 ev_fini(&ms->ms_events); 398 ms->ms_events.ev_io = NULL; 399 return(0); 400 } 401 402 int 403 msread(dev_t dev, struct uio *uio, int flags) 404 { 405 struct ms_port *ms; 406 407 ms = MS_DEV2MSPORT(dev); 408 409 return(ev_read(&ms->ms_events, uio, flags)); 410 } 411 412 int 413 msioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, 414 struct proc *p) 415 { 416 struct ms_port *ms; 417 418 ms = MS_DEV2MSPORT(dev); 419 420 switch (cmd) { 421 case FIONBIO: /* we will remove this someday (soon???) */ 422 return(0); 423 case FIOASYNC: 424 ms->ms_events.ev_async = *(int *)data != 0; 425 return(0); 426 case TIOCSPGRP: 427 if (*(int *)data != ms->ms_events.ev_io->p_pgid) 428 return(EPERM); 429 return(0); 430 case VUIDGFORMAT: /* we only do firm_events */ 431 *(int *)data = VUID_FIRM_EVENT; 432 return(0); 433 case VUIDSFORMAT: 434 if (*(int *)data != VUID_FIRM_EVENT) 435 return(EINVAL); 436 return(0); 437 } 438 return(ENOTTY); 439 } 440 441 int 442 mspoll(dev_t dev, int events, struct proc *p) 443 { 444 struct ms_port *ms; 445 446 ms = MS_DEV2MSPORT(dev); 447 448 return(ev_poll(&ms->ms_events, events, p)); 449 } 450 451 int 452 mskqfilter(dev, kn) 453 dev_t dev; 454 struct knote *kn; 455 { 456 struct ms_port *ms; 457 458 ms = MS_DEV2MSPORT(dev); 459 460 return (ev_kqfilter(&ms->ms_events, kn)); 461 } 462