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