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