1 /* $NetBSD: aed.c,v 1.5 2000/03/23 06:40:33 thorpej Exp $ */ 2 3 /* 4 * Copyright (C) 1994 Bradley A. Grantham 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bradley A. Grantham. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/device.h> 35 #include <sys/fcntl.h> 36 #include <sys/poll.h> 37 #include <sys/select.h> 38 #include <sys/proc.h> 39 #include <sys/signalvar.h> 40 #include <sys/systm.h> 41 42 #include <machine/autoconf.h> 43 #include <machine/cpu.h> 44 #include <machine/keyboard.h> 45 46 #include <macppc/dev/adbvar.h> 47 #include <macppc/dev/aedvar.h> 48 #include <macppc/dev/akbdvar.h> 49 50 #define spladb splhigh 51 52 /* 53 * Function declarations. 54 */ 55 static int aedmatch __P((struct device *, struct cfdata *, void *)); 56 static void aedattach __P((struct device *, struct device *, void *)); 57 static void aed_emulate_mouse __P((adb_event_t *event)); 58 static void aed_kbdrpt __P((void *kstate)); 59 static void aed_dokeyupdown __P((adb_event_t *event)); 60 static void aed_handoff __P((adb_event_t *event)); 61 static void aed_enqevent __P((adb_event_t *event)); 62 63 /* 64 * Global variables. 65 */ 66 extern int adb_polling; /* Are we polling? (Debugger mode) */ 67 68 /* 69 * Local variables. 70 */ 71 static struct aed_softc *aed_sc = NULL; 72 static int aed_options = 0; /* | AED_MSEMUL; */ 73 74 /* Driver definition */ 75 struct cfattach aed_ca = { 76 sizeof(struct aed_softc), aedmatch, aedattach 77 }; 78 79 extern struct cfdriver aed_cd; 80 81 static int 82 aedmatch(parent, cf, aux) 83 struct device *parent; 84 struct cfdata *cf; 85 void *aux; 86 { 87 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 88 static int aed_matched = 0; 89 90 /* Allow only one instance. */ 91 if ((aa_args->origaddr == 0) && (!aed_matched)) { 92 aed_matched = 1; 93 return (1); 94 } else 95 return (0); 96 } 97 98 static void 99 aedattach(parent, self, aux) 100 struct device *parent, *self; 101 void *aux; 102 { 103 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 104 struct aed_softc *sc = (struct aed_softc *)self; 105 106 callout_init(&sc->sc_repeat_ch); 107 108 sc->origaddr = aa_args->origaddr; 109 sc->adbaddr = aa_args->adbaddr; 110 sc->handler_id = aa_args->handler_id; 111 112 sc->sc_evq_tail = 0; 113 sc->sc_evq_len = 0; 114 115 sc->sc_rptdelay = 20; 116 sc->sc_rptinterval = 6; 117 sc->sc_repeating = -1; /* not repeating */ 118 119 /* Pull in the options flags. */ 120 sc->sc_options = (sc->sc_dev.dv_cfdata->cf_flags | aed_options); 121 122 sc->sc_ioproc = NULL; 123 124 sc->sc_buttons = 0; 125 126 sc->sc_open = 0; 127 128 aed_sc = sc; 129 130 printf("ADB Event device\n"); 131 132 return; 133 } 134 135 /* 136 * Given a keyboard ADB event, record the keycode and call the key 137 * repeat handler, optionally passing the event through the mouse 138 * button emulation handler first. Pass mouse events directly to 139 * the handoff function. 140 */ 141 void 142 aed_input(event) 143 adb_event_t *event; 144 { 145 adb_event_t new_event = *event; 146 147 switch (event->def_addr) { 148 case ADBADDR_KBD: 149 if (aed_sc->sc_options & AED_MSEMUL) 150 aed_emulate_mouse(&new_event); 151 else 152 aed_dokeyupdown(&new_event); 153 break; 154 case ADBADDR_MS: 155 new_event.u.m.buttons |= aed_sc->sc_buttons; 156 aed_handoff(&new_event); 157 break; 158 default: /* God only knows. */ 159 #ifdef DIAGNOSTIC 160 panic("aed: received event from unsupported device!\n"); 161 #endif 162 break; 163 } 164 165 } 166 167 /* 168 * Handles mouse button emulation via the keyboard. If the emulation 169 * modifier key is down, left and right arrows will generate 2nd and 170 * 3rd mouse button events while the 1, 2, and 3 keys will generate 171 * the corresponding mouse button event. 172 */ 173 static void 174 aed_emulate_mouse(event) 175 adb_event_t *event; 176 { 177 static int emulmodkey_down = 0; 178 adb_event_t new_event; 179 180 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) { 181 emulmodkey_down = 1; 182 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) { 183 /* key up */ 184 emulmodkey_down = 0; 185 if (aed_sc->sc_buttons & 0xfe) { 186 aed_sc->sc_buttons &= 1; 187 new_event.def_addr = ADBADDR_MS; 188 new_event.u.m.buttons = aed_sc->sc_buttons; 189 new_event.u.m.dx = new_event.u.m.dy = 0; 190 microtime(&new_event.timestamp); 191 aed_handoff(&new_event); 192 } 193 } else if (emulmodkey_down) { 194 switch(event->u.k.key) { 195 #ifdef ALTXBUTTONS 196 case ADBK_KEYDOWN(ADBK_1): 197 aed_sc->sc_buttons |= 1; /* left down */ 198 new_event.def_addr = ADBADDR_MS; 199 new_event.u.m.buttons = aed_sc->sc_buttons; 200 new_event.u.m.dx = new_event.u.m.dy = 0; 201 microtime(&new_event.timestamp); 202 aed_handoff(&new_event); 203 break; 204 case ADBK_KEYUP(ADBK_1): 205 aed_sc->sc_buttons &= ~1; /* left up */ 206 new_event.def_addr = ADBADDR_MS; 207 new_event.u.m.buttons = aed_sc->sc_buttons; 208 new_event.u.m.dx = new_event.u.m.dy = 0; 209 microtime(&new_event.timestamp); 210 aed_handoff(&new_event); 211 break; 212 #endif 213 case ADBK_KEYDOWN(ADBK_LEFT): 214 #ifdef ALTXBUTTONS 215 case ADBK_KEYDOWN(ADBK_2): 216 #endif 217 aed_sc->sc_buttons |= 2; /* middle down */ 218 new_event.def_addr = ADBADDR_MS; 219 new_event.u.m.buttons = aed_sc->sc_buttons; 220 new_event.u.m.dx = new_event.u.m.dy = 0; 221 microtime(&new_event.timestamp); 222 aed_handoff(&new_event); 223 break; 224 case ADBK_KEYUP(ADBK_LEFT): 225 #ifdef ALTXBUTTONS 226 case ADBK_KEYUP(ADBK_2): 227 #endif 228 aed_sc->sc_buttons &= ~2; /* middle up */ 229 new_event.def_addr = ADBADDR_MS; 230 new_event.u.m.buttons = aed_sc->sc_buttons; 231 new_event.u.m.dx = new_event.u.m.dy = 0; 232 microtime(&new_event.timestamp); 233 aed_handoff(&new_event); 234 break; 235 case ADBK_KEYDOWN(ADBK_RIGHT): 236 #ifdef ALTXBUTTONS 237 case ADBK_KEYDOWN(ADBK_3): 238 #endif 239 aed_sc->sc_buttons |= 4; /* right down */ 240 new_event.def_addr = ADBADDR_MS; 241 new_event.u.m.buttons = aed_sc->sc_buttons; 242 new_event.u.m.dx = new_event.u.m.dy = 0; 243 microtime(&new_event.timestamp); 244 aed_handoff(&new_event); 245 break; 246 case ADBK_KEYUP(ADBK_RIGHT): 247 #ifdef ALTXBUTTONS 248 case ADBK_KEYUP(ADBK_3): 249 #endif 250 aed_sc->sc_buttons &= ~4; /* right up */ 251 new_event.def_addr = ADBADDR_MS; 252 new_event.u.m.buttons = aed_sc->sc_buttons; 253 new_event.u.m.dx = new_event.u.m.dy = 0; 254 microtime(&new_event.timestamp); 255 aed_handoff(&new_event); 256 break; 257 case ADBK_KEYUP(ADBK_SHIFT): 258 case ADBK_KEYDOWN(ADBK_SHIFT): 259 case ADBK_KEYUP(ADBK_CONTROL): 260 case ADBK_KEYDOWN(ADBK_CONTROL): 261 case ADBK_KEYUP(ADBK_FLOWER): 262 case ADBK_KEYDOWN(ADBK_FLOWER): 263 /* ctrl, shift, cmd */ 264 aed_dokeyupdown(event); 265 break; 266 default: 267 if (event->u.k.key & 0x80) 268 /* ignore keyup */ 269 break; 270 271 /* key down */ 272 new_event = *event; 273 274 /* send option-down */ 275 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION); 276 new_event.bytes[0] = new_event.u.k.key; 277 microtime(&new_event.timestamp); 278 aed_dokeyupdown(&new_event); 279 280 /* send key-down */ 281 new_event.u.k.key = event->bytes[0]; 282 new_event.bytes[0] = new_event.u.k.key; 283 microtime(&new_event.timestamp); 284 aed_dokeyupdown(&new_event); 285 286 /* send key-up */ 287 new_event.u.k.key = 288 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0])); 289 microtime(&new_event.timestamp); 290 new_event.bytes[0] = new_event.u.k.key; 291 aed_dokeyupdown(&new_event); 292 293 /* send option-up */ 294 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION); 295 new_event.bytes[0] = new_event.u.k.key; 296 microtime(&new_event.timestamp); 297 aed_dokeyupdown(&new_event); 298 break; 299 } 300 } else { 301 aed_dokeyupdown(event); 302 } 303 } 304 305 /* 306 * Keyboard autorepeat timeout function. Sends key up/down events 307 * for the repeating key and schedules the next call at sc_rptinterval 308 * ticks in the future. 309 */ 310 static void 311 aed_kbdrpt(kstate) 312 void *kstate; 313 { 314 struct aed_softc *aed_sc = (struct aed_softc *)kstate; 315 316 aed_sc->sc_rptevent.bytes[0] |= 0x80; 317 microtime(&aed_sc->sc_rptevent.timestamp); 318 aed_handoff(&aed_sc->sc_rptevent); /* do key up */ 319 320 aed_sc->sc_rptevent.bytes[0] &= 0x7f; 321 microtime(&aed_sc->sc_rptevent.timestamp); 322 aed_handoff(&aed_sc->sc_rptevent); /* do key down */ 323 324 if (aed_sc->sc_repeating == aed_sc->sc_rptevent.u.k.key) { 325 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptinterval, 326 aed_kbdrpt, kstate); 327 } 328 } 329 330 331 /* 332 * Cancels the currently repeating key event if there is one, schedules 333 * a new repeating key event if needed, and hands the event off to the 334 * appropriate subsystem. 335 */ 336 static void 337 aed_dokeyupdown(event) 338 adb_event_t *event; 339 { 340 int kbd_key; 341 342 kbd_key = ADBK_KEYVAL(event->u.k.key); 343 if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) { 344 /* ignore shift & control */ 345 if (aed_sc->sc_repeating != -1) { 346 callout_stop(&aed_sc->sc_repeat_ch); 347 } 348 aed_sc->sc_rptevent = *event; 349 aed_sc->sc_repeating = kbd_key; 350 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay, 351 aed_kbdrpt, (void *)aed_sc); 352 } else { 353 if (aed_sc->sc_repeating != -1) { 354 aed_sc->sc_repeating = -1; 355 callout_stop(&aed_sc->sc_repeat_ch); 356 } 357 aed_sc->sc_rptevent = *event; 358 } 359 aed_handoff(event); 360 } 361 362 /* 363 * Place the event in the event queue if a requesting device is open 364 * and we are not polling. 365 */ 366 static void 367 aed_handoff(event) 368 adb_event_t *event; 369 { 370 if (aed_sc->sc_open && !adb_polling) 371 aed_enqevent(event); 372 } 373 374 /* 375 * Place the event in the event queue and wakeup any waiting processes. 376 */ 377 static void 378 aed_enqevent(event) 379 adb_event_t *event; 380 { 381 int s; 382 383 s = spladb(); 384 385 #ifdef DIAGNOSTIC 386 if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS) 387 panic("adb: event queue tail is out of bounds"); 388 389 if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS) 390 panic("adb: event queue len is out of bounds"); 391 #endif 392 393 if (aed_sc->sc_evq_len == AED_MAX_EVENTS) { 394 splx(s); 395 return; /* Oh, well... */ 396 } 397 aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) % 398 AED_MAX_EVENTS] = *event; 399 aed_sc->sc_evq_len++; 400 401 selwakeup(&aed_sc->sc_selinfo); 402 if (aed_sc->sc_ioproc) 403 psignal(aed_sc->sc_ioproc, SIGIO); 404 405 splx(s); 406 } 407 408 int 409 aedopen(dev, flag, mode, p) 410 dev_t dev; 411 int flag, mode; 412 struct proc *p; 413 { 414 int unit; 415 int error = 0; 416 int s; 417 418 unit = minor(dev); 419 420 if (unit != 0) 421 return (ENXIO); 422 423 s = spladb(); 424 if (aed_sc->sc_open) { 425 splx(s); 426 return (EBUSY); 427 } 428 aed_sc->sc_evq_tail = 0; 429 aed_sc->sc_evq_len = 0; 430 aed_sc->sc_open = 1; 431 aed_sc->sc_ioproc = p; 432 splx(s); 433 434 return (error); 435 } 436 437 438 int 439 aedclose(dev, flag, mode, p) 440 dev_t dev; 441 int flag, mode; 442 struct proc *p; 443 { 444 int s = spladb(); 445 446 aed_sc->sc_open = 0; 447 aed_sc->sc_ioproc = NULL; 448 splx(s); 449 450 return (0); 451 } 452 453 454 int 455 aedread(dev, uio, flag) 456 dev_t dev; 457 struct uio *uio; 458 int flag; 459 { 460 int s, error; 461 int willfit; 462 int total; 463 int firstmove; 464 int moremove; 465 466 if (uio->uio_resid < sizeof(adb_event_t)) 467 return (EMSGSIZE); /* close enough. */ 468 469 s = spladb(); 470 if (aed_sc->sc_evq_len == 0) { 471 splx(s); 472 return (0); 473 } 474 willfit = howmany(uio->uio_resid, sizeof(adb_event_t)); 475 total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit; 476 477 firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS) 478 ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total; 479 480 error = uiomove((caddr_t) & aed_sc->sc_evq[aed_sc->sc_evq_tail], 481 firstmove * sizeof(adb_event_t), uio); 482 if (error) { 483 splx(s); 484 return (error); 485 } 486 moremove = total - firstmove; 487 488 if (moremove > 0) { 489 error = uiomove((caddr_t) & aed_sc->sc_evq[0], 490 moremove * sizeof(adb_event_t), uio); 491 if (error) { 492 splx(s); 493 return (error); 494 } 495 } 496 aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS; 497 aed_sc->sc_evq_len -= total; 498 splx(s); 499 return (0); 500 } 501 502 503 int 504 aedwrite(dev, uio, flag) 505 dev_t dev; 506 struct uio *uio; 507 int flag; 508 { 509 return 0; 510 } 511 512 513 int 514 aedioctl(dev, cmd, data, flag, p) 515 dev_t dev; 516 int cmd; 517 caddr_t data; 518 int flag; 519 struct proc *p; 520 { 521 switch (cmd) { 522 case ADBIOCDEVSINFO: { 523 adb_devinfo_t *di; 524 ADBDataBlock adbdata; 525 int totaldevs; 526 int adbaddr; 527 int i; 528 529 di = (void *)data; 530 531 /* Initialize to no devices */ 532 for (i = 0; i < 16; i++) 533 di->dev[i].addr = -1; 534 535 totaldevs = CountADBs(); 536 for (i = 1; i <= totaldevs; i++) { 537 adbaddr = GetIndADB(&adbdata, i); 538 di->dev[adbaddr].addr = adbaddr; 539 di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr); 540 di->dev[adbaddr].handler_id = (int)(adbdata.devType); 541 } 542 543 /* Must call ADB Manager to get devices now */ 544 break; 545 } 546 547 case ADBIOCGETREPEAT:{ 548 adb_rptinfo_t *ri; 549 550 ri = (void *)data; 551 ri->delay_ticks = aed_sc->sc_rptdelay; 552 ri->interval_ticks = aed_sc->sc_rptinterval; 553 break; 554 } 555 556 case ADBIOCSETREPEAT:{ 557 adb_rptinfo_t *ri; 558 559 ri = (void *) data; 560 aed_sc->sc_rptdelay = ri->delay_ticks; 561 aed_sc->sc_rptinterval = ri->interval_ticks; 562 break; 563 } 564 565 case ADBIOCRESET: 566 /* Do nothing for now */ 567 break; 568 569 case ADBIOCLISTENCMD:{ 570 adb_listencmd_t *lc; 571 572 lc = (void *)data; 573 } 574 575 default: 576 return (EINVAL); 577 } 578 return (0); 579 } 580 581 582 int 583 aedpoll(dev, events, p) 584 dev_t dev; 585 int events; 586 struct proc *p; 587 { 588 int s, revents; 589 590 revents = events & (POLLOUT | POLLWRNORM); 591 592 if ((events & (POLLIN | POLLRDNORM)) == 0) 593 return (revents); 594 595 s = spladb(); 596 if (aed_sc->sc_evq_len > 0) 597 revents |= events & (POLLIN | POLLRDNORM); 598 else 599 selrecord(p, &aed_sc->sc_selinfo); 600 splx(s); 601 602 return (revents); 603 } 604