1 /* $NetBSD: aed.c,v 1.11 2002/11/26 19:50:27 christos 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 #include <sys/conf.h> 42 43 #include <machine/autoconf.h> 44 #include <machine/cpu.h> 45 #include <machine/keyboard.h> 46 47 #include <macppc/dev/adbvar.h> 48 #include <macppc/dev/aedvar.h> 49 #include <macppc/dev/akbdvar.h> 50 51 #define spladb splhigh 52 53 /* 54 * Function declarations. 55 */ 56 static int aedmatch __P((struct device *, struct cfdata *, void *)); 57 static void aedattach __P((struct device *, struct device *, void *)); 58 static void aed_emulate_mouse __P((adb_event_t *event)); 59 static void aed_kbdrpt __P((void *kstate)); 60 static void aed_dokeyupdown __P((adb_event_t *event)); 61 static void aed_handoff __P((adb_event_t *event)); 62 static void aed_enqevent __P((adb_event_t *event)); 63 64 /* 65 * Global variables. 66 */ 67 extern int adb_polling; /* Are we polling? (Debugger mode) */ 68 69 /* 70 * Local variables. 71 */ 72 static struct aed_softc *aed_sc = NULL; 73 static int aed_options = 0; /* | AED_MSEMUL; */ 74 75 /* Driver definition */ 76 CFATTACH_DECL(aed, sizeof(struct aed_softc), 77 aedmatch, aedattach, NULL, NULL); 78 79 extern struct cfdriver aed_cd; 80 81 dev_type_open(aedopen); 82 dev_type_close(aedclose); 83 dev_type_read(aedread); 84 dev_type_ioctl(aedioctl); 85 dev_type_poll(aedpoll); 86 dev_type_kqfilter(aedkqfilter); 87 88 const struct cdevsw aed_cdevsw = { 89 aedopen, aedclose, aedread, nullwrite, aedioctl, 90 nostop, notty, aedpoll, nommap, aedkqfilter, 91 }; 92 93 static int 94 aedmatch(parent, cf, aux) 95 struct device *parent; 96 struct cfdata *cf; 97 void *aux; 98 { 99 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 100 static int aed_matched = 0; 101 102 /* Allow only one instance. */ 103 if ((aa_args->origaddr == 0) && (!aed_matched)) { 104 aed_matched = 1; 105 return (1); 106 } else 107 return (0); 108 } 109 110 static void 111 aedattach(parent, self, aux) 112 struct device *parent, *self; 113 void *aux; 114 { 115 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 116 struct aed_softc *sc = (struct aed_softc *)self; 117 118 callout_init(&sc->sc_repeat_ch); 119 120 sc->origaddr = aa_args->origaddr; 121 sc->adbaddr = aa_args->adbaddr; 122 sc->handler_id = aa_args->handler_id; 123 124 sc->sc_evq_tail = 0; 125 sc->sc_evq_len = 0; 126 127 sc->sc_rptdelay = 20; 128 sc->sc_rptinterval = 6; 129 sc->sc_repeating = -1; /* not repeating */ 130 131 /* Pull in the options flags. */ 132 sc->sc_options = (sc->sc_dev.dv_cfdata->cf_flags | aed_options); 133 134 sc->sc_ioproc = NULL; 135 136 sc->sc_buttons = 0; 137 138 sc->sc_open = 0; 139 140 aed_sc = sc; 141 142 printf("ADB Event device\n"); 143 144 return; 145 } 146 147 /* 148 * Given a keyboard ADB event, record the keycode and call the key 149 * repeat handler, optionally passing the event through the mouse 150 * button emulation handler first. Pass mouse events directly to 151 * the handoff function. 152 */ 153 void 154 aed_input(event) 155 adb_event_t *event; 156 { 157 adb_event_t new_event = *event; 158 159 switch (event->def_addr) { 160 case ADBADDR_KBD: 161 if (aed_sc->sc_options & AED_MSEMUL) 162 aed_emulate_mouse(&new_event); 163 else 164 aed_dokeyupdown(&new_event); 165 break; 166 case ADBADDR_MS: 167 new_event.u.m.buttons |= aed_sc->sc_buttons; 168 aed_handoff(&new_event); 169 break; 170 default: /* God only knows. */ 171 #ifdef DIAGNOSTIC 172 panic("aed: received event from unsupported device!"); 173 #endif 174 break; 175 } 176 177 } 178 179 /* 180 * Handles mouse button emulation via the keyboard. If the emulation 181 * modifier key is down, left and right arrows will generate 2nd and 182 * 3rd mouse button events while the 1, 2, and 3 keys will generate 183 * the corresponding mouse button event. 184 */ 185 static void 186 aed_emulate_mouse(event) 187 adb_event_t *event; 188 { 189 static int emulmodkey_down = 0; 190 adb_event_t new_event; 191 192 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) { 193 emulmodkey_down = 1; 194 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) { 195 /* key up */ 196 emulmodkey_down = 0; 197 if (aed_sc->sc_buttons & 0xfe) { 198 aed_sc->sc_buttons &= 1; 199 new_event.def_addr = ADBADDR_MS; 200 new_event.u.m.buttons = aed_sc->sc_buttons; 201 new_event.u.m.dx = new_event.u.m.dy = 0; 202 microtime(&new_event.timestamp); 203 aed_handoff(&new_event); 204 } 205 } else if (emulmodkey_down) { 206 switch(event->u.k.key) { 207 #ifdef ALTXBUTTONS 208 case ADBK_KEYDOWN(ADBK_1): 209 aed_sc->sc_buttons |= 1; /* left down */ 210 new_event.def_addr = ADBADDR_MS; 211 new_event.u.m.buttons = aed_sc->sc_buttons; 212 new_event.u.m.dx = new_event.u.m.dy = 0; 213 microtime(&new_event.timestamp); 214 aed_handoff(&new_event); 215 break; 216 case ADBK_KEYUP(ADBK_1): 217 aed_sc->sc_buttons &= ~1; /* left up */ 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 #endif 225 case ADBK_KEYDOWN(ADBK_LEFT): 226 #ifdef ALTXBUTTONS 227 case ADBK_KEYDOWN(ADBK_2): 228 #endif 229 aed_sc->sc_buttons |= 2; /* middle down */ 230 new_event.def_addr = ADBADDR_MS; 231 new_event.u.m.buttons = aed_sc->sc_buttons; 232 new_event.u.m.dx = new_event.u.m.dy = 0; 233 microtime(&new_event.timestamp); 234 aed_handoff(&new_event); 235 break; 236 case ADBK_KEYUP(ADBK_LEFT): 237 #ifdef ALTXBUTTONS 238 case ADBK_KEYUP(ADBK_2): 239 #endif 240 aed_sc->sc_buttons &= ~2; /* middle up */ 241 new_event.def_addr = ADBADDR_MS; 242 new_event.u.m.buttons = aed_sc->sc_buttons; 243 new_event.u.m.dx = new_event.u.m.dy = 0; 244 microtime(&new_event.timestamp); 245 aed_handoff(&new_event); 246 break; 247 case ADBK_KEYDOWN(ADBK_RIGHT): 248 #ifdef ALTXBUTTONS 249 case ADBK_KEYDOWN(ADBK_3): 250 #endif 251 aed_sc->sc_buttons |= 4; /* right down */ 252 new_event.def_addr = ADBADDR_MS; 253 new_event.u.m.buttons = aed_sc->sc_buttons; 254 new_event.u.m.dx = new_event.u.m.dy = 0; 255 microtime(&new_event.timestamp); 256 aed_handoff(&new_event); 257 break; 258 case ADBK_KEYUP(ADBK_RIGHT): 259 #ifdef ALTXBUTTONS 260 case ADBK_KEYUP(ADBK_3): 261 #endif 262 aed_sc->sc_buttons &= ~4; /* right up */ 263 new_event.def_addr = ADBADDR_MS; 264 new_event.u.m.buttons = aed_sc->sc_buttons; 265 new_event.u.m.dx = new_event.u.m.dy = 0; 266 microtime(&new_event.timestamp); 267 aed_handoff(&new_event); 268 break; 269 case ADBK_KEYUP(ADBK_SHIFT): 270 case ADBK_KEYDOWN(ADBK_SHIFT): 271 case ADBK_KEYUP(ADBK_CONTROL): 272 case ADBK_KEYDOWN(ADBK_CONTROL): 273 case ADBK_KEYUP(ADBK_FLOWER): 274 case ADBK_KEYDOWN(ADBK_FLOWER): 275 /* ctrl, shift, cmd */ 276 aed_dokeyupdown(event); 277 break; 278 default: 279 if (event->u.k.key & 0x80) 280 /* ignore keyup */ 281 break; 282 283 /* key down */ 284 new_event = *event; 285 286 /* send option-down */ 287 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION); 288 new_event.bytes[0] = new_event.u.k.key; 289 microtime(&new_event.timestamp); 290 aed_dokeyupdown(&new_event); 291 292 /* send key-down */ 293 new_event.u.k.key = event->bytes[0]; 294 new_event.bytes[0] = new_event.u.k.key; 295 microtime(&new_event.timestamp); 296 aed_dokeyupdown(&new_event); 297 298 /* send key-up */ 299 new_event.u.k.key = 300 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0])); 301 microtime(&new_event.timestamp); 302 new_event.bytes[0] = new_event.u.k.key; 303 aed_dokeyupdown(&new_event); 304 305 /* send option-up */ 306 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION); 307 new_event.bytes[0] = new_event.u.k.key; 308 microtime(&new_event.timestamp); 309 aed_dokeyupdown(&new_event); 310 break; 311 } 312 } else { 313 aed_dokeyupdown(event); 314 } 315 } 316 317 /* 318 * Keyboard autorepeat timeout function. Sends key up/down events 319 * for the repeating key and schedules the next call at sc_rptinterval 320 * ticks in the future. 321 */ 322 static void 323 aed_kbdrpt(kstate) 324 void *kstate; 325 { 326 struct aed_softc *aed_sc = (struct aed_softc *)kstate; 327 328 aed_sc->sc_rptevent.bytes[0] |= 0x80; 329 microtime(&aed_sc->sc_rptevent.timestamp); 330 aed_handoff(&aed_sc->sc_rptevent); /* do key up */ 331 332 aed_sc->sc_rptevent.bytes[0] &= 0x7f; 333 microtime(&aed_sc->sc_rptevent.timestamp); 334 aed_handoff(&aed_sc->sc_rptevent); /* do key down */ 335 336 if (aed_sc->sc_repeating == aed_sc->sc_rptevent.u.k.key) { 337 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptinterval, 338 aed_kbdrpt, kstate); 339 } 340 } 341 342 343 /* 344 * Cancels the currently repeating key event if there is one, schedules 345 * a new repeating key event if needed, and hands the event off to the 346 * appropriate subsystem. 347 */ 348 static void 349 aed_dokeyupdown(event) 350 adb_event_t *event; 351 { 352 int kbd_key; 353 354 kbd_key = ADBK_KEYVAL(event->u.k.key); 355 if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) { 356 /* ignore shift & control */ 357 if (aed_sc->sc_repeating != -1) { 358 callout_stop(&aed_sc->sc_repeat_ch); 359 } 360 aed_sc->sc_rptevent = *event; 361 aed_sc->sc_repeating = kbd_key; 362 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay, 363 aed_kbdrpt, (void *)aed_sc); 364 } else { 365 if (aed_sc->sc_repeating != -1) { 366 aed_sc->sc_repeating = -1; 367 callout_stop(&aed_sc->sc_repeat_ch); 368 } 369 aed_sc->sc_rptevent = *event; 370 } 371 aed_handoff(event); 372 } 373 374 /* 375 * Place the event in the event queue if a requesting device is open 376 * and we are not polling. 377 */ 378 static void 379 aed_handoff(event) 380 adb_event_t *event; 381 { 382 if (aed_sc->sc_open && !adb_polling) 383 aed_enqevent(event); 384 } 385 386 /* 387 * Place the event in the event queue and wakeup any waiting processes. 388 */ 389 static void 390 aed_enqevent(event) 391 adb_event_t *event; 392 { 393 int s; 394 395 s = spladb(); 396 397 #ifdef DIAGNOSTIC 398 if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS) 399 panic("adb: event queue tail is out of bounds"); 400 401 if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS) 402 panic("adb: event queue len is out of bounds"); 403 #endif 404 405 if (aed_sc->sc_evq_len == AED_MAX_EVENTS) { 406 splx(s); 407 return; /* Oh, well... */ 408 } 409 aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) % 410 AED_MAX_EVENTS] = *event; 411 aed_sc->sc_evq_len++; 412 413 selnotify(&aed_sc->sc_selinfo, 0); 414 if (aed_sc->sc_ioproc) 415 psignal(aed_sc->sc_ioproc, SIGIO); 416 417 splx(s); 418 } 419 420 int 421 aedopen(dev, flag, mode, p) 422 dev_t dev; 423 int flag, mode; 424 struct proc *p; 425 { 426 int unit; 427 int error = 0; 428 int s; 429 430 unit = minor(dev); 431 432 if (unit != 0) 433 return (ENXIO); 434 435 s = spladb(); 436 if (aed_sc->sc_open) { 437 splx(s); 438 return (EBUSY); 439 } 440 aed_sc->sc_evq_tail = 0; 441 aed_sc->sc_evq_len = 0; 442 aed_sc->sc_open = 1; 443 aed_sc->sc_ioproc = p; 444 splx(s); 445 446 return (error); 447 } 448 449 450 int 451 aedclose(dev, flag, mode, p) 452 dev_t dev; 453 int flag, mode; 454 struct proc *p; 455 { 456 int s = spladb(); 457 458 aed_sc->sc_open = 0; 459 aed_sc->sc_ioproc = NULL; 460 splx(s); 461 462 return (0); 463 } 464 465 466 int 467 aedread(dev, uio, flag) 468 dev_t dev; 469 struct uio *uio; 470 int flag; 471 { 472 int s, error; 473 int willfit; 474 int total; 475 int firstmove; 476 int moremove; 477 478 if (uio->uio_resid < sizeof(adb_event_t)) 479 return (EMSGSIZE); /* close enough. */ 480 481 s = spladb(); 482 if (aed_sc->sc_evq_len == 0) { 483 splx(s); 484 return (0); 485 } 486 willfit = howmany(uio->uio_resid, sizeof(adb_event_t)); 487 total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit; 488 489 firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS) 490 ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total; 491 492 error = uiomove((caddr_t) & aed_sc->sc_evq[aed_sc->sc_evq_tail], 493 firstmove * sizeof(adb_event_t), uio); 494 if (error) { 495 splx(s); 496 return (error); 497 } 498 moremove = total - firstmove; 499 500 if (moremove > 0) { 501 error = uiomove((caddr_t) & aed_sc->sc_evq[0], 502 moremove * sizeof(adb_event_t), uio); 503 if (error) { 504 splx(s); 505 return (error); 506 } 507 } 508 aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS; 509 aed_sc->sc_evq_len -= total; 510 splx(s); 511 return (0); 512 } 513 514 int 515 aedioctl(dev, cmd, data, flag, p) 516 dev_t dev; 517 u_long cmd; 518 caddr_t data; 519 int flag; 520 struct proc *p; 521 { 522 switch (cmd) { 523 case ADBIOCDEVSINFO: { 524 adb_devinfo_t *di; 525 ADBDataBlock adbdata; 526 int totaldevs; 527 int adbaddr; 528 int i; 529 530 di = (void *)data; 531 532 /* Initialize to no devices */ 533 for (i = 0; i < 16; i++) 534 di->dev[i].addr = -1; 535 536 totaldevs = CountADBs(); 537 for (i = 1; i <= totaldevs; i++) { 538 adbaddr = GetIndADB(&adbdata, i); 539 di->dev[adbaddr].addr = adbaddr; 540 di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr); 541 di->dev[adbaddr].handler_id = (int)(adbdata.devType); 542 } 543 544 /* Must call ADB Manager to get devices now */ 545 break; 546 } 547 548 case ADBIOCGETREPEAT:{ 549 adb_rptinfo_t *ri; 550 551 ri = (void *)data; 552 ri->delay_ticks = aed_sc->sc_rptdelay; 553 ri->interval_ticks = aed_sc->sc_rptinterval; 554 break; 555 } 556 557 case ADBIOCSETREPEAT:{ 558 adb_rptinfo_t *ri; 559 560 ri = (void *) data; 561 aed_sc->sc_rptdelay = ri->delay_ticks; 562 aed_sc->sc_rptinterval = ri->interval_ticks; 563 break; 564 } 565 566 case ADBIOCRESET: 567 /* Do nothing for now */ 568 break; 569 570 case ADBIOCLISTENCMD:{ 571 adb_listencmd_t *lc; 572 573 lc = (void *)data; 574 } 575 576 default: 577 return (EINVAL); 578 } 579 return (0); 580 } 581 582 583 int 584 aedpoll(dev, events, p) 585 dev_t dev; 586 int events; 587 struct proc *p; 588 { 589 int s, revents; 590 591 revents = events & (POLLOUT | POLLWRNORM); 592 593 if ((events & (POLLIN | POLLRDNORM)) == 0) 594 return (revents); 595 596 s = spladb(); 597 if (aed_sc->sc_evq_len > 0) 598 revents |= events & (POLLIN | POLLRDNORM); 599 else 600 selrecord(p, &aed_sc->sc_selinfo); 601 splx(s); 602 603 return (revents); 604 } 605 606 static void 607 filt_aedrdetach(struct knote *kn) 608 { 609 int s; 610 611 s = spladb(); 612 SLIST_REMOVE(&aed_sc->sc_selinfo.sel_klist, kn, knote, kn_selnext); 613 splx(s); 614 } 615 616 static int 617 filt_aedread(struct knote *kn, long hint) 618 { 619 620 kn->kn_data = aed_sc->sc_evq_len * sizeof(adb_event_t); 621 return (kn->kn_data > 0); 622 } 623 624 static const struct filterops aedread_filtops = 625 { 1, NULL, filt_aedrdetach, filt_aedread }; 626 627 static const struct filterops aed_seltrue_filtops = 628 { 1, NULL, filt_aedrdetach, filt_seltrue }; 629 630 int 631 aedkqfilter(dev_t dev, struct knote *kn) 632 { 633 struct klist *klist; 634 int s; 635 636 switch (kn->kn_filter) { 637 case EVFILT_READ: 638 klist = &aed_sc->sc_selinfo.sel_klist; 639 kn->kn_fop = &aedread_filtops; 640 break; 641 642 case EVFILT_WRITE: 643 klist = &aed_sc->sc_selinfo.sel_klist; 644 kn->kn_fop = &aed_seltrue_filtops; 645 break; 646 647 default: 648 return (1); 649 } 650 651 kn->kn_hook = NULL; 652 653 s = spladb(); 654 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 655 splx(s); 656 657 return (0); 658 } 659