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