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