1 /* $NetBSD: ms.c,v 1.23 2002/10/02 04:55:52 thorpej 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.23 2002/10/02 04:55:52 thorpej 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 118 const struct cdevsw ms_cdevsw = { 119 msopen, msclose, msread, nowrite, msioctl, 120 nostop, notty, mspoll, nommap, 121 }; 122 123 #define MS_UNIT(d) ((minor(d) & ~0x1) >> 1) 124 #define MS_PORT(d) (minor(d) & 0x1) 125 126 /* 127 * Given a dev_t, return a pointer to the port's hardware state. 128 * Assumes the unit to be valid, so do *not* utilize this in msopen(). 129 */ 130 #define MS_DEV2MSPORT(d) \ 131 (&(((struct ms_softc *)getsoftc(ms_cd, MS_UNIT(d)))->sc_ports[MS_PORT(d)])) 132 133 int 134 msmatch(struct device *pdp, struct cfdata *cfp, void *auxp) 135 { 136 static int ms_matched = 0; 137 138 /* Allow only one instance. */ 139 if (!matchname((char *)auxp, "ms") || ms_matched) 140 return 0; 141 142 ms_matched = 1; 143 return 1; 144 } 145 146 void 147 msattach(struct device *pdp, struct device *dp, void *auxp) 148 { 149 struct ms_softc *sc = (void *) dp; 150 int i; 151 152 printf("\n"); 153 for (i = 0; i < MS_NPORTS; i++) { 154 sc->sc_ports[i].ms_portno = i; 155 callout_init(&sc->sc_ports[i].ms_intr_ch); 156 } 157 } 158 159 /* 160 * Amiga mice are hooked up to one of the two "game" ports, where 161 * the main mouse is usually on the first port, and port 2 can 162 * be used by a joystick. Nevertheless, we support two mouse 163 * devices, /dev/mouse0 and /dev/mouse1 (with a link of /dev/mouse to 164 * the device that represents the port of the mouse in use). 165 */ 166 167 /* 168 * enable scanner, called when someone opens the port. 169 */ 170 void 171 ms_enable(struct ms_port *ms) 172 { 173 174 /* 175 * use this as flag to the "interrupt" to tell it when to 176 * shut off (when it's reset to 0). 177 */ 178 ms->ms_ready = 1; 179 180 callout_reset(&ms->ms_intr_ch, 2, msintr, ms); 181 } 182 183 /* 184 * disable scanner. Just set ms_ready to 0, and after the next 185 * timeout taken, no further timeouts will be initiated. 186 */ 187 void 188 ms_disable(struct ms_port *ms) 189 { 190 int s; 191 192 s = splhigh (); 193 ms->ms_ready = 0; 194 /* 195 * sync with the interrupt 196 */ 197 tsleep(ms, PZERO - 1, "mouse-disable", 0); 198 splx(s); 199 } 200 201 202 /* 203 * we're emulating a mousesystems serial mouse here.. 204 */ 205 void 206 msintr(void *arg) 207 { 208 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; 209 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; 210 struct ms_port *ms = arg; 211 struct firm_event *fe; 212 int mb, ub, d, get, put, any, port; 213 u_char pra, *horc, *verc; 214 u_short pot, count; 215 short dx, dy; 216 217 port = ms->ms_portno; 218 219 horc = ((u_char *) &count) + 1; 220 verc = (u_char *) &count; 221 222 /* 223 * first read the three buttons. 224 */ 225 pot = custom.potgor; 226 pra = ciaa.pra; 227 pot >>= port == 0 ? 8 : 12; /* contains right and middle button */ 228 pra >>= port == 0 ? 6 : 7; /* contains left button */ 229 mb = (pot & 4) / 4 + (pot & 1) * 2 + (pra & 1) * 4; 230 mb ^= 0x07; 231 232 /* 233 * read current values of counter registers 234 */ 235 if (port == 0) 236 count = custom.joy0dat; 237 else 238 count = custom.joy1dat; 239 240 /* 241 * take care of wraparound 242 */ 243 dx = *horc - ms->ms_horc; 244 if (dx < -127) 245 dx += 255; 246 else if (dx > 127) 247 dx -= 255; 248 dy = *verc - ms->ms_verc; 249 if (dy < -127) 250 dy += 255; 251 else if (dy > 127) 252 dy -= 255; 253 254 /* 255 * remember current values for next scan 256 */ 257 ms->ms_horc = *horc; 258 ms->ms_verc = *verc; 259 260 ms->ms_dx = dx; 261 ms->ms_dy = dy; 262 ms->ms_mb = mb; 263 264 if (dx || dy || ms->ms_ub != ms->ms_mb) { 265 /* 266 * We have at least one event (mouse button, delta-X, or 267 * delta-Y; possibly all three, and possibly three separate 268 * button events). Deliver these events until we are out of 269 * changes or out of room. As events get delivered, mark them 270 * `unchanged'. 271 */ 272 any = 0; 273 get = ms->ms_events.ev_get; 274 put = ms->ms_events.ev_put; 275 fe = &ms->ms_events.ev_q[put]; 276 277 mb = ms->ms_mb; 278 ub = ms->ms_ub; 279 while ((d = mb ^ ub) != 0) { 280 /* 281 * Mouse button change. Convert up to three changes 282 * to the `first' change, and drop it into the event 283 * queue. 284 */ 285 if ((++put) % EV_QSIZE == get) { 286 put--; 287 goto out; 288 } 289 290 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ 291 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ 292 fe->value = mb & d ? VKEY_DOWN : VKEY_UP; 293 fe->time = time; 294 fe++; 295 296 if (put >= EV_QSIZE) { 297 put = 0; 298 fe = &ms->ms_events.ev_q[0]; 299 } 300 any = 1; 301 302 ub ^= d; 303 } 304 if (ms->ms_dx) { 305 if ((++put) % EV_QSIZE == get) { 306 put--; 307 goto out; 308 } 309 310 fe->id = LOC_X_DELTA; 311 fe->value = ms->ms_dx; 312 fe->time = time; 313 fe++; 314 315 if (put >= EV_QSIZE) { 316 put = 0; 317 fe = &ms->ms_events.ev_q[0]; 318 } 319 any = 1; 320 321 ms->ms_dx = 0; 322 } 323 if (ms->ms_dy) { 324 if ((++put) % EV_QSIZE == get) { 325 put--; 326 goto out; 327 } 328 329 fe->id = LOC_Y_DELTA; 330 fe->value = ms->ms_dy; 331 fe->time = time; 332 fe++; 333 334 if (put >= EV_QSIZE) { 335 put = 0; 336 fe = &ms->ms_events.ev_q[0]; 337 } 338 any = 1; 339 340 ms->ms_dy = 0; 341 } 342 out: 343 if (any) { 344 ms->ms_ub = ub; 345 ms->ms_events.ev_put = put; 346 EV_WAKEUP(&ms->ms_events); 347 } 348 } 349 350 /* 351 * reschedule handler, or if terminating, 352 * handshake with ms_disable 353 */ 354 if (ms->ms_ready) 355 callout_reset(&ms->ms_intr_ch, 2, msintr, ms); 356 else 357 wakeup(ms); 358 } 359 360 int 361 msopen(dev_t dev, int flags, int mode, 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_t dev, int flags, int mode, struct proc *p) 390 { 391 struct ms_port *ms; 392 393 ms = MS_DEV2MSPORT(dev); 394 395 ms_disable(ms); 396 ev_fini(&ms->ms_events); 397 ms->ms_events.ev_io = NULL; 398 return(0); 399 } 400 401 int 402 msread(dev_t dev, struct uio *uio, int flags) 403 { 404 struct ms_port *ms; 405 406 ms = MS_DEV2MSPORT(dev); 407 408 return(ev_read(&ms->ms_events, uio, flags)); 409 } 410 411 int 412 msioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, 413 struct proc *p) 414 { 415 struct ms_port *ms; 416 417 ms = MS_DEV2MSPORT(dev); 418 419 switch (cmd) { 420 case FIONBIO: /* we will remove this someday (soon???) */ 421 return(0); 422 case FIOASYNC: 423 ms->ms_events.ev_async = *(int *)data != 0; 424 return(0); 425 case TIOCSPGRP: 426 if (*(int *)data != ms->ms_events.ev_io->p_pgid) 427 return(EPERM); 428 return(0); 429 case VUIDGFORMAT: /* we only do firm_events */ 430 *(int *)data = VUID_FIRM_EVENT; 431 return(0); 432 case VUIDSFORMAT: 433 if (*(int *)data != VUID_FIRM_EVENT) 434 return(EINVAL); 435 return(0); 436 } 437 return(ENOTTY); 438 } 439 440 int 441 mspoll(dev_t dev, int events, struct proc *p) 442 { 443 struct ms_port *ms; 444 445 ms = MS_DEV2MSPORT(dev); 446 447 return(ev_poll(&ms->ms_events, events, p)); 448 } 449