1 /* $NetBSD: akbd.c,v 1.16 2003/07/15 02:43:16 lukem Exp $ */ 2 3 /* 4 * Copyright (C) 1998 Colin Wood 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 Colin Wood. 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 <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: akbd.c,v 1.16 2003/07/15 02:43:16 lukem Exp $"); 35 36 #include "opt_adb.h" 37 38 #include <sys/param.h> 39 #include <sys/device.h> 40 #include <sys/fcntl.h> 41 #include <sys/poll.h> 42 #include <sys/select.h> 43 #include <sys/proc.h> 44 #include <sys/signalvar.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 48 #include "aed.h" 49 #include "wskbd.h" 50 51 #include <dev/wscons/wsconsio.h> 52 #include <dev/wscons/wskbdvar.h> 53 #include <dev/wscons/wsksymdef.h> 54 #include <dev/wscons/wsksymvar.h> 55 56 #include <machine/autoconf.h> 57 #include <machine/cpu.h> 58 #define KEYBOARD_ARRAY 59 #include <machine/keyboard.h> 60 #include <machine/viareg.h> 61 62 #include <mac68k/mac68k/macrom.h> 63 #include <mac68k/dev/adbvar.h> 64 #include <mac68k/dev/aedvar.h> 65 #include <mac68k/dev/akbdmap.h> 66 #include <mac68k/dev/akbdvar.h> 67 #include <mac68k/dev/amsvar.h> 68 69 /* 70 * Function declarations. 71 */ 72 static int akbdmatch __P((struct device *, struct cfdata *, void *)); 73 static void akbdattach __P((struct device *, struct device *, void *)); 74 void kbd_adbcomplete __P((caddr_t buffer, caddr_t data_area, int adb_command)); 75 static void kbd_processevent __P((adb_event_t *event, struct akbd_softc *)); 76 #ifdef notyet 77 static u_char getleds __P((int)); 78 static int setleds __P((struct akbd_softc *, u_char)); 79 static void blinkleds __P((struct akbd_softc *)); 80 #endif 81 82 /* 83 * Local variables. 84 */ 85 86 /* Driver definition. */ 87 CFATTACH_DECL(akbd, sizeof(struct akbd_softc), 88 akbdmatch, akbdattach, NULL, NULL); 89 90 extern struct cfdriver akbd_cd; 91 92 int kbd_intr __P((adb_event_t *event, struct akbd_softc *)); 93 int akbd_enable __P((void *, int)); 94 void akbd_set_leds __P((void *, int)); 95 int akbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 96 97 struct wskbd_accessops akbd_accessops = { 98 akbd_enable, 99 akbd_set_leds, 100 akbd_ioctl, 101 }; 102 103 void akbd_cngetc __P((void *, u_int *, int *)); 104 void akbd_cnpollc __P((void *, int)); 105 int akbd_cnattach __P((void)); 106 107 struct wskbd_consops akbd_consops = { 108 akbd_cngetc, 109 akbd_cnpollc, 110 }; 111 112 struct wskbd_mapdata akbd_keymapdata = { 113 akbd_keydesctab, 114 KB_US, 115 }; 116 117 static int akbd_is_console __P((void)); 118 119 static int 120 akbdmatch(parent, cf, aux) 121 struct device *parent; 122 struct cfdata *cf; 123 void *aux; 124 { 125 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 126 127 if (aa_args->origaddr == ADBADDR_KBD) 128 return 1; 129 else 130 return 0; 131 } 132 133 static void 134 akbdattach(parent, self, aux) 135 struct device *parent, *self; 136 void *aux; 137 { 138 ADBSetInfoBlock adbinfo; 139 struct akbd_softc *sc = (struct akbd_softc *)self; 140 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 141 int error, kbd_done; 142 short cmd; 143 u_char buffer[9]; 144 #if NWSKBD > 0 145 struct wskbddev_attach_args a; 146 static int akbd_console_initted = 0; 147 int wskbd_eligible; 148 149 wskbd_eligible = 1; 150 #endif 151 152 sc->origaddr = aa_args->origaddr; 153 sc->adbaddr = aa_args->adbaddr; 154 sc->handler_id = aa_args->handler_id; 155 156 sc->sc_leds = (u_int8_t)0x00; /* initially off */ 157 158 adbinfo.siServiceRtPtr = (Ptr)adb_kbd_asmcomplete; 159 adbinfo.siDataAreaAddr = (caddr_t)sc; 160 161 switch (sc->handler_id) { 162 case ADB_STDKBD: 163 printf("standard keyboard\n"); 164 break; 165 case ADB_ISOKBD: 166 printf("standard keyboard (ISO layout)\n"); 167 break; 168 case ADB_EXTKBD: 169 cmd = ADBTALK(sc->adbaddr, 1); 170 kbd_done = 171 (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) == 0); 172 173 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */ 174 if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) { 175 printf("Mouseman (non-EMP) pseudo keyboard\n"); 176 adbinfo.siServiceRtPtr = (Ptr)0; 177 adbinfo.siDataAreaAddr = (Ptr)0; 178 #if NWSKBD > 0 179 wskbd_eligible = 0; 180 #endif /* NWSKBD > 0 */ 181 } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) { 182 printf("Trackman (non-EMP) pseudo keyboard\n"); 183 adbinfo.siServiceRtPtr = (Ptr)0; 184 adbinfo.siDataAreaAddr = (Ptr)0; 185 #if NWSKBD > 0 186 wskbd_eligible = 0; 187 #endif /* NWSKBD > 0 */ 188 } else { 189 printf("extended keyboard\n"); 190 #ifdef notyet 191 blinkleds(sc); 192 #endif 193 } 194 break; 195 case ADB_EXTISOKBD: 196 printf("extended keyboard (ISO layout)\n"); 197 #ifdef notyet 198 blinkleds(sc); 199 #endif 200 break; 201 case ADB_KBDII: 202 printf("keyboard II\n"); 203 break; 204 case ADB_ISOKBDII: 205 printf("keyboard II (ISO layout)\n"); 206 break; 207 case ADB_PBKBD: 208 printf("PowerBook keyboard\n"); 209 break; 210 case ADB_PBISOKBD: 211 printf("PowerBook keyboard (ISO layout)\n"); 212 break; 213 case ADB_ADJKPD: 214 printf("adjustable keypad\n"); 215 #if NWSKBD > 0 216 wskbd_eligible = 0; 217 #endif /* NWSKBD > 0 */ 218 break; 219 case ADB_ADJKBD: 220 printf("adjustable keyboard\n"); 221 break; 222 case ADB_ADJISOKBD: 223 printf("adjustable keyboard (ISO layout)\n"); 224 break; 225 case ADB_ADJJAPKBD: 226 printf("adjustable keyboard (Japanese layout)\n"); 227 break; 228 case ADB_PBEXTISOKBD: 229 printf("PowerBook extended keyboard (ISO layout)\n"); 230 break; 231 case ADB_PBEXTJAPKBD: 232 printf("PowerBook extended keyboard (Japanese layout)\n"); 233 break; 234 case ADB_JPKBDII: 235 printf("keyboard II (Japanese layout)\n"); 236 break; 237 case ADB_PBEXTKBD: 238 printf("PowerBook extended keyboard\n"); 239 break; 240 case ADB_DESIGNKBD: 241 printf("extended keyboard\n"); 242 #ifdef notyet 243 blinkleds(sc); 244 #endif 245 break; 246 case ADB_PBJPKBD: 247 printf("PowerBook keyboard (Japanese layout)\n"); 248 break; 249 default: 250 printf("mapped device (%d)\n", sc->handler_id); 251 #if NWSKBD > 0 252 wskbd_eligible = 0; 253 #endif /* NWSKBD > 0 */ 254 break; 255 } 256 error = SetADBInfo(&adbinfo, sc->adbaddr); 257 #ifdef ADB_DEBUG 258 if (adb_debug) 259 printf("akbd: returned %d from SetADBInfo\n", error); 260 #endif 261 262 #if NWSKBD > 0 263 if (akbd_is_console() && wskbd_eligible) 264 a.console = (++akbd_console_initted == 1); 265 else 266 a.console = 0; 267 a.keymap = &akbd_keymapdata; 268 a.accessops = &akbd_accessops; 269 a.accesscookie = sc; 270 271 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 272 #endif 273 } 274 275 276 /* 277 * Handle putting the keyboard data received from the ADB into 278 * an ADB event record. 279 */ 280 void 281 kbd_adbcomplete(buffer, data_area, adb_command) 282 caddr_t buffer; 283 caddr_t data_area; 284 int adb_command; 285 { 286 adb_event_t event; 287 struct akbd_softc *ksc; 288 int adbaddr; 289 #ifdef ADB_DEBUG 290 int i; 291 292 if (adb_debug) 293 printf("adb: transaction completion\n"); 294 #endif 295 296 adbaddr = ADB_CMDADDR(adb_command); 297 ksc = (struct akbd_softc *)data_area; 298 299 event.addr = adbaddr; 300 event.hand_id = ksc->handler_id; 301 event.def_addr = ksc->origaddr; 302 event.byte_count = buffer[0]; 303 memcpy(event.bytes, buffer + 1, event.byte_count); 304 305 #ifdef ADB_DEBUG 306 if (adb_debug) { 307 printf("akbd: from %d at %d (org %d) %d:", event.addr, 308 event.hand_id, event.def_addr, buffer[0]); 309 for (i = 1; i <= buffer[0]; i++) 310 printf(" %x", buffer[i]); 311 printf("\n"); 312 } 313 #endif 314 315 microtime(&event.timestamp); 316 317 kbd_processevent(&event, ksc); 318 } 319 320 /* 321 * Given a keyboard ADB event, record the keycodes and call the key 322 * repeat handler, optionally passing the event through the mouse 323 * button emulation handler first. 324 */ 325 static void 326 kbd_processevent(event, ksc) 327 adb_event_t *event; 328 struct akbd_softc *ksc; 329 { 330 adb_event_t new_event; 331 332 new_event = *event; 333 new_event.u.k.key = event->bytes[0]; 334 new_event.bytes[1] = 0xff; 335 #if NAED > 0 336 if (adb_polling || !aed_input(&new_event)) 337 #endif 338 #if NWSKBD > 0 339 if (ksc->sc_wskbddev != NULL) /* wskbd is attached? */ 340 kbd_intr(&new_event, ksc); 341 #else 342 /* do nothing */ ; 343 #endif 344 if (event->bytes[1] != 0xff) { 345 new_event.u.k.key = event->bytes[1]; 346 new_event.bytes[0] = event->bytes[1]; 347 new_event.bytes[1] = 0xff; 348 #if NAED > 0 349 if (adb_polling || !aed_input(&new_event)) 350 #endif 351 #if NWSKBD > 0 352 if (ksc->sc_wskbddev != NULL) /* wskbd is attached? */ 353 kbd_intr(&new_event, ksc); 354 #else 355 /* do nothing */ ; 356 #endif 357 } 358 359 } 360 361 #ifdef notyet 362 /* 363 * Get the actual hardware LED state and convert it to softc format. 364 */ 365 static u_char 366 getleds(addr) 367 int addr; 368 { 369 short cmd; 370 u_char buffer[9], leds; 371 372 leds = 0x00; /* all off */ 373 buffer[0] = 0; 374 375 cmd = ADBTALK(addr, 2); 376 if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) == 0 && 377 buffer[0] > 0) 378 leds = ~(buffer[2]) & 0x07; 379 380 return (leds); 381 } 382 383 /* 384 * Set the keyboard LED's. 385 * 386 * Automatically translates from ioctl/softc format to the 387 * actual keyboard register format 388 */ 389 static int 390 setleds(ksc, leds) 391 struct akbd_softc *ksc; 392 u_char leds; 393 { 394 int addr; 395 short cmd; 396 u_char buffer[9]; 397 398 if ((leds & 0x07) == (ksc->sc_leds & 0x07)) 399 return (0); 400 401 addr = ksc->adbaddr; 402 buffer[0] = 0; 403 404 cmd = ADBTALK(addr, 2); 405 if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) || buffer[0] == 0) 406 return (EIO); 407 408 leds = ~leds & 0x07; 409 buffer[2] &= 0xf8; 410 buffer[2] |= leds; 411 412 cmd = ADBLISTEN(addr, 2); 413 adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd); 414 415 /* talk R2 */ 416 cmd = ADBTALK(addr, 2); 417 if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) || buffer[0] == 0) 418 return (EIO); 419 420 ksc->sc_leds = ~((u_int8_t)buffer[2]) & 0x07; 421 422 if ((buffer[2] & 0xf8) != leds) 423 return (EIO); 424 else 425 return (0); 426 } 427 428 /* 429 * Toggle all of the LED's on and off, just for show. 430 */ 431 static void 432 blinkleds(ksc) 433 struct akbd_softc *ksc; 434 { 435 int addr, i; 436 u_char blinkleds, origleds; 437 438 addr = ksc->adbaddr; 439 origleds = getleds(addr); 440 blinkleds = LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK; 441 442 (void)setleds(ksc, blinkleds); 443 444 for (i = 0; i < 10000; i++) 445 delay(50); 446 447 /* make sure that we restore the LED settings */ 448 i = 10; 449 do { 450 (void)setleds(ksc, (u_char)0x00); 451 } while (setleds(ksc, (u_char)0x00) && (i-- > 0)); 452 453 return; 454 } 455 #endif 456 457 int 458 akbd_is_console() 459 { 460 extern struct mac68k_machine_S mac68k_machine; 461 462 return ((mac68k_machine.serial_console & 0x03) == 0); 463 } 464 465 int 466 akbd_enable(v, on) 467 void *v; 468 int on; 469 { 470 return 0; 471 } 472 473 void 474 akbd_set_leds(v, on) 475 void *v; 476 int on; 477 { 478 } 479 480 int 481 akbd_ioctl(v, cmd, data, flag, p) 482 void *v; 483 u_long cmd; 484 caddr_t data; 485 int flag; 486 struct proc *p; 487 { 488 switch (cmd) { 489 490 case WSKBDIO_GTYPE: 491 *(int *)data = 0; /* XXX */ 492 return 0; 493 case WSKBDIO_SETLEDS: 494 return 0; 495 case WSKBDIO_GETLEDS: 496 *(int *)data = 0; 497 return 0; 498 case WSKBDIO_BELL: 499 case WSKBDIO_COMPLEXBELL: 500 #define d ((struct wskbd_bell_data *)data) 501 mac68k_ring_bell(d->pitch, d->period * hz / 1000, 100); 502 /* comes in as msec, goes out as ticks; volume ignored */ 503 #undef d 504 return (0); 505 } 506 /* kbdioctl(...); */ 507 508 return EPASSTHROUGH; 509 } 510 511 static int polledkey; 512 extern int adb_polling; 513 514 int 515 kbd_intr(event, sc) 516 adb_event_t *event; 517 struct akbd_softc *sc; 518 { 519 int key, press, val; 520 int type; 521 522 key = event->u.k.key; 523 press = ADBK_PRESS(key); 524 val = ADBK_KEYVAL(key); 525 526 type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 527 528 if (key == 185) { /* Caps Lock released */ 529 type = WSCONS_EVENT_KEY_DOWN; 530 wskbd_input(sc->sc_wskbddev, type, val); 531 type = WSCONS_EVENT_KEY_UP; 532 } 533 534 if (adb_polling) 535 polledkey = key; 536 else 537 wskbd_input(sc->sc_wskbddev, type, val); 538 539 return 0; 540 } 541 542 int 543 akbd_cnattach() 544 { 545 wskbd_cnattach(&akbd_consops, NULL, &akbd_keymapdata); 546 547 return 0; 548 } 549 550 void 551 akbd_cngetc(v, type, data) 552 void *v; 553 u_int *type; 554 int *data; 555 { 556 int intbits, key, press, val; 557 int s; 558 559 s = splhigh(); 560 561 polledkey = -1; 562 adb_polling = 1; 563 564 while (polledkey == -1) { 565 intbits = via_reg(VIA1, vIFR); 566 567 if (intbits & V1IF_ADBRDY) { 568 mrg_adbintr(); 569 via_reg(VIA1, vIFR) = V1IF_ADBRDY; 570 } 571 if (intbits & 0x10) { 572 mrg_pmintr(); 573 via_reg(VIA1, vIFR) = 0x10; 574 } 575 } 576 577 adb_polling = 0; 578 splx(s); 579 580 key = polledkey; 581 press = ADBK_PRESS(key); 582 val = ADBK_KEYVAL(key); 583 584 *data = val; 585 *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 586 } 587 588 void 589 akbd_cnpollc(v, on) 590 void *v; 591 int on; 592 { 593 } 594