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