1 /* $NetBSD: pckbd.c,v 1.33 2017/06/11 03:55:56 nat Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /*- 33 * Copyright (c) 1990 The Regents of the University of California. 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * William Jolitz and Don Ahn. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 * 63 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 64 */ 65 66 /* 67 * code to work keyboard for PC-style console 68 */ 69 70 #include <sys/cdefs.h> 71 __KERNEL_RCSID(0, "$NetBSD: pckbd.c,v 1.33 2017/06/11 03:55:56 nat Exp $"); 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/device.h> 76 #include <sys/malloc.h> 77 #include <sys/ioctl.h> 78 79 #include <sys/bus.h> 80 81 #include <dev/pckbport/pckbportvar.h> 82 83 #include <dev/wscons/wsconsio.h> 84 #include <dev/wscons/wskbdvar.h> 85 #include <dev/wscons/wsksymdef.h> 86 #include <dev/wscons/wsksymvar.h> 87 88 #include <dev/pckbport/pckbdreg.h> 89 #include <dev/pckbport/pckbdvar.h> 90 #include <dev/pckbport/wskbdmap_mfii.h> 91 92 #include "locators.h" 93 94 #include "opt_pckbd_layout.h" 95 #include "opt_pckbd_cnattach_may_fail.h" 96 #include "opt_wsdisplay_compat.h" 97 98 struct pckbd_internal { 99 int t_isconsole; 100 pckbport_tag_t t_kbctag; 101 pckbport_slot_t t_kbcslot; 102 103 int t_translating; 104 105 int t_lastchar; 106 int t_extended0; 107 int t_extended1; 108 int t_releasing; 109 110 struct pckbd_softc *t_sc; /* back pointer */ 111 }; 112 113 struct pckbd_softc { 114 device_t sc_dev; 115 116 struct pckbd_internal *id; 117 int sc_enabled; 118 119 int sc_ledstate; 120 121 device_t sc_wskbddev; 122 #ifdef WSDISPLAY_COMPAT_RAWKBD 123 int rawkbd; 124 #endif 125 }; 126 127 static int pckbd_is_console(pckbport_tag_t, pckbport_slot_t); 128 129 int pckbdprobe(device_t, cfdata_t, void *); 130 void pckbdattach(device_t, device_t, void *); 131 132 CFATTACH_DECL_NEW(pckbd, sizeof(struct pckbd_softc), 133 pckbdprobe, pckbdattach, NULL, NULL); 134 135 int pckbd_enable(void *, int); 136 void pckbd_set_leds(void *, int); 137 int pckbd_ioctl(void *, u_long, void *, int, struct lwp *); 138 139 const struct wskbd_accessops pckbd_accessops = { 140 pckbd_enable, 141 pckbd_set_leds, 142 pckbd_ioctl, 143 }; 144 145 void pckbd_cngetc(void *, u_int *, int *); 146 void pckbd_cnpollc(void *, int); 147 void pckbd_cnbell(void *, u_int, u_int, u_int); 148 149 const struct wskbd_consops pckbd_consops = { 150 pckbd_cngetc, 151 pckbd_cnpollc, 152 pckbd_cnbell, 153 }; 154 155 const struct wskbd_mapdata pckbd_keymapdata = { 156 pckbd_keydesctab, 157 #ifdef PCKBD_LAYOUT 158 PCKBD_LAYOUT, 159 #else 160 KB_US, 161 #endif 162 }; 163 164 /* 165 * Hackish support for a bell on the PC Keyboard; when a suitable feeper 166 * is found, it attaches itself into the pckbd driver here. 167 */ 168 void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int); 169 void *pckbd_bell_fn_arg; 170 171 void pckbd_bell(u_int, u_int, u_int, int); 172 173 int pckbd_scancode_translate(struct pckbd_internal *, int); 174 int pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t, 175 struct pckbd_internal *); 176 int pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t, 177 int); 178 void pckbd_input(void *, int); 179 180 static int pckbd_decode(struct pckbd_internal *, int, u_int *, int *); 181 static int pckbd_led_encode(int); 182 static int pckbd_led_decode(int); 183 184 struct pckbd_internal pckbd_consdata; 185 186 int 187 pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot, 188 struct pckbd_internal *id) 189 { 190 int xt, res = 0; 191 u_char cmd[2]; 192 193 /* 194 * Some keyboard/8042 combinations do not seem to work if the keyboard 195 * is set to table 1; in fact, it would appear that some keyboards just 196 * ignore the command altogether. So by default, we use the AT scan 197 * codes and have the 8042 translate them. Unfortunately, this is 198 * known to not work on some PS/2 machines. We try desperately to deal 199 * with this by checking the (lack of a) translate bit in the 8042 and 200 * attempting to set the keyboard to XT mode. If this all fails, well, 201 * tough luck. If the PCKBC_CANT_TRANSLATE pckbc flag was set, we 202 * enable software translation. 203 * 204 * XXX It would perhaps be a better choice to just use AT scan codes 205 * and not bother with this. 206 */ 207 xt = pckbport_xt_translation(kbctag, kbcslot, 1); 208 if (xt == 1) { 209 /* The 8042 is translating for us; use AT codes. */ 210 cmd[0] = KBC_SETTABLE; 211 cmd[1] = 2; 212 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0); 213 if (res) { 214 u_char cmdb[1]; 215 aprint_debug("pckbd: error setting scanset 2\n"); 216 /* 217 * XXX at least one keyboard is reported to lock up 218 * if a "set table" is attempted, thus the "reset". 219 * XXX ignore errors, scanset 2 should be 220 * default anyway. 221 */ 222 cmdb[0] = KBC_RESET; 223 (void)pckbport_poll_cmd(kbctag, kbcslot, cmdb, 1, 1, 0, 1); 224 pckbport_flush(kbctag, kbcslot); 225 res = 0; 226 } 227 if (id != NULL) 228 id->t_translating = 1; 229 } else if (xt == -1) { 230 /* Software translation required */ 231 if (id != NULL) 232 id->t_translating = 0; 233 } else { 234 /* Stupid 8042; set keyboard to XT codes. */ 235 cmd[0] = KBC_SETTABLE; 236 cmd[1] = 1; 237 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0); 238 if (res) 239 aprint_debug("pckbd: error setting scanset 1\n"); 240 if (id != NULL) 241 id->t_translating = 1; 242 } 243 return res; 244 } 245 246 static int 247 pckbd_is_console(pckbport_tag_t tag, pckbport_slot_t slot) 248 { 249 250 return pckbd_consdata.t_isconsole && 251 tag == pckbd_consdata.t_kbctag && slot == pckbd_consdata.t_kbcslot; 252 } 253 254 static bool 255 pckbd_suspend(device_t dv, const pmf_qual_t *qual) 256 { 257 struct pckbd_softc *sc = device_private(dv); 258 u_char cmd[1]; 259 int res; 260 261 /* XXX duped from pckbd_enable, but we want to disable 262 * it even if it's the console kbd 263 */ 264 cmd[0] = KBC_DISABLE; 265 res = pckbport_enqueue_cmd(sc->id->t_kbctag, 266 sc->id->t_kbcslot, cmd, 1, 0, 1, 0); 267 if (res) 268 return false; 269 270 pckbport_slot_enable(sc->id->t_kbctag, 271 sc->id->t_kbcslot, 0); 272 273 sc->sc_enabled = 0; 274 return true; 275 } 276 277 static bool 278 pckbd_resume(device_t dv, const pmf_qual_t *qual) 279 { 280 struct pckbd_softc *sc = device_private(dv); 281 u_char cmd[1], resp[1]; 282 int res; 283 284 /* XXX jmcneill reset the keyboard */ 285 pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot); 286 287 cmd[0] = KBC_RESET; 288 res = pckbport_poll_cmd(sc->id->t_kbctag, 289 sc->id->t_kbcslot, cmd, 1, 1, resp, 1); 290 if (res) 291 aprint_debug("%s: reset error %d\n", __func__, res); 292 if (resp[0] != KBR_RSTDONE) 293 printf("%s: reset response 0x%x\n", __func__, resp[0]); 294 295 pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot); 296 297 pckbd_enable(sc, 1); 298 299 return true; 300 } 301 302 /* 303 * these are both bad jokes 304 */ 305 int 306 pckbdprobe(device_t parent, cfdata_t cf, void *aux) 307 { 308 struct pckbport_attach_args *pa = aux; 309 int res; 310 u_char cmd[1], resp[1]; 311 312 /* 313 * XXX There are rumours that a keyboard can be connected 314 * to the aux port as well. For me, this didn't work. 315 * For further experiments, allow it if explicitly 316 * wired in the config file. 317 */ 318 if ((pa->pa_slot != PCKBPORT_KBD_SLOT) && 319 (cf->cf_loc[PCKBPORTCF_SLOT] == PCKBPORTCF_SLOT_DEFAULT)) 320 return 0; 321 322 /* Flush any garbage. */ 323 pckbport_flush(pa->pa_tag, pa->pa_slot); 324 325 /* Reset the keyboard. */ 326 cmd[0] = KBC_RESET; 327 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1); 328 if (res) { 329 aprint_debug("pckbdprobe: reset error %d\n", res); 330 /* 331 * There is probably no keyboard connected. 332 * Let the probe succeed if the keyboard is used 333 * as console input - it can be connected later. 334 */ 335 return pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0; 336 } 337 if (resp[0] != KBR_RSTDONE) { 338 printf("pckbdprobe: reset response 0x%x\n", resp[0]); 339 return 0; 340 } 341 342 /* 343 * Some keyboards seem to leave a second ack byte after the reset. 344 * This is kind of stupid, but we account for them anyway by just 345 * flushing the buffer. 346 */ 347 pckbport_flush(pa->pa_tag, pa->pa_slot); 348 349 if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL)) 350 return 0; 351 352 return 2; 353 } 354 355 void 356 pckbdattach(device_t parent, device_t self, void *aux) 357 { 358 struct pckbd_softc *sc = device_private(self); 359 struct pckbport_attach_args *pa = aux; 360 struct wskbddev_attach_args a; 361 int isconsole; 362 u_char cmd[1]; 363 364 aprint_naive("\n"); 365 aprint_normal("\n"); 366 367 sc->sc_dev = self; 368 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot); 369 370 if (isconsole) { 371 sc->id = &pckbd_consdata; 372 373 /* 374 * Some keyboards are not enabled after a reset, 375 * so make sure it is enabled now. 376 */ 377 cmd[0] = KBC_ENABLE; 378 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 379 cmd, 1, 0, 0, 0); 380 sc->sc_enabled = 1; 381 } else { 382 sc->id = malloc(sizeof(struct pckbd_internal), 383 M_DEVBUF, M_WAITOK); 384 (void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0); 385 386 /* no interrupts until enabled */ 387 cmd[0] = KBC_DISABLE; 388 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 389 cmd, 1, 0, 0, 0); 390 sc->sc_enabled = 0; 391 } 392 393 sc->id->t_sc = sc; 394 395 pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot, 396 pckbd_input, sc, device_xname(sc->sc_dev)); 397 398 a.console = isconsole; 399 400 a.keymap = &pckbd_keymapdata; 401 402 a.accessops = &pckbd_accessops; 403 a.accesscookie = sc; 404 405 if (!pmf_device_register(self, pckbd_suspend, pckbd_resume)) 406 aprint_error_dev(self, "couldn't establish power handler\n"); 407 408 /* 409 * Attach the wskbd, saving a handle to it. 410 * XXX XXX XXX 411 */ 412 sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); 413 } 414 415 int 416 pckbd_enable(void *v, int on) 417 { 418 struct pckbd_softc *sc = v; 419 int res; 420 u_char cmd[1]; 421 422 if (on) { 423 if (sc->sc_enabled) { 424 aprint_debug("pckbd_enable: bad enable\n"); 425 return EBUSY; 426 } 427 428 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 429 430 cmd[0] = KBC_ENABLE; 431 res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 432 cmd, 1, 0, NULL, 0); 433 if (res) { 434 printf("pckbd_enable: command error\n"); 435 return (res); 436 } 437 438 res = pckbd_set_xtscancode(sc->id->t_kbctag, 439 sc->id->t_kbcslot, sc->id); 440 if (res) 441 return res; 442 443 sc->sc_enabled = 1; 444 } else { 445 if (sc->id->t_isconsole) 446 return EBUSY; 447 448 cmd[0] = KBC_DISABLE; 449 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 450 cmd, 1, 0, 1, 0); 451 if (res) { 452 printf("pckbd_disable: command error\n"); 453 return res; 454 } 455 456 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 457 458 sc->sc_enabled = 0; 459 } 460 461 return 0; 462 } 463 464 const u_int8_t pckbd_xtbl[] = { 465 /* 0x00 */ 466 0, 467 0x43, /* F9 */ 468 0x89, /* SunStop */ 469 0x3f, /* F5 */ 470 0x3d, /* F3 */ 471 0x3b, /* F1 */ 472 0x3c, /* F2 */ 473 0x58, /* F12 */ 474 0, 475 0x44, /* F10 */ 476 0x42, /* F8 */ 477 0x40, /* F6 */ 478 0x3e, /* F4 */ 479 0x0f, /* Tab */ 480 0x29, /* ` ~ */ 481 0, 482 /* 0x10 */ 483 0, 484 0x38, /* Left Alt */ 485 0x2a, /* Left Shift */ 486 0, 487 0x1d, /* Left Ctrl */ 488 0x10, /* q */ 489 0x02, /* 1 ! */ 490 0, 491 0, 492 0, 493 0x2c, /* z */ 494 0x1f, /* s */ 495 0x1e, /* a */ 496 0x11, /* w */ 497 0x03, /* 2 @ */ 498 0, 499 /* 0x20 */ 500 0, 501 0x2e, /* c */ 502 0x2d, /* x */ 503 0x20, /* d */ 504 0x12, /* e */ 505 0x05, /* 4 $ */ 506 0x04, /* 3 # */ 507 0, 508 0, 509 0x39, /* Space */ 510 0x2f, /* v */ 511 0x21, /* f */ 512 0x14, /* t */ 513 0x13, /* r */ 514 0x06, /* 5 % */ 515 0, 516 /* 0x30 */ 517 0, 518 0x31, /* n */ 519 0x30, /* b */ 520 0x23, /* h */ 521 0x22, /* g */ 522 0x15, /* y */ 523 0x07, /* 6 ^ */ 524 0, 525 0, 526 0, 527 0x32, /* m */ 528 0x24, /* j */ 529 0x16, /* u */ 530 0x08, /* 7 & */ 531 0x09, /* 8 * */ 532 0, 533 /* 0x40 */ 534 0, 535 0x33, /* , < */ 536 0x25, /* k */ 537 0x17, /* i */ 538 0x18, /* o */ 539 0x0b, /* 0 ) */ 540 0x0a, /* 9 ( */ 541 0, 542 0, 543 0x34, /* . > */ 544 0x35, /* / ? */ 545 0x26, /* l */ 546 0x27, /* ; : */ 547 0x19, /* p */ 548 0x0c, /* - _ */ 549 0, 550 /* 0x50 */ 551 0, 552 0, 553 0x28, /* ' " */ 554 0, 555 0x1a, /* [ { */ 556 0x0d, /* = + */ 557 0, 558 0, 559 0x3a, /* Caps Lock */ 560 0x36, /* Right Shift */ 561 0x1c, /* Return */ 562 0x1b, /* ] } */ 563 0, 564 0x2b, /* \ | */ 565 0, 566 0, 567 /* 0x60 */ 568 0, 569 0, 570 0, 571 0, 572 0, 573 0, 574 0x0e, /* Back Space */ 575 0, 576 0, 577 0x4f, /* KP 1 */ 578 0, 579 0x4b, /* KP 4 */ 580 0x47, /* KP 7 */ 581 0, 582 0, 583 0, 584 /* 0x70 */ 585 0x52, /* KP 0 */ 586 0x53, /* KP . */ 587 0x50, /* KP 2 */ 588 0x4c, /* KP 5 */ 589 0x4d, /* KP 6 */ 590 0x48, /* KP 8 */ 591 0x01, /* Escape */ 592 0x45, /* Num Lock */ 593 0x57, /* F11 */ 594 0x4e, /* KP + */ 595 0x51, /* KP 3 */ 596 0x4a, /* KP - */ 597 0x37, /* KP * */ 598 0x49, /* KP 9 */ 599 0x46, /* Scroll Lock */ 600 0, 601 /* 0x80 */ 602 0, 603 0, 604 0, 605 0x41, /* F7 (produced as an actual 8 bit code) */ 606 0, /* Alt-Print Screen */ 607 0, 608 0, 609 0, 610 0, 611 0, 612 0, 613 0, 614 0, 615 0, 616 0, 617 0, 618 /* 0x90 */ 619 0xdb, /* Left Meta */ 620 0x88, /* SunHelp */ 621 0x8a, /* SunAgain */ 622 0x8c, /* SunUndo */ 623 0x8e, /* SunCopy */ 624 0x90, /* SunPaste */ 625 0x92, /* SunCut */ 626 0x8b, /* SunProps */ 627 0x8d, /* SunFront */ 628 0x8f, /* SunOpen */ 629 0x91 /* SunFind */ 630 }; 631 632 const u_int8_t pckbd_xtbl_ext[] = { 633 /* 0x00 */ 634 0, 635 0, 636 0, 637 0, 638 0, 639 0, 640 0, 641 0, 642 0, 643 0, 644 0, 645 0, 646 0, 647 0, 648 0, 649 0, 650 /* 0x10 */ 651 0, 652 0x38, /* Right Alt */ 653 0, /* E0 12, to be ignored */ 654 0, 655 0x1d, /* Right Ctrl */ 656 0, 657 0, 658 0, 659 0, 660 0, 661 0, 662 0, 663 0, 664 0, 665 0, 666 0, 667 /* 0x20 */ 668 0, 669 0, 670 0, 671 0, 672 0, 673 0, 674 0, 675 0, 676 0, 677 0, 678 0, 679 0, 680 0, 681 0, 682 0, 683 0xdd, /* Compose */ 684 /* 0x30 */ 685 0, 686 0, 687 0, 688 0, 689 0, 690 0, 691 0, 692 0, 693 0, 694 0, 695 0, 696 0, 697 0, 698 0, 699 0, 700 0, 701 /* 0x40 */ 702 0, 703 0, 704 0, 705 0, 706 0, 707 0, 708 0, 709 0, 710 0, 711 0, 712 0xb5, /* KP / */ 713 0, 714 0, 715 0, 716 0, 717 0, 718 /* 0x50 */ 719 0, 720 0, 721 0, 722 0, 723 0, 724 0, 725 0, 726 0, 727 0, 728 0, 729 0x1c, /* KP Return */ 730 0, 731 0, 732 0, 733 0, 734 0, 735 /* 0x60 */ 736 0, 737 0, 738 0, 739 0, 740 0, 741 0, 742 0, 743 0, 744 0, 745 0x4f, /* End */ 746 0, 747 0x4b, /* Left */ 748 0x47, /* Home */ 749 0, 750 0, 751 0, 752 /* 0x70 */ 753 0x52, /* Insert */ 754 0x53, /* Delete */ 755 0x50, /* Down */ 756 0, 757 0x4d, /* Right */ 758 0x48, /* Up */ 759 0, 760 0, 761 0, 762 0, 763 0x51, /* Page Down */ 764 0, 765 0x37, /* Print Screen */ 766 0x49, /* Page Up */ 767 0x46, /* Ctrl-Break */ 768 0 769 }; 770 771 /* 772 * Translate scan codes from set 2 to set 1 773 */ 774 int 775 pckbd_scancode_translate(struct pckbd_internal *id, int datain) 776 { 777 if (id->t_translating != 0) 778 return datain; 779 780 if (datain == KBR_BREAK) { 781 id->t_releasing = 0x80; /* next keycode is a release */ 782 return 0; /* consume scancode */ 783 } 784 785 /* 786 * Handle extended sequences 787 */ 788 if (datain == KBR_EXTENDED0 || datain == KBR_EXTENDED1) 789 return datain; 790 791 /* 792 * Convert BREAK sequence (14 77 -> 1D 45) 793 */ 794 if (id->t_extended1 == 2 && datain == 0x14) 795 return 0x1d | id->t_releasing; 796 else if (id->t_extended1 == 1 && datain == 0x77) 797 return 0x45 | id->t_releasing; 798 799 if (id->t_extended0 != 0) { 800 if (datain >= sizeof pckbd_xtbl_ext) 801 datain = 0; 802 else 803 datain = pckbd_xtbl_ext[datain]; 804 } else { 805 if (datain >= sizeof pckbd_xtbl) 806 datain = 0; 807 else 808 datain = pckbd_xtbl[datain]; 809 } 810 811 /* 812 * If we are mapping in the range 128-254, then make this 813 * an extended keycode, as table 1 codes are limited to 814 * the range 0-127 (the top bit is used for key up/break). 815 */ 816 if (datain > 0x7f) { 817 datain &= 0x7f; 818 id->t_extended0 = 0x80; 819 } 820 821 if (datain == 0) { 822 /* 823 * We don't know how to translate this scan code, but 824 * we can't silently eat it either (because there might 825 * have been an extended byte transmitted already). 826 * Hopefully this value will be harmless to the upper 827 * layers. 828 */ 829 return 0xff; 830 } 831 return datain | id->t_releasing; 832 } 833 834 static int 835 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) 836 { 837 int key; 838 int releasing; 839 840 if (datain == KBR_EXTENDED0) { 841 id->t_extended0 = 0x80; 842 return 0; 843 } else if (datain == KBR_EXTENDED1) { 844 id->t_extended1 = 2; 845 return 0; 846 } 847 848 releasing = datain & 0x80; 849 datain &= 0x7f; 850 851 if (id->t_extended0 == 0x80) { 852 switch (datain) { 853 case 0x2a: 854 case 0x36: 855 id->t_extended0 = 0; 856 return 0; 857 default: 858 break; 859 } 860 } 861 862 /* map extended keys to (unused) codes 128-254 */ 863 key = datain | id->t_extended0; 864 id->t_extended0 = 0; 865 866 /* 867 * process PAUSE (also break) key (EXT1 1D 45 EXT1 9D C5): 868 * map to (unused) code 7F 869 */ 870 if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) { 871 id->t_extended1 = 1; 872 return 0; 873 } else if (id->t_extended1 == 1 && 874 (datain == 0x45 || datain == 0xc5)) { 875 id->t_extended1 = 0; 876 key = 0x7f; 877 } else if (id->t_extended1 > 0) { 878 id->t_extended1 = 0; 879 } 880 881 if (id->t_translating != 0) { 882 id->t_releasing = releasing; 883 } else { 884 /* id->t_releasing computed in pckbd_scancode_translate() */ 885 } 886 887 if (id->t_releasing) { 888 id->t_releasing = 0; 889 id->t_lastchar = 0; 890 *type = WSCONS_EVENT_KEY_UP; 891 } else { 892 /* Always ignore typematic keys */ 893 if (key == id->t_lastchar) 894 return 0; 895 id->t_lastchar = key; 896 *type = WSCONS_EVENT_KEY_DOWN; 897 } 898 899 *dataout = key; 900 return 1; 901 } 902 903 int 904 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag, 905 pckbport_slot_t kbcslot, int console) 906 { 907 908 memset(t, 0, sizeof(struct pckbd_internal)); 909 910 t->t_isconsole = console; 911 t->t_kbctag = kbctag; 912 t->t_kbcslot = kbcslot; 913 914 return pckbd_set_xtscancode(kbctag, kbcslot, t); 915 } 916 917 static int 918 pckbd_led_encode(int led) 919 { 920 int res; 921 922 res = 0; 923 924 if (led & WSKBD_LED_SCROLL) 925 res |= 0x01; 926 if (led & WSKBD_LED_NUM) 927 res |= 0x02; 928 if (led & WSKBD_LED_CAPS) 929 res |= 0x04; 930 return res; 931 } 932 933 static int 934 pckbd_led_decode(int led) 935 { 936 int res; 937 938 res = 0; 939 if (led & 0x01) 940 res |= WSKBD_LED_SCROLL; 941 if (led & 0x02) 942 res |= WSKBD_LED_NUM; 943 if (led & 0x04) 944 res |= WSKBD_LED_CAPS; 945 return res; 946 } 947 948 void 949 pckbd_set_leds(void *v, int leds) 950 { 951 struct pckbd_softc *sc = v; 952 u_char cmd[2]; 953 954 cmd[0] = KBC_MODEIND; 955 cmd[1] = pckbd_led_encode(leds); 956 sc->sc_ledstate = cmd[1]; 957 958 (void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 959 cmd, 2, 0, 0, 0); 960 } 961 962 /* 963 * Got a console receive interrupt - 964 * the console processor wants to give us a character. 965 */ 966 void 967 pckbd_input(void *vsc, int data) 968 { 969 struct pckbd_softc *sc = vsc; 970 int key; 971 u_int type; 972 973 data = pckbd_scancode_translate(sc->id, data); 974 if (data == 0) 975 return; 976 977 #ifdef WSDISPLAY_COMPAT_RAWKBD 978 if (sc->rawkbd) { 979 u_char d = data; 980 wskbd_rawinput(sc->sc_wskbddev, &d, 1); 981 return; 982 } 983 #endif 984 if (pckbd_decode(sc->id, data, &type, &key)) 985 wskbd_input(sc->sc_wskbddev, type, key); 986 } 987 988 int 989 pckbd_ioctl(void *v, u_long cmd, void *data, int flag, 990 struct lwp *l) 991 { 992 struct pckbd_softc *sc = v; 993 994 switch (cmd) { 995 case WSKBDIO_GTYPE: 996 *(int *)data = WSKBD_TYPE_PC_XT; 997 return 0; 998 case WSKBDIO_SETLEDS: 999 { 1000 int res; 1001 u_char cmdb[2]; 1002 1003 cmdb[0] = KBC_MODEIND; 1004 cmdb[1] = pckbd_led_encode(*(int *)data); 1005 sc->sc_ledstate = cmdb[1]; 1006 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 1007 cmdb, 2, 0, 1, 0); 1008 return res; 1009 } 1010 case WSKBDIO_GETLEDS: 1011 *(int *)data = pckbd_led_decode(sc->sc_ledstate); 1012 return 0; 1013 #if 0 1014 case WSKBDIO_COMPLEXBELL: 1015 #define d ((struct wskbd_bell_data *)data) 1016 /* 1017 * Keyboard can't beep directly; we have an 1018 * externally-provided global hook to do this. 1019 */ 1020 pckbd_bell(d->pitch, d->period, d->volume, 0); 1021 #undef d 1022 return 0; 1023 #endif 1024 #ifdef WSDISPLAY_COMPAT_RAWKBD 1025 case WSKBDIO_SETMODE: 1026 sc->rawkbd = (*(int *)data == WSKBD_RAW); 1027 return 0; 1028 #endif 1029 } 1030 return EPASSTHROUGH; 1031 } 1032 1033 void 1034 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll) 1035 { 1036 1037 if (pckbd_bell_fn != NULL) 1038 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 1039 volume, poll); 1040 } 1041 1042 void 1043 pckbd_unhook_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 1044 { 1045 if (pckbd_bell_fn != fn && pckbd_bell_fn_arg != arg) 1046 return; 1047 pckbd_bell_fn = NULL; 1048 pckbd_bell_fn_arg = NULL; 1049 } 1050 1051 void 1052 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 1053 { 1054 1055 if (pckbd_bell_fn == NULL) { 1056 pckbd_bell_fn = fn; 1057 pckbd_bell_fn_arg = arg; 1058 } 1059 } 1060 1061 int 1062 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot) 1063 { 1064 int res; 1065 u_char cmd[1]; 1066 1067 res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1); 1068 /* We may allow the console to be attached if no keyboard is present */ 1069 #if defined(PCKBD_CNATTACH_MAY_FAIL) 1070 if (res) 1071 return res; 1072 #endif 1073 1074 /* Just to be sure. */ 1075 cmd[0] = KBC_ENABLE; 1076 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0); 1077 1078 #if defined(PCKBD_CNATTACH_MAY_FAIL) 1079 if (res) 1080 return res; 1081 #endif 1082 1083 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 1084 1085 return res; 1086 } 1087 1088 /* ARGSUSED */ 1089 void 1090 pckbd_cngetc(void *v, u_int *type, int *data) 1091 { 1092 struct pckbd_internal *t = v; 1093 int val; 1094 1095 for (;;) { 1096 val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot); 1097 if (val == -1) 1098 continue; 1099 1100 val = pckbd_scancode_translate(t, val); 1101 if (val == 0) 1102 continue; 1103 1104 if (pckbd_decode(t, val, type, data)) 1105 return; 1106 } 1107 } 1108 1109 void 1110 pckbd_cnpollc(void *v, int on) 1111 { 1112 struct pckbd_internal *t = v; 1113 1114 pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on); 1115 } 1116 1117 void 1118 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 1119 { 1120 1121 pckbd_bell(pitch, period, volume, 1); 1122 } 1123