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