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