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