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