1 /* $NetBSD: aed.c,v 1.35 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.35 2024/06/05 11:01:47 nat 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 void 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 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 void 190 aed_emulate_mouse(adb_event_t *event) 191 { 192 static int emulmodkey_down = 0; 193 adb_event_t new_event; 194 195 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) { 196 emulmodkey_down = 1; 197 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) { 198 /* key up */ 199 emulmodkey_down = 0; 200 if (aed_sc->sc_buttons & 0xfe) { 201 aed_sc->sc_buttons &= 1; 202 new_event.def_addr = ADBADDR_MS; 203 new_event.u.m.buttons = aed_sc->sc_buttons; 204 new_event.u.m.dx = new_event.u.m.dy = 0; 205 microtime(&new_event.timestamp); 206 aed_handoff(&new_event); 207 } 208 } else if (emulmodkey_down) { 209 switch(event->u.k.key) { 210 #ifdef ALTXBUTTONS 211 case ADBK_KEYDOWN(ADBK_1): 212 aed_sc->sc_buttons |= 1; /* left down */ 213 new_event.def_addr = ADBADDR_MS; 214 new_event.u.m.buttons = aed_sc->sc_buttons; 215 new_event.u.m.dx = new_event.u.m.dy = 0; 216 microtime(&new_event.timestamp); 217 aed_handoff(&new_event); 218 break; 219 case ADBK_KEYUP(ADBK_1): 220 aed_sc->sc_buttons &= ~1; /* left up */ 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 #endif 228 case ADBK_KEYDOWN(ADBK_LEFT): 229 #ifdef ALTXBUTTONS 230 case ADBK_KEYDOWN(ADBK_2): 231 #endif 232 aed_sc->sc_buttons |= 2; /* middle down */ 233 new_event.def_addr = ADBADDR_MS; 234 new_event.u.m.buttons = aed_sc->sc_buttons; 235 new_event.u.m.dx = new_event.u.m.dy = 0; 236 microtime(&new_event.timestamp); 237 aed_handoff(&new_event); 238 break; 239 case ADBK_KEYUP(ADBK_LEFT): 240 #ifdef ALTXBUTTONS 241 case ADBK_KEYUP(ADBK_2): 242 #endif 243 aed_sc->sc_buttons &= ~2; /* middle up */ 244 new_event.def_addr = ADBADDR_MS; 245 new_event.u.m.buttons = aed_sc->sc_buttons; 246 new_event.u.m.dx = new_event.u.m.dy = 0; 247 microtime(&new_event.timestamp); 248 aed_handoff(&new_event); 249 break; 250 case ADBK_KEYDOWN(ADBK_RIGHT): 251 #ifdef ALTXBUTTONS 252 case ADBK_KEYDOWN(ADBK_3): 253 #endif 254 aed_sc->sc_buttons |= 4; /* right down */ 255 new_event.def_addr = ADBADDR_MS; 256 new_event.u.m.buttons = aed_sc->sc_buttons; 257 new_event.u.m.dx = new_event.u.m.dy = 0; 258 microtime(&new_event.timestamp); 259 aed_handoff(&new_event); 260 break; 261 case ADBK_KEYUP(ADBK_RIGHT): 262 #ifdef ALTXBUTTONS 263 case ADBK_KEYUP(ADBK_3): 264 #endif 265 aed_sc->sc_buttons &= ~4; /* right up */ 266 new_event.def_addr = ADBADDR_MS; 267 new_event.u.m.buttons = aed_sc->sc_buttons; 268 new_event.u.m.dx = new_event.u.m.dy = 0; 269 microtime(&new_event.timestamp); 270 aed_handoff(&new_event); 271 break; 272 case ADBK_KEYUP(ADBK_SHIFT): 273 case ADBK_KEYDOWN(ADBK_SHIFT): 274 case ADBK_KEYUP(ADBK_CONTROL): 275 case ADBK_KEYDOWN(ADBK_CONTROL): 276 case ADBK_KEYUP(ADBK_FLOWER): 277 case ADBK_KEYDOWN(ADBK_FLOWER): 278 /* ctrl, shift, cmd */ 279 aed_dokeyupdown(event); 280 break; 281 default: 282 if (event->u.k.key & 0x80) 283 /* ignore keyup */ 284 break; 285 286 /* key down */ 287 new_event = *event; 288 289 /* send option-down */ 290 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION); 291 new_event.bytes[0] = new_event.u.k.key; 292 microtime(&new_event.timestamp); 293 aed_dokeyupdown(&new_event); 294 295 /* send key-down */ 296 new_event.u.k.key = event->bytes[0]; 297 new_event.bytes[0] = new_event.u.k.key; 298 microtime(&new_event.timestamp); 299 aed_dokeyupdown(&new_event); 300 301 /* send key-up */ 302 new_event.u.k.key = 303 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0])); 304 microtime(&new_event.timestamp); 305 new_event.bytes[0] = new_event.u.k.key; 306 aed_dokeyupdown(&new_event); 307 308 /* send option-up */ 309 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION); 310 new_event.bytes[0] = new_event.u.k.key; 311 microtime(&new_event.timestamp); 312 aed_dokeyupdown(&new_event); 313 break; 314 } 315 } else { 316 aed_dokeyupdown(event); 317 } 318 } 319 320 /* 321 * Keyboard autorepeat timeout function. Sends key up/down events 322 * for the repeating key and schedules the next call at sc_rptinterval 323 * ticks in the future. 324 */ 325 static void 326 aed_kbdrpt(void *kstate) 327 { 328 struct aed_softc *sc = (struct aed_softc *)kstate; 329 330 sc->sc_rptevent.bytes[0] |= 0x80; 331 microtime(&sc->sc_rptevent.timestamp); 332 aed_handoff(&sc->sc_rptevent); /* do key up */ 333 334 sc->sc_rptevent.bytes[0] &= 0x7f; 335 microtime(&sc->sc_rptevent.timestamp); 336 aed_handoff(&sc->sc_rptevent); /* do key down */ 337 338 if (sc->sc_repeating == sc->sc_rptevent.u.k.key) { 339 callout_reset(&sc->sc_repeat_ch, sc->sc_rptinterval, 340 aed_kbdrpt, kstate); 341 } 342 } 343 344 345 /* 346 * Cancels the currently repeating key event if there is one, schedules 347 * a new repeating key event if needed, and hands the event off to the 348 * appropriate subsystem. 349 */ 350 static void 351 aed_dokeyupdown(adb_event_t *event) 352 { 353 int kbd_key; 354 355 kbd_key = ADBK_KEYVAL(event->u.k.key); 356 if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) { 357 /* ignore shift & control */ 358 if (aed_sc->sc_repeating != -1) { 359 callout_stop(&aed_sc->sc_repeat_ch); 360 } 361 aed_sc->sc_rptevent = *event; 362 aed_sc->sc_repeating = kbd_key; 363 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay, 364 aed_kbdrpt, (void *)aed_sc); 365 } else { 366 if (aed_sc->sc_repeating != -1) { 367 aed_sc->sc_repeating = -1; 368 callout_stop(&aed_sc->sc_repeat_ch); 369 } 370 aed_sc->sc_rptevent = *event; 371 } 372 aed_handoff(event); 373 } 374 375 /* 376 * Place the event in the event queue if a requesting device is open 377 * and we are not polling. 378 */ 379 static void 380 aed_handoff(adb_event_t *event) 381 { 382 if (aed_sc->sc_open && !adb_polling) 383 aed_enqevent(event); 384 } 385 386 /* 387 * Place the event in the event queue and wakeup any waiting processes. 388 */ 389 static void 390 aed_enqevent(adb_event_t *event) 391 { 392 int s; 393 394 s = spladb(); 395 396 #ifdef DIAGNOSTIC 397 if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS) 398 panic("adb: event queue tail is out of bounds"); 399 400 if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS) 401 panic("adb: event queue len is out of bounds"); 402 #endif 403 404 if (aed_sc->sc_evq_len == AED_MAX_EVENTS) { 405 splx(s); 406 return; /* Oh, well... */ 407 } 408 aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) % 409 AED_MAX_EVENTS] = *event; 410 aed_sc->sc_evq_len++; 411 412 selnotify(&aed_sc->sc_selinfo, 0, 0); 413 if (aed_sc->sc_ioproc) 414 psignal(aed_sc->sc_ioproc, SIGIO); 415 416 splx(s); 417 } 418 419 int 420 aedopen(dev_t dev, int flag, int mode, struct lwp *l) 421 { 422 int unit; 423 int error = 0; 424 int s; 425 426 unit = minor(dev); 427 428 if (unit != 0) 429 return (ENXIO); 430 431 s = spladb(); 432 if (aed_sc->sc_open) { 433 splx(s); 434 return (EBUSY); 435 } 436 aed_sc->sc_evq_tail = 0; 437 aed_sc->sc_evq_len = 0; 438 aed_sc->sc_open = 1; 439 aed_sc->sc_ioproc = l->l_proc; 440 splx(s); 441 442 return (error); 443 } 444 445 446 int 447 aedclose(dev_t dev, int flag, int mode, struct lwp *l) 448 { 449 int s = spladb(); 450 451 aed_sc->sc_open = 0; 452 aed_sc->sc_ioproc = NULL; 453 splx(s); 454 455 return (0); 456 } 457 458 459 int 460 aedread(dev_t dev, struct uio *uio, int flag) 461 { 462 int s, error; 463 int willfit; 464 int total; 465 int firstmove; 466 int moremove; 467 468 if (uio->uio_resid < sizeof(adb_event_t)) 469 return (EMSGSIZE); /* close enough. */ 470 471 s = spladb(); 472 if (aed_sc->sc_evq_len == 0) { 473 splx(s); 474 return (0); 475 } 476 willfit = howmany(uio->uio_resid, sizeof(adb_event_t)); 477 total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit; 478 479 firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS) 480 ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total; 481 482 error = uiomove((void *) & aed_sc->sc_evq[aed_sc->sc_evq_tail], 483 firstmove * sizeof(adb_event_t), uio); 484 if (error) { 485 splx(s); 486 return (error); 487 } 488 moremove = total - firstmove; 489 490 if (moremove > 0) { 491 error = uiomove((void *) & aed_sc->sc_evq[0], 492 moremove * sizeof(adb_event_t), uio); 493 if (error) { 494 splx(s); 495 return (error); 496 } 497 } 498 aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS; 499 aed_sc->sc_evq_len -= total; 500 splx(s); 501 return (0); 502 } 503 504 int 505 aedioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 506 { 507 switch (cmd) { 508 case ADBIOCDEVSINFO: { 509 adb_devinfo_t *di; 510 ADBDataBlock adbdata; 511 int totaldevs; 512 int adbaddr; 513 int i; 514 515 di = (void *)data; 516 517 /* Initialize to no devices */ 518 for (i = 0; i < 16; i++) 519 di->dev[i].addr = -1; 520 521 totaldevs = CountADBs(); 522 for (i = 1; i <= totaldevs; i++) { 523 adbaddr = GetIndADB(&adbdata, i); 524 di->dev[adbaddr].addr = adbaddr; 525 di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr); 526 di->dev[adbaddr].handler_id = (int)(adbdata.devType); 527 } 528 529 /* Must call ADB Manager to get devices now */ 530 break; 531 } 532 533 case ADBIOCGETREPEAT:{ 534 adb_rptinfo_t *ri; 535 536 ri = (void *)data; 537 ri->delay_ticks = aed_sc->sc_rptdelay; 538 ri->interval_ticks = aed_sc->sc_rptinterval; 539 break; 540 } 541 542 case ADBIOCSETREPEAT:{ 543 adb_rptinfo_t *ri; 544 545 ri = (void *) data; 546 aed_sc->sc_rptdelay = ri->delay_ticks; 547 aed_sc->sc_rptinterval = ri->interval_ticks; 548 break; 549 } 550 551 case ADBIOCRESET: 552 /* Do nothing for now */ 553 break; 554 555 case ADBIOCLISTENCMD:{ 556 adb_listencmd_t *lc; 557 558 lc = (void *)data; 559 } 560 561 default: 562 return (EINVAL); 563 } 564 return (0); 565 } 566 567 568 int 569 aedpoll(dev_t dev, int events, struct lwp *l) 570 { 571 int s, revents; 572 573 revents = events & (POLLOUT | POLLWRNORM); 574 575 if ((events & (POLLIN | POLLRDNORM)) == 0) 576 return (revents); 577 578 s = spladb(); 579 if (aed_sc->sc_evq_len > 0) 580 revents |= events & (POLLIN | POLLRDNORM); 581 else 582 selrecord(l, &aed_sc->sc_selinfo); 583 splx(s); 584 585 return (revents); 586 } 587 588 static void 589 filt_aedrdetach(struct knote *kn) 590 { 591 int s; 592 593 s = spladb(); 594 selremove_knote(&aed_sc->sc_selinfo, kn); 595 splx(s); 596 } 597 598 static int 599 filt_aedread(struct knote *kn, long hint) 600 { 601 602 kn->kn_data = aed_sc->sc_evq_len * sizeof(adb_event_t); 603 return (kn->kn_data > 0); 604 } 605 606 static const struct filterops aedread_filtops = { 607 .f_flags = FILTEROP_ISFD, 608 .f_attach = NULL, 609 .f_detach = filt_aedrdetach, 610 .f_event = filt_aedread 611 }; 612 613 int 614 aedkqfilter(dev_t dev, struct knote *kn) 615 { 616 int s; 617 618 switch (kn->kn_filter) { 619 case EVFILT_READ: 620 kn->kn_fop = &aedread_filtops; 621 s = spladb(); 622 selrecord_knote(&aed_sc->sc_selinfo, kn); 623 splx(s); 624 break; 625 626 case EVFILT_WRITE: 627 kn->kn_fop = &seltrue_filtops; 628 break; 629 630 default: 631 return (EINVAL); 632 } 633 634 return (0); 635 } 636