1 /* $NetBSD: aed.c,v 1.40 2024/09/14 20:59:45 nat Exp $ */ 2 3 /* 4 * Copyright (c) 2024 Nathanial Sloss <nathanialsloss@yahoo.com.au> 5 * All rights reserved. 6 * 7 * Copyright (C) 1994 Bradley A. Grantham 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: aed.c,v 1.40 2024/09/14 20:59:45 nat Exp $"); 33 34 #include "opt_adb.h" 35 36 #include <sys/param.h> 37 #include <sys/device.h> 38 #include <sys/fcntl.h> 39 #include <sys/poll.h> 40 #include <sys/select.h> 41 #include <sys/proc.h> 42 #include <sys/signalvar.h> 43 #include <sys/systm.h> 44 #include <sys/conf.h> 45 46 #include <machine/autoconf.h> 47 #include <machine/cpu.h> 48 #include <machine/keyboard.h> 49 50 #include <mac68k/mac68k/macrom.h> 51 #include <mac68k/dev/adbvar.h> 52 #include <mac68k/dev/aedvar.h> 53 #include <mac68k/dev/akbdvar.h> 54 #include <mac68k/dev/pm_direct.h> 55 56 #define BRIGHTNESS_MAX 31 57 #define BRIGHTNESS_MIN 0 58 #define BRIGHTNESS_STEP 4 59 60 /* 61 * Function declarations. 62 */ 63 static int aedmatch(device_t, cfdata_t, void *); 64 static void aedattach(device_t, device_t, void *); 65 static void aed_emulate_mouse(adb_event_t *); 66 static void aed_kbdrpt(void *); 67 static void aed_dokeyupdown(adb_event_t *); 68 static void aed_handoff(adb_event_t *); 69 static void aed_enqevent(adb_event_t *); 70 71 static void aed_brightness_down(device_t); 72 static void aed_brightness_up(device_t); 73 74 /* 75 * Local variables. 76 */ 77 static struct aed_softc *aed_sc; 78 static int aed_options = 0 | AED_MSEMUL; 79 static int brightness = BRIGHTNESS_MAX; 80 81 /* Driver definition */ 82 CFATTACH_DECL_NEW(aed, sizeof(struct aed_softc), 83 aedmatch, aedattach, NULL, NULL); 84 85 extern struct cfdriver aed_cd; 86 87 dev_type_open(aedopen); 88 dev_type_close(aedclose); 89 dev_type_read(aedread); 90 dev_type_ioctl(aedioctl); 91 dev_type_poll(aedpoll); 92 dev_type_kqfilter(aedkqfilter); 93 94 const struct cdevsw aed_cdevsw = { 95 .d_open = aedopen, 96 .d_close = aedclose, 97 .d_read = aedread, 98 .d_write = nullwrite, 99 .d_ioctl = aedioctl, 100 .d_stop = nostop, 101 .d_tty = notty, 102 .d_poll = aedpoll, 103 .d_mmap = nommap, 104 .d_kqfilter = aedkqfilter, 105 .d_discard = nodiscard, 106 .d_flag = 0 107 }; 108 109 static int 110 aedmatch(device_t parent, cfdata_t cf, void *aux) 111 { 112 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 113 static int aed_matched; 114 115 /* Allow only one instance. */ 116 if ((aa_args->origaddr == 0) && (!aed_matched)) { 117 aed_matched = 1; 118 return (1); 119 } else 120 return (0); 121 } 122 123 static void 124 aedattach(device_t parent, device_t self, void *aux) 125 { 126 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 127 struct aed_softc *sc = device_private(self); 128 129 callout_init(&sc->sc_repeat_ch, 0); 130 selinit(&sc->sc_selinfo); 131 132 sc->origaddr = aa_args->origaddr; 133 sc->adbaddr = aa_args->adbaddr; 134 sc->handler_id = aa_args->handler_id; 135 136 sc->sc_evq_tail = 0; 137 sc->sc_evq_len = 0; 138 139 sc->sc_rptdelay = 20; 140 sc->sc_rptinterval = 6; 141 sc->sc_repeating = -1; /* not repeating */ 142 143 /* Pull in the options flags. */ 144 sc->sc_options = (device_cfdata(self)->cf_flags | aed_options); 145 146 sc->sc_ioproc = NULL; 147 148 sc->sc_buttons = 0; 149 150 sc->sc_open = 0; 151 152 aed_sc = sc; 153 154 pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, 155 aed_brightness_up, TRUE); 156 pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, 157 aed_brightness_down, TRUE); 158 159 printf("ADB Event device\n"); 160 161 return; 162 } 163 164 /* 165 * Given a keyboard ADB event, record the keycode and call the key 166 * repeat handler, optionally passing the event through the mouse 167 * button emulation handler first. Pass mouse events directly to 168 * the handoff function. 169 */ 170 int 171 aed_input(adb_event_t *event) 172 { 173 adb_event_t new_event = *event; 174 int rv = aed_sc->sc_open; 175 176 switch (event->def_addr) { 177 case ADBADDR_KBD: 178 if (aed_sc->sc_options & AED_MSEMUL) 179 aed_emulate_mouse(&new_event); 180 else 181 aed_dokeyupdown(&new_event); 182 break; 183 case ADBADDR_MS: 184 event->u.m.buttons |= aed_sc->sc_buttons; 185 new_event.u.m.buttons |= aed_sc->sc_buttons; 186 aed_handoff(&new_event); 187 break; 188 default: /* God only knows. */ 189 #ifdef DIAGNOSTIC 190 panic("aed: received event from unsupported device!"); 191 #endif 192 rv = 0; 193 break; 194 } 195 196 return (rv); 197 } 198 199 /* 200 * Handles mouse button emulation via the keyboard. If the emulation 201 * modifier key is down, left and right arrows will generate 2nd and 202 * 3rd mouse button events while the 1, 2, and 3 keys will generate 203 * the corresponding mouse button event. 204 */ 205 static void 206 aed_emulate_mouse(adb_event_t *event) 207 { 208 static int emulmodkey_down; 209 adb_event_t new_event; 210 211 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) { 212 emulmodkey_down = 1; 213 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) { 214 /* key up */ 215 emulmodkey_down = 0; 216 if (aed_sc->sc_buttons & 0xfe) { 217 aed_sc->sc_buttons &= 1; 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 } 224 } else if (emulmodkey_down) { 225 switch(event->u.k.key) { 226 #ifdef ALTXBUTTONS 227 case ADBK_KEYDOWN(ADBK_1): 228 aed_sc->sc_buttons |= 1; /* left down */ 229 new_event.def_addr = ADBADDR_MS; 230 new_event.u.m.buttons = aed_sc->sc_buttons; 231 new_event.u.m.dx = new_event.u.m.dy = 0; 232 microtime(&new_event.timestamp); 233 aed_handoff(&new_event); 234 break; 235 case ADBK_KEYUP(ADBK_1): 236 aed_sc->sc_buttons &= ~1; /* left up */ 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 #endif 244 case ADBK_KEYDOWN(ADBK_LEFT): 245 #ifdef ALTXBUTTONS 246 case ADBK_KEYDOWN(ADBK_2): 247 #endif 248 aed_sc->sc_buttons |= 2; /* middle down */ 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_KEYUP(ADBK_LEFT): 256 #ifdef ALTXBUTTONS 257 case ADBK_KEYUP(ADBK_2): 258 #endif 259 aed_sc->sc_buttons &= ~2; /* middle up */ 260 new_event.def_addr = ADBADDR_MS; 261 new_event.u.m.buttons = aed_sc->sc_buttons; 262 new_event.u.m.dx = new_event.u.m.dy = 0; 263 microtime(&new_event.timestamp); 264 aed_handoff(&new_event); 265 break; 266 case ADBK_KEYDOWN(ADBK_RIGHT): 267 #ifdef ALTXBUTTONS 268 case ADBK_KEYDOWN(ADBK_3): 269 #endif 270 aed_sc->sc_buttons |= 4; /* right down */ 271 new_event.def_addr = ADBADDR_MS; 272 new_event.u.m.buttons = aed_sc->sc_buttons; 273 new_event.u.m.dx = new_event.u.m.dy = 0; 274 microtime(&new_event.timestamp); 275 aed_handoff(&new_event); 276 break; 277 case ADBK_KEYUP(ADBK_RIGHT): 278 #ifdef ALTXBUTTONS 279 case ADBK_KEYUP(ADBK_3): 280 #endif 281 aed_sc->sc_buttons &= ~4; /* right up */ 282 new_event.def_addr = ADBADDR_MS; 283 new_event.u.m.buttons = aed_sc->sc_buttons; 284 new_event.u.m.dx = new_event.u.m.dy = 0; 285 microtime(&new_event.timestamp); 286 aed_handoff(&new_event); 287 break; 288 case ADBK_KEYUP(ADBK_UP): 289 pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP); 290 break; 291 case ADBK_KEYUP(ADBK_DOWN): 292 pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN); 293 break; 294 case ADBK_KEYUP(ADBK_SHIFT): 295 case ADBK_KEYDOWN(ADBK_SHIFT): 296 case ADBK_KEYUP(ADBK_CONTROL): 297 case ADBK_KEYDOWN(ADBK_CONTROL): 298 case ADBK_KEYUP(ADBK_FLOWER): 299 case ADBK_KEYDOWN(ADBK_FLOWER): 300 /* ctrl, shift, cmd */ 301 aed_dokeyupdown(event); 302 break; 303 default: 304 if (event->u.k.key & 0x80) 305 /* ignore keyup */ 306 break; 307 308 /* key down */ 309 new_event = *event; 310 311 /* send option-down */ 312 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION); 313 new_event.bytes[0] = new_event.u.k.key; 314 microtime(&new_event.timestamp); 315 aed_dokeyupdown(&new_event); 316 317 /* send key-down */ 318 new_event.u.k.key = event->bytes[0]; 319 new_event.bytes[0] = new_event.u.k.key; 320 microtime(&new_event.timestamp); 321 aed_dokeyupdown(&new_event); 322 323 /* send key-up */ 324 new_event.u.k.key = 325 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0])); 326 microtime(&new_event.timestamp); 327 new_event.bytes[0] = new_event.u.k.key; 328 aed_dokeyupdown(&new_event); 329 330 /* send option-up */ 331 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION); 332 new_event.bytes[0] = new_event.u.k.key; 333 microtime(&new_event.timestamp); 334 aed_dokeyupdown(&new_event); 335 break; 336 } 337 } else { 338 aed_dokeyupdown(event); 339 } 340 } 341 342 /* 343 * Keyboard autorepeat timeout function. Sends key up/down events 344 * for the repeating key and schedules the next call at sc_rptinterval 345 * ticks in the future. 346 */ 347 static void 348 aed_kbdrpt(void *kstate) 349 { 350 struct aed_softc *sc = (struct aed_softc *)kstate; 351 352 sc->sc_rptevent.bytes[0] |= 0x80; 353 microtime(&sc->sc_rptevent.timestamp); 354 aed_handoff(&sc->sc_rptevent); /* do key up */ 355 356 sc->sc_rptevent.bytes[0] &= 0x7f; 357 microtime(&sc->sc_rptevent.timestamp); 358 aed_handoff(&sc->sc_rptevent); /* do key down */ 359 360 if (sc->sc_repeating == sc->sc_rptevent.u.k.key) { 361 callout_reset(&sc->sc_repeat_ch, sc->sc_rptinterval, 362 aed_kbdrpt, kstate); 363 } 364 } 365 366 367 /* 368 * Cancels the currently repeating key event if there is one, schedules 369 * a new repeating key event if needed, and hands the event off to the 370 * appropriate subsystem. 371 */ 372 static void 373 aed_dokeyupdown(adb_event_t *event) 374 { 375 int kbd_key; 376 377 kbd_key = ADBK_KEYVAL(event->u.k.key); 378 if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) { 379 /* ignore shift & control */ 380 if (aed_sc->sc_repeating != -1) { 381 callout_stop(&aed_sc->sc_repeat_ch); 382 } 383 aed_sc->sc_rptevent = *event; 384 aed_sc->sc_repeating = kbd_key; 385 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay, 386 aed_kbdrpt, (void *)aed_sc); 387 } else { 388 if (aed_sc->sc_repeating != -1) { 389 aed_sc->sc_repeating = -1; 390 callout_stop(&aed_sc->sc_repeat_ch); 391 } 392 aed_sc->sc_rptevent = *event; 393 } 394 aed_handoff(event); 395 } 396 397 /* 398 * Place the event in the event queue if a requesting device is open 399 * and we are not polling, otherwise, pass it up to the console driver. 400 */ 401 static void 402 aed_handoff(adb_event_t *event) 403 { 404 if (aed_sc->sc_open && !adb_polling) 405 aed_enqevent(event); 406 } 407 408 /* 409 * Place the event in the event queue and wakeup any waiting processes. 410 */ 411 static void 412 aed_enqevent(adb_event_t *event) 413 { 414 int s; 415 416 s = splvm(); 417 418 #ifdef DIAGNOSTIC 419 if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS) 420 panic("adb: event queue tail is out of bounds"); 421 422 if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS) 423 panic("adb: event queue len is out of bounds"); 424 #endif 425 426 if (aed_sc->sc_evq_len == AED_MAX_EVENTS) { 427 splx(s); 428 return; /* Oh, well... */ 429 } 430 aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) % 431 AED_MAX_EVENTS] = *event; 432 aed_sc->sc_evq_len++; 433 434 selnotify(&aed_sc->sc_selinfo, 0, 0); 435 if (aed_sc->sc_ioproc) 436 psignal(aed_sc->sc_ioproc, SIGIO); 437 438 splx(s); 439 } 440 441 int 442 aedopen(dev_t dev, int flag, int mode, struct lwp *l) 443 { 444 struct aed_softc *sc; 445 int s; 446 447 sc = device_lookup_private(&aed_cd, minor(dev)); 448 if (sc == NULL) 449 return (ENXIO); 450 451 s = splvm(); 452 if (sc->sc_open) { 453 splx(s); 454 return (EBUSY); 455 } 456 aed_sc->sc_evq_tail = 0; 457 aed_sc->sc_evq_len = 0; 458 aed_sc->sc_open = 1; 459 aed_sc->sc_ioproc = l->l_proc; 460 splx(s); 461 462 return 0; 463 } 464 465 466 int 467 aedclose(dev_t dev, int flag, int mode, struct lwp *l) 468 { 469 int s; 470 471 s = splvm(); 472 aed_sc->sc_open = 0; 473 aed_sc->sc_ioproc = NULL; 474 splx(s); 475 476 return (0); 477 } 478 479 480 int 481 aedread(dev_t dev, struct uio *uio, int flag) 482 { 483 int s, error; 484 int willfit; 485 int total; 486 int firstmove; 487 int moremove; 488 489 if (uio->uio_resid < sizeof(adb_event_t)) 490 return (EMSGSIZE); /* close enough. */ 491 492 s = splvm(); 493 if (aed_sc->sc_evq_len == 0) { 494 splx(s); 495 return (0); 496 } 497 willfit = howmany(uio->uio_resid, sizeof(adb_event_t)); 498 total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit; 499 500 firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS) 501 ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total; 502 503 error = uiomove((void *) & aed_sc->sc_evq[aed_sc->sc_evq_tail], 504 firstmove * sizeof(adb_event_t), uio); 505 if (error) { 506 splx(s); 507 return (error); 508 } 509 moremove = total - firstmove; 510 511 if (moremove > 0) { 512 error = uiomove((void *) & aed_sc->sc_evq[0], 513 moremove * sizeof(adb_event_t), uio); 514 if (error) { 515 splx(s); 516 return (error); 517 } 518 } 519 aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS; 520 aed_sc->sc_evq_len -= total; 521 splx(s); 522 return (0); 523 } 524 525 int 526 aedioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 527 { 528 switch (cmd) { 529 case ADBIOC_DEVSINFO: { 530 adb_devinfo_t *di; 531 ADBDataBlock adbdata; 532 int totaldevs; 533 int adbaddr; 534 int i; 535 536 di = (void *)data; 537 538 /* Initialize to no devices */ 539 for (i = 0; i < 16; i++) 540 di->dev[i].addr = -1; 541 542 totaldevs = CountADBs(); 543 for (i = 1; i <= totaldevs; i++) { 544 adbaddr = GetIndADB(&adbdata, i); 545 di->dev[adbaddr].addr = adbaddr; 546 di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr); 547 di->dev[adbaddr].handler_id = (int)(adbdata.devType); 548 } 549 550 /* Must call ADB Manager to get devices now */ 551 break; 552 } 553 554 case ADBIOC_GETREPEAT:{ 555 adb_rptinfo_t *ri; 556 557 ri = (void *)data; 558 ri->delay_ticks = aed_sc->sc_rptdelay; 559 ri->interval_ticks = aed_sc->sc_rptinterval; 560 break; 561 } 562 563 case ADBIOC_SETREPEAT:{ 564 adb_rptinfo_t *ri; 565 566 ri = (void *) data; 567 aed_sc->sc_rptdelay = ri->delay_ticks; 568 aed_sc->sc_rptinterval = ri->interval_ticks; 569 break; 570 } 571 572 case ADBIOC_RESET: 573 /* Do nothing for now */ 574 break; 575 576 case ADBIOC_LISTENCMD: 577 /* adb_listencmd_t *lc = data; */ 578 579 default: 580 return (EINVAL); 581 } 582 return (0); 583 } 584 585 586 int 587 aedpoll(dev_t dev, int events, struct lwp *l) 588 { 589 int s, revents; 590 591 revents = events & (POLLOUT | POLLWRNORM); 592 593 if ((events & (POLLIN | POLLRDNORM)) == 0) 594 return (revents); 595 596 s = splvm(); 597 if (aed_sc->sc_evq_len > 0) 598 revents |= events & (POLLIN | POLLRDNORM); 599 else 600 selrecord(l, &aed_sc->sc_selinfo); 601 splx(s); 602 603 return (revents); 604 } 605 606 static void 607 filt_aedrdetach(struct knote *kn) 608 { 609 int s; 610 611 s = splvm(); 612 selremove_knote(&aed_sc->sc_selinfo, kn); 613 splx(s); 614 } 615 616 static int 617 filt_aedread(struct knote *kn, long hint) 618 { 619 620 kn->kn_data = aed_sc->sc_evq_len * sizeof(adb_event_t); 621 return (kn->kn_data > 0); 622 } 623 624 static const struct filterops aedread_filtops = { 625 .f_flags = FILTEROP_ISFD, 626 .f_attach = NULL, 627 .f_detach = filt_aedrdetach, 628 .f_event = filt_aedread, 629 }; 630 631 int 632 aedkqfilter(dev_t dev, struct knote *kn) 633 { 634 int s; 635 636 switch (kn->kn_filter) { 637 case EVFILT_READ: 638 kn->kn_fop = &aedread_filtops; 639 s = splvm(); 640 selrecord_knote(&aed_sc->sc_selinfo, kn); 641 splx(s); 642 break; 643 644 case EVFILT_WRITE: 645 kn->kn_fop = &seltrue_filtops; 646 break; 647 648 default: 649 return (EINVAL); 650 } 651 652 return (0); 653 } 654 655 static void 656 aed_brightness_down(device_t dev) 657 { 658 int level, step; 659 660 level = brightness; 661 if (level <= 4) /* logarithmic brightness curve. */ 662 step = 1; 663 else 664 step = BRIGHTNESS_STEP; 665 666 level = uimax(BRIGHTNESS_MIN, level - step); 667 brightness = pm_set_brightness(level); 668 } 669 670 static void 671 aed_brightness_up(device_t dev) 672 { 673 int level, step; 674 675 level = brightness; 676 if (level <= 4) /* logarithmic brightness curve. */ 677 step = 1; 678 else 679 step = BRIGHTNESS_STEP; 680 681 level = uimin(BRIGHTNESS_MAX, level + step); 682 brightness = pm_set_brightness(level); 683 } 684