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