1 /* $NetBSD: aed.c,v 1.14 2002/10/02 05:36:37 thorpej 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bradley A. Grantham. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "opt_adb.h" 34 35 #include <sys/param.h> 36 #include <sys/device.h> 37 #include <sys/fcntl.h> 38 #include <sys/poll.h> 39 #include <sys/select.h> 40 #include <sys/proc.h> 41 #include <sys/signalvar.h> 42 #include <sys/systm.h> 43 #include <sys/conf.h> 44 45 #include <machine/autoconf.h> 46 #include <machine/cpu.h> 47 #include <machine/keyboard.h> 48 49 #include <mac68k/mac68k/macrom.h> 50 #include <mac68k/dev/adbvar.h> 51 #include <mac68k/dev/aedvar.h> 52 #include <mac68k/dev/akbdvar.h> 53 54 /* 55 * Function declarations. 56 */ 57 static int aedmatch __P((struct device *, struct cfdata *, void *)); 58 static void aedattach __P((struct device *, struct device *, void *)); 59 static void aed_emulate_mouse __P((adb_event_t *event)); 60 static void aed_kbdrpt __P((void *kstate)); 61 static void aed_dokeyupdown __P((adb_event_t *event)); 62 static void aed_handoff __P((adb_event_t *event)); 63 static void aed_enqevent __P((adb_event_t *event)); 64 65 /* 66 * Local variables. 67 */ 68 static struct aed_softc *aed_sc = NULL; 69 static int aed_options = 0 | AED_MSEMUL; 70 71 /* Driver definition */ 72 CFATTACH_DECL(aed, sizeof(struct aed_softc), 73 aedmatch, aedattach, NULL, NULL); 74 75 extern struct cfdriver aed_cd; 76 77 dev_type_open(aedopen); 78 dev_type_close(aedclose); 79 dev_type_read(aedread); 80 dev_type_ioctl(aedioctl); 81 dev_type_poll(aedpoll); 82 83 const struct cdevsw aed_cdevsw = { 84 aedopen, aedclose, aedread, nullwrite, aedioctl, 85 nostop, notty, aedpoll, nommap, 86 }; 87 88 static int 89 aedmatch(parent, cf, aux) 90 struct device *parent; 91 struct cfdata *cf; 92 void *aux; 93 { 94 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 95 static int aed_matched = 0; 96 97 /* Allow only one instance. */ 98 if ((aa_args->origaddr == 0) && (!aed_matched)) { 99 aed_matched = 1; 100 return (1); 101 } else 102 return (0); 103 } 104 105 static void 106 aedattach(parent, self, aux) 107 struct device *parent, *self; 108 void *aux; 109 { 110 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 111 struct aed_softc *sc = (struct aed_softc *)self; 112 113 callout_init(&sc->sc_repeat_ch); 114 115 sc->origaddr = aa_args->origaddr; 116 sc->adbaddr = aa_args->adbaddr; 117 sc->handler_id = aa_args->handler_id; 118 119 sc->sc_evq_tail = 0; 120 sc->sc_evq_len = 0; 121 122 sc->sc_rptdelay = 20; 123 sc->sc_rptinterval = 6; 124 sc->sc_repeating = -1; /* not repeating */ 125 126 /* Pull in the options flags. */ 127 sc->sc_options = (sc->sc_dev.dv_cfdata->cf_flags | aed_options); 128 129 sc->sc_ioproc = NULL; 130 131 sc->sc_buttons = 0; 132 133 sc->sc_open = 0; 134 135 aed_sc = sc; 136 137 printf("ADB Event device\n"); 138 139 return; 140 } 141 142 /* 143 * Given a keyboard ADB event, record the keycode and call the key 144 * repeat handler, optionally passing the event through the mouse 145 * button emulation handler first. Pass mouse events directly to 146 * the handoff function. 147 */ 148 int 149 aed_input(event) 150 adb_event_t *event; 151 { 152 adb_event_t new_event = *event; 153 int rv = aed_sc->sc_open; 154 155 switch (event->def_addr) { 156 case ADBADDR_KBD: 157 if (aed_sc->sc_options & AED_MSEMUL) 158 aed_emulate_mouse(&new_event); 159 else 160 aed_dokeyupdown(&new_event); 161 break; 162 case ADBADDR_MS: 163 new_event.u.m.buttons |= aed_sc->sc_buttons; 164 aed_handoff(&new_event); 165 break; 166 default: /* God only knows. */ 167 #ifdef DIAGNOSTIC 168 panic("aed: received event from unsupported device!"); 169 #endif 170 rv = 0; 171 break; 172 } 173 174 return (rv); 175 } 176 177 /* 178 * Handles mouse button emulation via the keyboard. If the emulation 179 * modifier key is down, left and right arrows will generate 2nd and 180 * 3rd mouse button events while the 1, 2, and 3 keys will generate 181 * the corresponding mouse button event. 182 */ 183 static void 184 aed_emulate_mouse(event) 185 adb_event_t *event; 186 { 187 static int emulmodkey_down = 0; 188 adb_event_t new_event; 189 190 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) { 191 emulmodkey_down = 1; 192 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) { 193 /* key up */ 194 emulmodkey_down = 0; 195 if (aed_sc->sc_buttons & 0xfe) { 196 aed_sc->sc_buttons &= 1; 197 new_event.def_addr = ADBADDR_MS; 198 new_event.u.m.buttons = aed_sc->sc_buttons; 199 new_event.u.m.dx = new_event.u.m.dy = 0; 200 microtime(&new_event.timestamp); 201 aed_handoff(&new_event); 202 } 203 } else if (emulmodkey_down) { 204 switch(event->u.k.key) { 205 #ifdef ALTXBUTTONS 206 case ADBK_KEYDOWN(ADBK_1): 207 aed_sc->sc_buttons |= 1; /* left down */ 208 new_event.def_addr = ADBADDR_MS; 209 new_event.u.m.buttons = aed_sc->sc_buttons; 210 new_event.u.m.dx = new_event.u.m.dy = 0; 211 microtime(&new_event.timestamp); 212 aed_handoff(&new_event); 213 break; 214 case ADBK_KEYUP(ADBK_1): 215 aed_sc->sc_buttons &= ~1; /* left up */ 216 new_event.def_addr = ADBADDR_MS; 217 new_event.u.m.buttons = aed_sc->sc_buttons; 218 new_event.u.m.dx = new_event.u.m.dy = 0; 219 microtime(&new_event.timestamp); 220 aed_handoff(&new_event); 221 break; 222 #endif 223 case ADBK_KEYDOWN(ADBK_LEFT): 224 #ifdef ALTXBUTTONS 225 case ADBK_KEYDOWN(ADBK_2): 226 #endif 227 aed_sc->sc_buttons |= 2; /* middle down */ 228 new_event.def_addr = ADBADDR_MS; 229 new_event.u.m.buttons = aed_sc->sc_buttons; 230 new_event.u.m.dx = new_event.u.m.dy = 0; 231 microtime(&new_event.timestamp); 232 aed_handoff(&new_event); 233 break; 234 case ADBK_KEYUP(ADBK_LEFT): 235 #ifdef ALTXBUTTONS 236 case ADBK_KEYUP(ADBK_2): 237 #endif 238 aed_sc->sc_buttons &= ~2; /* middle up */ 239 new_event.def_addr = ADBADDR_MS; 240 new_event.u.m.buttons = aed_sc->sc_buttons; 241 new_event.u.m.dx = new_event.u.m.dy = 0; 242 microtime(&new_event.timestamp); 243 aed_handoff(&new_event); 244 break; 245 case ADBK_KEYDOWN(ADBK_RIGHT): 246 #ifdef ALTXBUTTONS 247 case ADBK_KEYDOWN(ADBK_3): 248 #endif 249 aed_sc->sc_buttons |= 4; /* right down */ 250 new_event.def_addr = ADBADDR_MS; 251 new_event.u.m.buttons = aed_sc->sc_buttons; 252 new_event.u.m.dx = new_event.u.m.dy = 0; 253 microtime(&new_event.timestamp); 254 aed_handoff(&new_event); 255 break; 256 case ADBK_KEYUP(ADBK_RIGHT): 257 #ifdef ALTXBUTTONS 258 case ADBK_KEYUP(ADBK_3): 259 #endif 260 aed_sc->sc_buttons &= ~4; /* right up */ 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_SHIFT): 268 case ADBK_KEYDOWN(ADBK_SHIFT): 269 case ADBK_KEYUP(ADBK_CONTROL): 270 case ADBK_KEYDOWN(ADBK_CONTROL): 271 case ADBK_KEYUP(ADBK_FLOWER): 272 case ADBK_KEYDOWN(ADBK_FLOWER): 273 /* ctrl, shift, cmd */ 274 aed_dokeyupdown(event); 275 break; 276 default: 277 if (event->u.k.key & 0x80) 278 /* ignore keyup */ 279 break; 280 281 /* key down */ 282 new_event = *event; 283 284 /* send option-down */ 285 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION); 286 new_event.bytes[0] = new_event.u.k.key; 287 microtime(&new_event.timestamp); 288 aed_dokeyupdown(&new_event); 289 290 /* send key-down */ 291 new_event.u.k.key = event->bytes[0]; 292 new_event.bytes[0] = new_event.u.k.key; 293 microtime(&new_event.timestamp); 294 aed_dokeyupdown(&new_event); 295 296 /* send key-up */ 297 new_event.u.k.key = 298 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0])); 299 microtime(&new_event.timestamp); 300 new_event.bytes[0] = new_event.u.k.key; 301 aed_dokeyupdown(&new_event); 302 303 /* send option-up */ 304 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION); 305 new_event.bytes[0] = new_event.u.k.key; 306 microtime(&new_event.timestamp); 307 aed_dokeyupdown(&new_event); 308 break; 309 } 310 } else { 311 aed_dokeyupdown(event); 312 } 313 } 314 315 /* 316 * Keyboard autorepeat timeout function. Sends key up/down events 317 * for the repeating key and schedules the next call at sc_rptinterval 318 * ticks in the future. 319 */ 320 static void 321 aed_kbdrpt(kstate) 322 void *kstate; 323 { 324 struct aed_softc *aed_sc = (struct aed_softc *)kstate; 325 326 aed_sc->sc_rptevent.bytes[0] |= 0x80; 327 microtime(&aed_sc->sc_rptevent.timestamp); 328 aed_handoff(&aed_sc->sc_rptevent); /* do key up */ 329 330 aed_sc->sc_rptevent.bytes[0] &= 0x7f; 331 microtime(&aed_sc->sc_rptevent.timestamp); 332 aed_handoff(&aed_sc->sc_rptevent); /* do key down */ 333 334 if (aed_sc->sc_repeating == aed_sc->sc_rptevent.u.k.key) { 335 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptinterval, 336 aed_kbdrpt, kstate); 337 } 338 } 339 340 341 /* 342 * Cancels the currently repeating key event if there is one, schedules 343 * a new repeating key event if needed, and hands the event off to the 344 * appropriate subsystem. 345 */ 346 static void 347 aed_dokeyupdown(event) 348 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(event) 378 adb_event_t *event; 379 { 380 if (aed_sc->sc_open && !adb_polling) 381 aed_enqevent(event); 382 } 383 384 /* 385 * Place the event in the event queue and wakeup any waiting processes. 386 */ 387 static void 388 aed_enqevent(event) 389 adb_event_t *event; 390 { 391 int s; 392 393 s = spladb(); 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 selwakeup(&aed_sc->sc_selinfo); 412 if (aed_sc->sc_ioproc) 413 psignal(aed_sc->sc_ioproc, SIGIO); 414 415 splx(s); 416 } 417 418 int 419 aedopen(dev, flag, mode, p) 420 dev_t dev; 421 int flag, mode; 422 struct proc *p; 423 { 424 int unit; 425 int error = 0; 426 int s; 427 428 unit = minor(dev); 429 430 if (unit != 0) 431 return (ENXIO); 432 433 s = spladb(); 434 if (aed_sc->sc_open) { 435 splx(s); 436 return (EBUSY); 437 } 438 aed_sc->sc_evq_tail = 0; 439 aed_sc->sc_evq_len = 0; 440 aed_sc->sc_open = 1; 441 aed_sc->sc_ioproc = p; 442 splx(s); 443 444 return (error); 445 } 446 447 448 int 449 aedclose(dev, flag, mode, p) 450 dev_t dev; 451 int flag, mode; 452 struct proc *p; 453 { 454 int s = spladb(); 455 456 aed_sc->sc_open = 0; 457 aed_sc->sc_ioproc = NULL; 458 splx(s); 459 460 return (0); 461 } 462 463 464 int 465 aedread(dev, uio, flag) 466 dev_t dev; 467 struct uio *uio; 468 int flag; 469 { 470 int s, error; 471 int willfit; 472 int total; 473 int firstmove; 474 int moremove; 475 476 if (uio->uio_resid < sizeof(adb_event_t)) 477 return (EMSGSIZE); /* close enough. */ 478 479 s = spladb(); 480 if (aed_sc->sc_evq_len == 0) { 481 splx(s); 482 return (0); 483 } 484 willfit = howmany(uio->uio_resid, sizeof(adb_event_t)); 485 total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit; 486 487 firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS) 488 ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total; 489 490 error = uiomove((caddr_t) & aed_sc->sc_evq[aed_sc->sc_evq_tail], 491 firstmove * sizeof(adb_event_t), uio); 492 if (error) { 493 splx(s); 494 return (error); 495 } 496 moremove = total - firstmove; 497 498 if (moremove > 0) { 499 error = uiomove((caddr_t) & aed_sc->sc_evq[0], 500 moremove * sizeof(adb_event_t), uio); 501 if (error) { 502 splx(s); 503 return (error); 504 } 505 } 506 aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS; 507 aed_sc->sc_evq_len -= total; 508 splx(s); 509 return (0); 510 } 511 512 int 513 aedioctl(dev, cmd, data, flag, p) 514 dev_t dev; 515 u_long cmd; 516 caddr_t data; 517 int flag; 518 struct proc *p; 519 { 520 switch (cmd) { 521 case ADBIOC_DEVSINFO: { 522 adb_devinfo_t *di; 523 ADBDataBlock adbdata; 524 int totaldevs; 525 int adbaddr; 526 int i; 527 528 di = (void *)data; 529 530 /* Initialize to no devices */ 531 for (i = 0; i < 16; i++) 532 di->dev[i].addr = -1; 533 534 totaldevs = CountADBs(); 535 for (i = 1; i <= totaldevs; i++) { 536 adbaddr = GetIndADB(&adbdata, i); 537 di->dev[adbaddr].addr = adbaddr; 538 di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr); 539 di->dev[adbaddr].handler_id = (int)(adbdata.devType); 540 } 541 542 /* Must call ADB Manager to get devices now */ 543 break; 544 } 545 546 case ADBIOC_GETREPEAT:{ 547 adb_rptinfo_t *ri; 548 549 ri = (void *)data; 550 ri->delay_ticks = aed_sc->sc_rptdelay; 551 ri->interval_ticks = aed_sc->sc_rptinterval; 552 break; 553 } 554 555 case ADBIOC_SETREPEAT:{ 556 adb_rptinfo_t *ri; 557 558 ri = (void *) data; 559 aed_sc->sc_rptdelay = ri->delay_ticks; 560 aed_sc->sc_rptinterval = ri->interval_ticks; 561 break; 562 } 563 564 case ADBIOC_RESET: 565 /* Do nothing for now */ 566 break; 567 568 case ADBIOC_LISTENCMD:{ 569 adb_listencmd_t *lc; 570 571 lc = (void *)data; 572 } 573 574 default: 575 return (EINVAL); 576 } 577 return (0); 578 } 579 580 581 int 582 aedpoll(dev, events, p) 583 dev_t dev; 584 int events; 585 struct proc *p; 586 { 587 int s, revents; 588 589 revents = events & (POLLOUT | POLLWRNORM); 590 591 if ((events & (POLLIN | POLLRDNORM)) == 0) 592 return (revents); 593 594 s = spladb(); 595 if (aed_sc->sc_evq_len > 0) 596 revents |= events & (POLLIN | POLLRDNORM); 597 else 598 selrecord(p, &aed_sc->sc_selinfo); 599 splx(s); 600 601 return (revents); 602 } 603