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