1 /* $NetBSD: aed.c,v 1.24 2009/03/14 21:04:11 dsl 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.24 2009/03/14 21:04:11 dsl 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(struct device *, struct cfdata *, void *); 60 static void aedattach(struct device *, struct device *, void *); 61 static void aed_emulate_mouse(adb_event_t *event); 62 static void aed_kbdrpt(void *kstate); 63 static void aed_dokeyupdown(adb_event_t *event); 64 static void aed_handoff(adb_event_t *event); 65 static void aed_enqevent(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(struct device *parent, struct cfdata *cf, 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(struct device *parent, struct device *self, void *aux) 112 { 113 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 114 struct aed_softc *sc = (struct aed_softc *)self; 115 116 callout_init(&sc->sc_repeat_ch, 0); 117 selinit(&sc->sc_selinfo); 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 = (device_cfdata(&sc->sc_dev)->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 void 153 aed_input(adb_event_t *event) 154 { 155 adb_event_t new_event = *event; 156 157 switch (event->def_addr) { 158 case ADBADDR_KBD: 159 if (aed_sc->sc_options & AED_MSEMUL) 160 aed_emulate_mouse(&new_event); 161 else 162 aed_dokeyupdown(&new_event); 163 break; 164 case ADBADDR_MS: 165 new_event.u.m.buttons |= aed_sc->sc_buttons; 166 aed_handoff(&new_event); 167 break; 168 default: /* God only knows. */ 169 #ifdef DIAGNOSTIC 170 panic("aed: received event from unsupported device!"); 171 #endif 172 break; 173 } 174 175 } 176 177 /* 178 * Handles mouse button emulation via the keyboard. If the emulation 179 * modifier key is down, left and right arrows will generate 2nd and 180 * 3rd mouse button events while the 1, 2, and 3 keys will generate 181 * the corresponding mouse button event. 182 */ 183 static void 184 aed_emulate_mouse(adb_event_t *event) 185 { 186 static int emulmodkey_down = 0; 187 adb_event_t new_event; 188 189 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) { 190 emulmodkey_down = 1; 191 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) { 192 /* key up */ 193 emulmodkey_down = 0; 194 if (aed_sc->sc_buttons & 0xfe) { 195 aed_sc->sc_buttons &= 1; 196 new_event.def_addr = ADBADDR_MS; 197 new_event.u.m.buttons = aed_sc->sc_buttons; 198 new_event.u.m.dx = new_event.u.m.dy = 0; 199 microtime(&new_event.timestamp); 200 aed_handoff(&new_event); 201 } 202 } else if (emulmodkey_down) { 203 switch(event->u.k.key) { 204 #ifdef ALTXBUTTONS 205 case ADBK_KEYDOWN(ADBK_1): 206 aed_sc->sc_buttons |= 1; /* left down */ 207 new_event.def_addr = ADBADDR_MS; 208 new_event.u.m.buttons = aed_sc->sc_buttons; 209 new_event.u.m.dx = new_event.u.m.dy = 0; 210 microtime(&new_event.timestamp); 211 aed_handoff(&new_event); 212 break; 213 case ADBK_KEYUP(ADBK_1): 214 aed_sc->sc_buttons &= ~1; /* left up */ 215 new_event.def_addr = ADBADDR_MS; 216 new_event.u.m.buttons = aed_sc->sc_buttons; 217 new_event.u.m.dx = new_event.u.m.dy = 0; 218 microtime(&new_event.timestamp); 219 aed_handoff(&new_event); 220 break; 221 #endif 222 case ADBK_KEYDOWN(ADBK_LEFT): 223 #ifdef ALTXBUTTONS 224 case ADBK_KEYDOWN(ADBK_2): 225 #endif 226 aed_sc->sc_buttons |= 2; /* middle down */ 227 new_event.def_addr = ADBADDR_MS; 228 new_event.u.m.buttons = aed_sc->sc_buttons; 229 new_event.u.m.dx = new_event.u.m.dy = 0; 230 microtime(&new_event.timestamp); 231 aed_handoff(&new_event); 232 break; 233 case ADBK_KEYUP(ADBK_LEFT): 234 #ifdef ALTXBUTTONS 235 case ADBK_KEYUP(ADBK_2): 236 #endif 237 aed_sc->sc_buttons &= ~2; /* middle up */ 238 new_event.def_addr = ADBADDR_MS; 239 new_event.u.m.buttons = aed_sc->sc_buttons; 240 new_event.u.m.dx = new_event.u.m.dy = 0; 241 microtime(&new_event.timestamp); 242 aed_handoff(&new_event); 243 break; 244 case ADBK_KEYDOWN(ADBK_RIGHT): 245 #ifdef ALTXBUTTONS 246 case ADBK_KEYDOWN(ADBK_3): 247 #endif 248 aed_sc->sc_buttons |= 4; /* right down */ 249 new_event.def_addr = ADBADDR_MS; 250 new_event.u.m.buttons = aed_sc->sc_buttons; 251 new_event.u.m.dx = new_event.u.m.dy = 0; 252 microtime(&new_event.timestamp); 253 aed_handoff(&new_event); 254 break; 255 case ADBK_KEYUP(ADBK_RIGHT): 256 #ifdef ALTXBUTTONS 257 case ADBK_KEYUP(ADBK_3): 258 #endif 259 aed_sc->sc_buttons &= ~4; /* right up */ 260 new_event.def_addr = ADBADDR_MS; 261 new_event.u.m.buttons = aed_sc->sc_buttons; 262 new_event.u.m.dx = new_event.u.m.dy = 0; 263 microtime(&new_event.timestamp); 264 aed_handoff(&new_event); 265 break; 266 case ADBK_KEYUP(ADBK_SHIFT): 267 case ADBK_KEYDOWN(ADBK_SHIFT): 268 case ADBK_KEYUP(ADBK_CONTROL): 269 case ADBK_KEYDOWN(ADBK_CONTROL): 270 case ADBK_KEYUP(ADBK_FLOWER): 271 case ADBK_KEYDOWN(ADBK_FLOWER): 272 /* ctrl, shift, cmd */ 273 aed_dokeyupdown(event); 274 break; 275 default: 276 if (event->u.k.key & 0x80) 277 /* ignore keyup */ 278 break; 279 280 /* key down */ 281 new_event = *event; 282 283 /* send option-down */ 284 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION); 285 new_event.bytes[0] = new_event.u.k.key; 286 microtime(&new_event.timestamp); 287 aed_dokeyupdown(&new_event); 288 289 /* send key-down */ 290 new_event.u.k.key = event->bytes[0]; 291 new_event.bytes[0] = new_event.u.k.key; 292 microtime(&new_event.timestamp); 293 aed_dokeyupdown(&new_event); 294 295 /* send key-up */ 296 new_event.u.k.key = 297 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0])); 298 microtime(&new_event.timestamp); 299 new_event.bytes[0] = new_event.u.k.key; 300 aed_dokeyupdown(&new_event); 301 302 /* send option-up */ 303 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION); 304 new_event.bytes[0] = new_event.u.k.key; 305 microtime(&new_event.timestamp); 306 aed_dokeyupdown(&new_event); 307 break; 308 } 309 } else { 310 aed_dokeyupdown(event); 311 } 312 } 313 314 /* 315 * Keyboard autorepeat timeout function. Sends key up/down events 316 * for the repeating key and schedules the next call at sc_rptinterval 317 * ticks in the future. 318 */ 319 static void 320 aed_kbdrpt(void *kstate) 321 { 322 struct aed_softc *sc = (struct aed_softc *)kstate; 323 324 sc->sc_rptevent.bytes[0] |= 0x80; 325 microtime(&sc->sc_rptevent.timestamp); 326 aed_handoff(&sc->sc_rptevent); /* do key up */ 327 328 sc->sc_rptevent.bytes[0] &= 0x7f; 329 microtime(&sc->sc_rptevent.timestamp); 330 aed_handoff(&sc->sc_rptevent); /* do key down */ 331 332 if (sc->sc_repeating == sc->sc_rptevent.u.k.key) { 333 callout_reset(&sc->sc_repeat_ch, sc->sc_rptinterval, 334 aed_kbdrpt, kstate); 335 } 336 } 337 338 339 /* 340 * Cancels the currently repeating key event if there is one, schedules 341 * a new repeating key event if needed, and hands the event off to the 342 * appropriate subsystem. 343 */ 344 static void 345 aed_dokeyupdown(adb_event_t *event) 346 { 347 int kbd_key; 348 349 kbd_key = ADBK_KEYVAL(event->u.k.key); 350 if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) { 351 /* ignore shift & control */ 352 if (aed_sc->sc_repeating != -1) { 353 callout_stop(&aed_sc->sc_repeat_ch); 354 } 355 aed_sc->sc_rptevent = *event; 356 aed_sc->sc_repeating = kbd_key; 357 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay, 358 aed_kbdrpt, (void *)aed_sc); 359 } else { 360 if (aed_sc->sc_repeating != -1) { 361 aed_sc->sc_repeating = -1; 362 callout_stop(&aed_sc->sc_repeat_ch); 363 } 364 aed_sc->sc_rptevent = *event; 365 } 366 aed_handoff(event); 367 } 368 369 /* 370 * Place the event in the event queue if a requesting device is open 371 * and we are not polling. 372 */ 373 static void 374 aed_handoff(adb_event_t *event) 375 { 376 if (aed_sc->sc_open && !adb_polling) 377 aed_enqevent(event); 378 } 379 380 /* 381 * Place the event in the event queue and wakeup any waiting processes. 382 */ 383 static void 384 aed_enqevent(adb_event_t *event) 385 { 386 int s; 387 388 s = spladb(); 389 390 #ifdef DIAGNOSTIC 391 if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS) 392 panic("adb: event queue tail is out of bounds"); 393 394 if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS) 395 panic("adb: event queue len is out of bounds"); 396 #endif 397 398 if (aed_sc->sc_evq_len == AED_MAX_EVENTS) { 399 splx(s); 400 return; /* Oh, well... */ 401 } 402 aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) % 403 AED_MAX_EVENTS] = *event; 404 aed_sc->sc_evq_len++; 405 406 selnotify(&aed_sc->sc_selinfo, 0, 0); 407 if (aed_sc->sc_ioproc) 408 psignal(aed_sc->sc_ioproc, SIGIO); 409 410 splx(s); 411 } 412 413 int 414 aedopen(dev_t dev, int flag, int mode, struct lwp *l) 415 { 416 int unit; 417 int error = 0; 418 int s; 419 420 unit = minor(dev); 421 422 if (unit != 0) 423 return (ENXIO); 424 425 s = spladb(); 426 if (aed_sc->sc_open) { 427 splx(s); 428 return (EBUSY); 429 } 430 aed_sc->sc_evq_tail = 0; 431 aed_sc->sc_evq_len = 0; 432 aed_sc->sc_open = 1; 433 aed_sc->sc_ioproc = l->l_proc; 434 splx(s); 435 436 return (error); 437 } 438 439 440 int 441 aedclose(dev_t dev, int flag, int mode, struct lwp *l) 442 { 443 int s = spladb(); 444 445 aed_sc->sc_open = 0; 446 aed_sc->sc_ioproc = NULL; 447 splx(s); 448 449 return (0); 450 } 451 452 453 int 454 aedread(dev_t dev, struct uio *uio, int flag) 455 { 456 int s, error; 457 int willfit; 458 int total; 459 int firstmove; 460 int moremove; 461 462 if (uio->uio_resid < sizeof(adb_event_t)) 463 return (EMSGSIZE); /* close enough. */ 464 465 s = spladb(); 466 if (aed_sc->sc_evq_len == 0) { 467 splx(s); 468 return (0); 469 } 470 willfit = howmany(uio->uio_resid, sizeof(adb_event_t)); 471 total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit; 472 473 firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS) 474 ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total; 475 476 error = uiomove((void *) & aed_sc->sc_evq[aed_sc->sc_evq_tail], 477 firstmove * sizeof(adb_event_t), uio); 478 if (error) { 479 splx(s); 480 return (error); 481 } 482 moremove = total - firstmove; 483 484 if (moremove > 0) { 485 error = uiomove((void *) & aed_sc->sc_evq[0], 486 moremove * sizeof(adb_event_t), uio); 487 if (error) { 488 splx(s); 489 return (error); 490 } 491 } 492 aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS; 493 aed_sc->sc_evq_len -= total; 494 splx(s); 495 return (0); 496 } 497 498 int 499 aedioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 500 { 501 switch (cmd) { 502 case ADBIOCDEVSINFO: { 503 adb_devinfo_t *di; 504 ADBDataBlock adbdata; 505 int totaldevs; 506 int adbaddr; 507 int i; 508 509 di = (void *)data; 510 511 /* Initialize to no devices */ 512 for (i = 0; i < 16; i++) 513 di->dev[i].addr = -1; 514 515 totaldevs = CountADBs(); 516 for (i = 1; i <= totaldevs; i++) { 517 adbaddr = GetIndADB(&adbdata, i); 518 di->dev[adbaddr].addr = adbaddr; 519 di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr); 520 di->dev[adbaddr].handler_id = (int)(adbdata.devType); 521 } 522 523 /* Must call ADB Manager to get devices now */ 524 break; 525 } 526 527 case ADBIOCGETREPEAT:{ 528 adb_rptinfo_t *ri; 529 530 ri = (void *)data; 531 ri->delay_ticks = aed_sc->sc_rptdelay; 532 ri->interval_ticks = aed_sc->sc_rptinterval; 533 break; 534 } 535 536 case ADBIOCSETREPEAT:{ 537 adb_rptinfo_t *ri; 538 539 ri = (void *) data; 540 aed_sc->sc_rptdelay = ri->delay_ticks; 541 aed_sc->sc_rptinterval = ri->interval_ticks; 542 break; 543 } 544 545 case ADBIOCRESET: 546 /* Do nothing for now */ 547 break; 548 549 case ADBIOCLISTENCMD:{ 550 adb_listencmd_t *lc; 551 552 lc = (void *)data; 553 } 554 555 default: 556 return (EINVAL); 557 } 558 return (0); 559 } 560 561 562 int 563 aedpoll(dev_t dev, int events, struct lwp *l) 564 { 565 int s, revents; 566 567 revents = events & (POLLOUT | POLLWRNORM); 568 569 if ((events & (POLLIN | POLLRDNORM)) == 0) 570 return (revents); 571 572 s = spladb(); 573 if (aed_sc->sc_evq_len > 0) 574 revents |= events & (POLLIN | POLLRDNORM); 575 else 576 selrecord(l, &aed_sc->sc_selinfo); 577 splx(s); 578 579 return (revents); 580 } 581 582 static void 583 filt_aedrdetach(struct knote *kn) 584 { 585 int s; 586 587 s = spladb(); 588 SLIST_REMOVE(&aed_sc->sc_selinfo.sel_klist, kn, knote, kn_selnext); 589 splx(s); 590 } 591 592 static int 593 filt_aedread(struct knote *kn, long hint) 594 { 595 596 kn->kn_data = aed_sc->sc_evq_len * sizeof(adb_event_t); 597 return (kn->kn_data > 0); 598 } 599 600 static const struct filterops aedread_filtops = 601 { 1, NULL, filt_aedrdetach, filt_aedread }; 602 603 static const struct filterops aed_seltrue_filtops = 604 { 1, NULL, filt_aedrdetach, filt_seltrue }; 605 606 int 607 aedkqfilter(dev_t dev, struct knote *kn) 608 { 609 struct klist *klist; 610 int s; 611 612 switch (kn->kn_filter) { 613 case EVFILT_READ: 614 klist = &aed_sc->sc_selinfo.sel_klist; 615 kn->kn_fop = &aedread_filtops; 616 break; 617 618 case EVFILT_WRITE: 619 klist = &aed_sc->sc_selinfo.sel_klist; 620 kn->kn_fop = &aed_seltrue_filtops; 621 break; 622 623 default: 624 return (1); 625 } 626 627 kn->kn_hook = NULL; 628 629 s = spladb(); 630 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 631 splx(s); 632 633 return (0); 634 } 635