1 /* $OpenBSD: pckbd.c,v 1.51 2023/08/13 21:54:02 miod Exp $ */ 2 /* $NetBSD: pckbd.c,v 1.24 2000/06/05 22:20:57 sommerfeld Exp $ */ 3 4 /*- 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Charles M. Hannum. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /*- 34 * Copyright (c) 1990 The Regents of the University of California. 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * William Jolitz and Don Ahn. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 65 */ 66 67 /* 68 * code to work keyboard for PC-style console 69 */ 70 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/device.h> 74 #include <sys/malloc.h> 75 #include <sys/ioctl.h> 76 77 #include <machine/bus.h> 78 79 #include <dev/ic/pckbcvar.h> 80 #include <dev/pckbc/pckbdreg.h> 81 #include <dev/pckbc/pmsreg.h> 82 83 #include <dev/wscons/wsconsio.h> 84 #include <dev/wscons/wskbdraw.h> 85 #include <dev/wscons/wskbdvar.h> 86 #include <dev/wscons/wsksymdef.h> 87 #include <dev/wscons/wsksymvar.h> 88 89 #include <dev/pckbc/wskbdmap_mfii.h> 90 91 struct pckbd_internal { 92 int t_isconsole; 93 pckbc_tag_t t_kbctag; 94 pckbc_slot_t t_kbcslot; 95 96 int t_translating; /* nonzero if hardware performs translation */ 97 int t_table; /* scan code set in use */ 98 99 int t_lastchar; 100 int t_extended; 101 int t_extended1; 102 int t_releasing; 103 104 struct pckbd_softc *t_sc; /* back pointer */ 105 }; 106 107 struct pckbd_softc { 108 struct device sc_dev; 109 110 struct pckbd_internal *id; 111 int sc_enabled; 112 113 int sc_ledstate; 114 115 struct device *sc_wskbddev; 116 #ifdef WSDISPLAY_COMPAT_RAWKBD 117 int rawkbd; 118 u_int sc_rawcnt; 119 char sc_rawbuf[3]; 120 #endif 121 }; 122 123 static int pckbd_is_console(pckbc_tag_t, pckbc_slot_t); 124 125 int pckbdprobe(struct device *, void *, void *); 126 void pckbdattach(struct device *, struct device *, void *); 127 int pckbdactivate(struct device *, int); 128 129 const struct cfattach pckbd_ca = { 130 sizeof(struct pckbd_softc), 131 pckbdprobe, 132 pckbdattach, 133 NULL, 134 pckbdactivate 135 }; 136 137 int pckbd_enable(void *, int); 138 void pckbd_set_leds(void *, int); 139 int pckbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 140 141 const struct wskbd_accessops pckbd_accessops = { 142 pckbd_enable, 143 pckbd_set_leds, 144 pckbd_ioctl, 145 }; 146 147 void pckbd_cngetc(void *, u_int *, int *); 148 void pckbd_cnpollc(void *, int); 149 void pckbd_cnbell(void *, u_int, u_int, u_int); 150 151 const struct wskbd_consops pckbd_consops = { 152 pckbd_cngetc, 153 pckbd_cnpollc, 154 pckbd_cnbell, 155 }; 156 157 const struct wskbd_mapdata pckbd_keymapdata = { 158 pckbd_keydesctab, 159 #ifdef PCKBD_LAYOUT 160 PCKBD_LAYOUT, 161 #else 162 KB_US | KB_DEFAULT, 163 #endif 164 }; 165 166 /* 167 * Hackish support for a bell on the PC Keyboard; when a suitable beeper 168 * is found, it attaches itself into the pckbd driver here. 169 */ 170 void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int); 171 void *pckbd_bell_fn_arg; 172 173 void pckbd_bell(u_int, u_int, u_int, int); 174 175 int pckbd_scancode_translate(struct pckbd_internal *, int); 176 int pckbd_set_xtscancode(pckbc_tag_t, pckbc_slot_t, 177 struct pckbd_internal *); 178 void pckbd_init(struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t, int); 179 void pckbd_input(void *, int); 180 181 static int pckbd_decode(struct pckbd_internal *, int, 182 u_int *, int *); 183 static int pckbd_led_encode(int); 184 185 struct pckbd_internal pckbd_consdata; 186 187 int 188 pckbdactivate(struct device *self, int act) 189 { 190 struct pckbd_softc *sc = (struct pckbd_softc *)self; 191 int rv = 0; 192 u_char cmd[1]; 193 194 switch(act) { 195 case DVACT_RESUME: 196 if (sc->sc_enabled) { 197 /* 198 * Some keyboards are not enabled after a reset, 199 * so make sure it is enabled now. 200 */ 201 cmd[0] = KBC_ENABLE; 202 (void) pckbc_poll_cmd(sc->id->t_kbctag, 203 sc->id->t_kbcslot, cmd, 1, 0, NULL, 0); 204 /* XXX - also invoke pckbd_set_xtscancode() too? */ 205 } 206 break; 207 } 208 209 rv = config_activate_children(self, act); 210 211 return (rv); 212 } 213 214 int 215 pckbd_set_xtscancode(pckbc_tag_t kbctag, pckbc_slot_t kbcslot, 216 struct pckbd_internal *id) 217 { 218 int table = 0; 219 220 if (pckbc_xt_translation(kbctag, &table)) { 221 #ifdef DEBUG 222 printf("pckbd: enabling of translation failed\n"); 223 #endif 224 #ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */ 225 /* 226 * If hardware lacks translation capability, stick to the 227 * table it is using. 228 */ 229 if (table != 0) { 230 id->t_translating = 0; 231 id->t_table = table; 232 return 0; 233 } 234 #endif 235 /* 236 * Since the keyboard controller can not translate scan 237 * codes to the XT set (#1), we would like to request 238 * this exact set. However it is likely that the 239 * controller does not support it either. 240 * 241 * So try scan code set #2 as well, which this driver 242 * knows how to translate. 243 */ 244 table = 2; 245 if (id != NULL) 246 id->t_translating = 0; 247 } else { 248 table = 3; 249 if (id != NULL) { 250 id->t_translating = 1; 251 if (id->t_table == 0) { 252 /* 253 * Don't bother explicitly setting into set 2, 254 * it's the default. 255 */ 256 id->t_table = 2; 257 return (0); 258 } 259 } 260 } 261 262 /* keep falling back until we hit a table that looks usable. */ 263 for (; table >= 1; table--) { 264 u_char cmd[2]; 265 #ifdef DEBUG 266 printf("pckbd: trying table %d\n", table); 267 #endif 268 cmd[0] = KBC_SETTABLE; 269 cmd[1] = table; 270 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, NULL, 0)) { 271 #ifdef DEBUG 272 printf("pckbd: table set of %d failed\n", table); 273 #endif 274 if (table > 1) { 275 cmd[0] = KBC_RESET; 276 (void)pckbc_poll_cmd(kbctag, kbcslot, cmd, 277 1, 1, NULL, 1); 278 pckbc_flush(kbctag, kbcslot); 279 280 continue; 281 } 282 } 283 284 /* 285 * the 8042 took the table set request, however, not all that 286 * report they can work with table 3 actually work, so ask what 287 * table it reports it's in. 288 */ 289 if (table == 3) { 290 u_char resp[1]; 291 292 cmd[0] = KBC_SETTABLE; 293 cmd[1] = 0; 294 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 1, resp, 0)) { 295 /* 296 * query failed, step down to table 2 to be 297 * safe. 298 */ 299 #ifdef DEBUG 300 printf("pckbd: table 3 verification failed\n"); 301 #endif 302 continue; 303 } else if (resp[0] == 3) { 304 #ifdef DEBUG 305 printf("pckbd: settling on table 3\n"); 306 #endif 307 break; 308 } 309 #ifdef DEBUG 310 else 311 printf("pckbd: table \"%x\" != 3, trying 2\n", 312 resp[0]); 313 #endif 314 } else { 315 #ifdef DEBUG 316 printf("pckbd: settling on table %d\n", table); 317 #endif 318 break; 319 } 320 } 321 322 if (table == 0) 323 return (1); 324 325 if (id != NULL) 326 id->t_table = table; 327 328 return (0); 329 } 330 331 static int 332 pckbd_is_console(pckbc_tag_t tag, pckbc_slot_t slot) 333 { 334 return (pckbd_consdata.t_isconsole && 335 (tag == pckbd_consdata.t_kbctag) && 336 (slot == pckbd_consdata.t_kbcslot)); 337 } 338 339 /* 340 * these are both bad jokes 341 */ 342 int 343 pckbdprobe(struct device *parent, void *match, void *aux) 344 { 345 struct cfdata *cf = match; 346 struct pckbc_attach_args *pa = aux; 347 u_char cmd[1], resp[2]; 348 int res; 349 350 /* 351 * XXX There are rumours that a keyboard can be connected 352 * to the aux port as well. For me, this didn't work. 353 * For further experiments, allow it if explicitly 354 * wired in the config file. 355 */ 356 if ((pa->pa_slot != PCKBC_KBD_SLOT) && 357 (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT)) 358 return (0); 359 360 /* Flush any garbage. */ 361 pckbc_flush(pa->pa_tag, pa->pa_slot); 362 363 /* Reset the keyboard. */ 364 cmd[0] = KBC_RESET; 365 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1); 366 if (res != 0) { 367 #ifdef DEBUG 368 printf("pckbdprobe: reset error %d\n", res); 369 #endif 370 } else if (resp[0] != KBR_RSTDONE) { 371 #ifdef DEBUG 372 printf("pckbdprobe: reset response 0x%x\n", resp[0]); 373 #endif 374 res = EINVAL; 375 } 376 #if defined(__i386__) || defined(__amd64__) 377 if (res) { 378 /* 379 * The 8042 emulation on Chromebooks fails the reset 380 * command but otherwise appears to work correctly. 381 * Try a "get ID" command to give it a second chance. 382 */ 383 cmd[0] = KBC_GETID; 384 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, 385 cmd, 1, 2, resp, 0); 386 if (res != 0) { 387 #ifdef DEBUG 388 printf("pckbdprobe: getid error %d\n", res); 389 #endif 390 } else if (resp[0] != 0xab || resp[1] != 0x83) { 391 #ifdef DEBUG 392 printf("pckbdprobe: unexpected id 0x%x/0x%x\n", 393 resp[0], resp[1]); 394 #endif 395 res = EINVAL; 396 } 397 } 398 #endif 399 if (res) { 400 /* 401 * There is probably no keyboard connected. 402 * Let the probe succeed if the keyboard is used 403 * as console input - it can be connected later. 404 */ 405 #if defined(__i386__) || defined(__amd64__) 406 /* 407 * However, on legacy-free PCs, there might really 408 * be no PS/2 connector at all; in that case, do not 409 * even try to attach; ukbd will take over as console. 410 */ 411 if (res == ENXIO) { 412 /* check cf_flags from parent */ 413 struct cfdata *cf = parent->dv_cfdata; 414 if (!ISSET(cf->cf_flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) 415 return 0; 416 } 417 #endif 418 return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0); 419 } 420 421 /* 422 * Some keyboards seem to leave a second ack byte after the reset. 423 * This is kind of stupid, but we account for them anyway by just 424 * flushing the buffer. 425 */ 426 pckbc_flush(pa->pa_tag, pa->pa_slot); 427 428 return (2); 429 } 430 431 void 432 pckbdattach(struct device *parent, struct device *self, void *aux) 433 { 434 struct pckbd_softc *sc = (void *)self; 435 struct pckbc_attach_args *pa = aux; 436 int isconsole; 437 struct wskbddev_attach_args a; 438 u_char cmd[1]; 439 440 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot); 441 442 if (isconsole) { 443 sc->id = &pckbd_consdata; 444 if (sc->id->t_table == 0) 445 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id); 446 447 /* 448 * Some keyboards are not enabled after a reset, 449 * so make sure it is enabled now. 450 */ 451 cmd[0] = KBC_ENABLE; 452 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 453 cmd, 1, 0, NULL, 0); 454 sc->sc_enabled = 1; 455 } else { 456 sc->id = malloc(sizeof(struct pckbd_internal), 457 M_DEVBUF, M_WAITOK); 458 pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0); 459 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id); 460 461 /* no interrupts until enabled */ 462 cmd[0] = KBC_DISABLE; 463 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 464 cmd, 1, 0, NULL, 0); 465 sc->sc_enabled = 0; 466 } 467 468 sc->id->t_sc = sc; 469 470 pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot, 471 pckbd_input, sc, sc->sc_dev.dv_xname); 472 473 a.console = isconsole; 474 475 a.keymap = &pckbd_keymapdata; 476 477 a.accessops = &pckbd_accessops; 478 a.accesscookie = sc; 479 480 printf("\n"); 481 482 /* 483 * Attach the wskbd, saving a handle to it. 484 */ 485 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 486 } 487 488 int 489 pckbd_enable(void *v, int on) 490 { 491 struct pckbd_softc *sc = v; 492 u_char cmd[1]; 493 int res; 494 495 if (on) { 496 if (sc->sc_enabled) 497 return (EBUSY); 498 499 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 500 501 cmd[0] = KBC_ENABLE; 502 res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 503 cmd, 1, 0, NULL, 0); 504 if (res) { 505 printf("pckbd_enable: command error\n"); 506 return (res); 507 } 508 509 res = pckbd_set_xtscancode(sc->id->t_kbctag, 510 sc->id->t_kbcslot, sc->id); 511 if (res) 512 return (res); 513 514 sc->sc_enabled = 1; 515 } else { 516 if (sc->id->t_isconsole) 517 return (EBUSY); 518 519 cmd[0] = KBC_DISABLE; 520 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 521 cmd, 1, 0, 1, 0); 522 if (res) { 523 printf("pckbd_disable: command error\n"); 524 return (res); 525 } 526 527 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 528 529 sc->sc_enabled = 0; 530 } 531 532 return (0); 533 } 534 535 /* 536 * Scan code set #2 translation tables 537 */ 538 539 const u_int8_t pckbd_xtbl2[] = { 540 /* 0x00 */ 541 0, 542 RAWKEY_f9, 543 0, 544 RAWKEY_f5, 545 RAWKEY_f3, 546 RAWKEY_f1, 547 RAWKEY_f2, 548 RAWKEY_f12, 549 RAWKEY_f6, /* F6 according to documentation */ 550 RAWKEY_f10, 551 RAWKEY_f8, 552 RAWKEY_f6, /* F6 according to experimentation */ 553 RAWKEY_f4, 554 RAWKEY_Tab, 555 RAWKEY_grave, 556 0, 557 /* 0x10 */ 558 0, 559 RAWKEY_Alt_L, 560 RAWKEY_Shift_L, 561 0, 562 RAWKEY_Control_L, 563 RAWKEY_q, 564 RAWKEY_1, 565 0, 566 0, 567 0, 568 RAWKEY_z, 569 RAWKEY_s, 570 RAWKEY_a, 571 RAWKEY_w, 572 RAWKEY_2, 573 RAWKEY_Meta_L, 574 /* 0x20 */ 575 0, 576 RAWKEY_c, 577 RAWKEY_x, 578 RAWKEY_d, 579 RAWKEY_e, 580 RAWKEY_4, 581 RAWKEY_3, 582 0, 583 RAWKEY_Meta_R, 584 RAWKEY_space, 585 RAWKEY_v, 586 RAWKEY_f, 587 RAWKEY_t, 588 RAWKEY_r, 589 RAWKEY_5, 590 0, 591 /* 0x30 */ 592 0, 593 RAWKEY_n, 594 RAWKEY_b, 595 RAWKEY_h, 596 RAWKEY_g, 597 RAWKEY_y, 598 RAWKEY_6, 599 0, 600 0, 601 0, 602 RAWKEY_m, 603 RAWKEY_j, 604 RAWKEY_u, 605 RAWKEY_7, 606 RAWKEY_8, 607 0, 608 /* 0x40 */ 609 0, 610 RAWKEY_comma, 611 RAWKEY_k, 612 RAWKEY_i, 613 RAWKEY_o, 614 RAWKEY_0, 615 RAWKEY_9, 616 0, 617 0, 618 RAWKEY_period, 619 RAWKEY_slash, 620 RAWKEY_l, 621 RAWKEY_semicolon, 622 RAWKEY_p, 623 RAWKEY_minus, 624 0, 625 /* 0x50 */ 626 0, 627 0, 628 RAWKEY_apostrophe, 629 0, 630 RAWKEY_bracketleft, 631 RAWKEY_equal, 632 0, 633 0, 634 RAWKEY_Caps_Lock, 635 RAWKEY_Shift_R, 636 RAWKEY_Return, 637 RAWKEY_bracketright, 638 0, 639 RAWKEY_backslash, 640 0, 641 0, 642 /* 0x60 */ 643 0, 644 0, 645 0, 646 0, 647 0, 648 0, 649 RAWKEY_BackSpace, 650 0, 651 0, 652 RAWKEY_KP_End, 653 0, 654 RAWKEY_KP_Left, 655 RAWKEY_KP_Home, 656 0, 657 0, 658 0, 659 /* 0x70 */ 660 RAWKEY_KP_Insert, 661 RAWKEY_KP_Delete, 662 RAWKEY_KP_Down, 663 RAWKEY_KP_Begin, 664 RAWKEY_KP_Right, 665 RAWKEY_KP_Up, 666 RAWKEY_Escape, 667 RAWKEY_Num_Lock, 668 RAWKEY_f11, 669 RAWKEY_KP_Add, 670 RAWKEY_KP_Next, 671 RAWKEY_KP_Subtract, 672 RAWKEY_KP_Multiply, 673 RAWKEY_KP_Prior, 674 RAWKEY_Hold_Screen, 675 0, 676 /* 0x80 */ 677 0, 678 0, 679 0, 680 RAWKEY_f7, 681 0 /* Alt-Print Screen */ 682 }; 683 684 const u_int8_t pckbd_xtbl2_ext[] = { 685 /* 0x00 */ 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 /* 0x10 */ 702 0, 703 RAWKEY_Alt_R, 704 0, /* E0 12, to be ignored */ 705 0, 706 RAWKEY_Control_R, 707 0, 708 0, 709 0, 710 0, 711 0, 712 0, 713 0, 714 0, 715 0, 716 0, 717 0, 718 /* 0x20 */ 719 0, 720 0, 721 0, 722 0, 723 0, 724 0, 725 0, 726 0, 727 0, 728 0, 729 0, 730 0, 731 0, 732 0, 733 0, 734 0, 735 /* 0x30 */ 736 0, 737 0, 738 0, 739 0, 740 0, 741 0, 742 0, 743 0, 744 0, 745 0, 746 0, 747 0, 748 0, 749 0, 750 0, 751 0, 752 /* 0x40 */ 753 0, 754 0, 755 0, 756 0, 757 0, 758 0, 759 0, 760 0, 761 0, 762 0, 763 RAWKEY_KP_Divide, 764 0, 765 0, 766 0, 767 0, 768 0, 769 /* 0x50 */ 770 0, 771 0, 772 0, 773 0, 774 0, 775 0, 776 0, 777 0, 778 0, 779 0, 780 RAWKEY_KP_Enter, 781 0, 782 0, 783 0, 784 0, 785 0, 786 /* 0x60 */ 787 0, 788 0, 789 0, 790 0, 791 0, 792 0, 793 0, 794 0, 795 0, 796 RAWKEY_End, 797 0, 798 RAWKEY_Left, 799 RAWKEY_Home, 800 0, 801 0, 802 0, 803 /* 0x70 */ 804 RAWKEY_Insert, 805 RAWKEY_Delete, 806 RAWKEY_Down, 807 0, 808 RAWKEY_Right, 809 RAWKEY_Up, 810 0, 811 0, 812 0, 813 0, 814 RAWKEY_Next, 815 0, 816 RAWKEY_Print_Screen, 817 RAWKEY_Prior, 818 0xc6, /* Ctrl-Break */ 819 0 820 }; 821 822 #ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */ 823 824 /* 825 * Scan code set #3 translation table 826 */ 827 828 const u_int8_t pckbd_xtbl3[] = { 829 /* 0x00 */ 830 0, 831 RAWKEY_L5, /* Front */ 832 RAWKEY_L1, /* Stop */ 833 RAWKEY_L3, /* Props */ 834 0, 835 RAWKEY_L7, /* Open */ 836 RAWKEY_L9, /* Find */ 837 RAWKEY_f1, 838 RAWKEY_Escape, 839 RAWKEY_L10, /* Cut */ 840 0, 841 0, 842 0, 843 RAWKEY_Tab, 844 RAWKEY_grave, 845 RAWKEY_f2, 846 /* 0x10 */ 847 RAWKEY_Help, 848 RAWKEY_Control_L, 849 RAWKEY_Shift_L, 850 0, 851 RAWKEY_Caps_Lock, 852 RAWKEY_q, 853 RAWKEY_1, 854 RAWKEY_f3, 855 0, 856 RAWKEY_Alt_L, 857 RAWKEY_z, 858 RAWKEY_s, 859 RAWKEY_a, 860 RAWKEY_w, 861 RAWKEY_2, 862 RAWKEY_f4, 863 /* 0x20 */ 864 0, 865 RAWKEY_c, 866 RAWKEY_x, 867 RAWKEY_d, 868 RAWKEY_e, 869 RAWKEY_4, 870 RAWKEY_3, 871 RAWKEY_f5, 872 RAWKEY_L4, /* Undo */ 873 RAWKEY_space, 874 RAWKEY_v, 875 RAWKEY_f, 876 RAWKEY_t, 877 RAWKEY_r, 878 RAWKEY_5, 879 RAWKEY_f6, 880 /* 0x30 */ 881 RAWKEY_L2, /* Again */ 882 RAWKEY_n, 883 RAWKEY_b, 884 RAWKEY_h, 885 RAWKEY_g, 886 RAWKEY_y, 887 RAWKEY_6, 888 RAWKEY_f7, 889 0, 890 RAWKEY_Alt_R, 891 RAWKEY_m, 892 RAWKEY_j, 893 RAWKEY_u, 894 RAWKEY_7, 895 RAWKEY_8, 896 RAWKEY_f8, 897 /* 0x40 */ 898 0, 899 RAWKEY_comma, 900 RAWKEY_k, 901 RAWKEY_i, 902 RAWKEY_o, 903 RAWKEY_0, 904 RAWKEY_9, 905 RAWKEY_f9, 906 RAWKEY_L6, /* Copy */ 907 RAWKEY_period, 908 RAWKEY_slash, 909 RAWKEY_l, 910 RAWKEY_semicolon, 911 RAWKEY_p, 912 RAWKEY_minus, 913 RAWKEY_f10, 914 /* 0x50 */ 915 0, 916 0, 917 RAWKEY_apostrophe, 918 0, 919 RAWKEY_bracketleft, 920 RAWKEY_equal, 921 RAWKEY_f11, 922 RAWKEY_Print_Screen, 923 RAWKEY_Control_R, 924 RAWKEY_Shift_R, 925 RAWKEY_Return, 926 RAWKEY_bracketright, 927 RAWKEY_backslash, 928 0, 929 RAWKEY_f12, 930 RAWKEY_Hold_Screen, 931 /* 0x60 */ 932 RAWKEY_Down, 933 RAWKEY_Left, 934 RAWKEY_Pause, 935 RAWKEY_Up, 936 RAWKEY_Delete, 937 RAWKEY_End, 938 RAWKEY_BackSpace, 939 RAWKEY_Insert, 940 RAWKEY_L8, /* Paste */ 941 RAWKEY_KP_End, 942 RAWKEY_Right, 943 RAWKEY_KP_Left, 944 RAWKEY_KP_Home, 945 RAWKEY_Next, 946 RAWKEY_Home, 947 RAWKEY_Prior, 948 /* 0x70 */ 949 RAWKEY_KP_Insert, 950 RAWKEY_KP_Delete, 951 RAWKEY_KP_Down, 952 RAWKEY_KP_Begin, 953 RAWKEY_KP_Right, 954 RAWKEY_KP_Up, 955 RAWKEY_Num_Lock, 956 RAWKEY_KP_Divide, 957 0, 958 RAWKEY_KP_Enter, 959 RAWKEY_KP_Next, 960 0, 961 RAWKEY_KP_Add, 962 RAWKEY_KP_Prior, 963 RAWKEY_KP_Multiply, 964 0, 965 /* 0x80 */ 966 0, 967 0, 968 0, 969 0, 970 RAWKEY_KP_Subtract, 971 0, 972 0, 973 0, 974 0, 975 0, 976 0, 977 RAWKEY_Meta_L, 978 RAWKEY_Meta_R 979 }; 980 981 #endif 982 983 /* 984 * Translate scan codes from set 2 or 3 to set 1 985 */ 986 int 987 pckbd_scancode_translate(struct pckbd_internal *id, int datain) 988 { 989 if (id->t_translating != 0 || id->t_table == 1) 990 return datain; 991 992 if (datain == KBR_BREAK) { 993 id->t_releasing = 0x80; /* next keycode is a release */ 994 return 0; /* consume scancode */ 995 } 996 997 switch (id->t_table) { 998 case 2: 999 /* 1000 * Convert BREAK sequence (14 77 -> 1D 45) 1001 */ 1002 if (id->t_extended1 == 2 && datain == 0x14) 1003 return 0x1d | id->t_releasing; 1004 else if (id->t_extended1 == 1 && datain == 0x77) 1005 return 0x45 | id->t_releasing; 1006 1007 if (id->t_extended != 0) { 1008 if (datain >= sizeof pckbd_xtbl2_ext) 1009 datain = 0; 1010 else 1011 datain = pckbd_xtbl2_ext[datain]; 1012 /* xtbl2_ext already has the upper bit set */ 1013 id->t_extended = 0; 1014 } else { 1015 if (datain >= sizeof pckbd_xtbl2) 1016 datain = 0; 1017 else 1018 datain = pckbd_xtbl2[datain] & ~0x80; 1019 } 1020 break; 1021 #ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */ 1022 case 3: 1023 if (datain >= sizeof pckbd_xtbl3) 1024 datain = 0; 1025 else 1026 datain = pckbd_xtbl3[datain] & ~0x80; 1027 break; 1028 #endif 1029 } 1030 1031 if (datain == 0) { 1032 /* 1033 * We don't know how to translate this scan code, but 1034 * we can't silently eat it either (because there might 1035 * have been an extended byte transmitted already). 1036 * Hopefully this value will be harmless to the upper 1037 * layers. 1038 */ 1039 return 0xff; 1040 } 1041 1042 return datain | id->t_releasing; 1043 } 1044 1045 static int 1046 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) 1047 { 1048 int key; 1049 int releasing; 1050 1051 if (datain == KBR_EXTENDED0) { 1052 id->t_extended = 0x80; 1053 return 0; 1054 } else if (datain == KBR_EXTENDED1) { 1055 id->t_extended1 = 2; 1056 return 0; 1057 } 1058 1059 releasing = datain & 0x80; 1060 datain &= 0x7f; 1061 1062 /* 1063 * process BREAK key sequence (EXT1 1D 45 / EXT1 9D C5): 1064 * map to (unused) code 7F 1065 */ 1066 if (id->t_extended1 == 2 && datain == 0x1d) { 1067 id->t_extended1 = 1; 1068 return 0; 1069 } else if (id->t_extended1 == 1 && datain == 0x45) { 1070 id->t_extended1 = 0; 1071 datain = 0x7f; 1072 } else 1073 id->t_extended1 = 0; 1074 1075 if (id->t_translating != 0 || id->t_table == 1) { 1076 id->t_releasing = releasing; 1077 } else { 1078 /* id->t_releasing computed in pckbd_scancode_translate() */ 1079 } 1080 1081 /* map extended keys to (unused) codes 128-254 */ 1082 key = datain | id->t_extended; 1083 id->t_extended = 0; 1084 1085 if (id->t_releasing) { 1086 id->t_releasing = 0; 1087 id->t_lastchar = 0; 1088 *type = WSCONS_EVENT_KEY_UP; 1089 } else { 1090 /* Always ignore typematic keys */ 1091 if (key == id->t_lastchar) 1092 return 0; 1093 id->t_lastchar = key; 1094 *type = WSCONS_EVENT_KEY_DOWN; 1095 } 1096 1097 *dataout = key; 1098 return 1; 1099 } 1100 1101 void 1102 pckbd_init(struct pckbd_internal *t, pckbc_tag_t kbctag, pckbc_slot_t kbcslot, 1103 int console) 1104 { 1105 bzero(t, sizeof(struct pckbd_internal)); 1106 1107 t->t_isconsole = console; 1108 t->t_kbctag = kbctag; 1109 t->t_kbcslot = kbcslot; 1110 } 1111 1112 static int 1113 pckbd_led_encode(int led) 1114 { 1115 int res; 1116 1117 res = 0; 1118 1119 if (led & WSKBD_LED_SCROLL) 1120 res |= 0x01; 1121 if (led & WSKBD_LED_NUM) 1122 res |= 0x02; 1123 if (led & WSKBD_LED_CAPS) 1124 res |= 0x04; 1125 return(res); 1126 } 1127 1128 void 1129 pckbd_set_leds(void *v, int leds) 1130 { 1131 struct pckbd_softc *sc = v; 1132 u_char cmd[2]; 1133 1134 cmd[0] = KBC_MODEIND; 1135 cmd[1] = pckbd_led_encode(leds); 1136 sc->sc_ledstate = leds; 1137 1138 (void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 1139 cmd, 2, 0, 0, 0); 1140 } 1141 1142 /* 1143 * Got a console receive interrupt - 1144 * the console processor wants to give us a character. 1145 */ 1146 void 1147 pckbd_input(void *vsc, int data) 1148 { 1149 struct pckbd_softc *sc = vsc; 1150 int rc, type, key; 1151 1152 data = pckbd_scancode_translate(sc->id, data); 1153 if (data == 0) 1154 return; 1155 1156 rc = pckbd_decode(sc->id, data, &type, &key); 1157 1158 #ifdef WSDISPLAY_COMPAT_RAWKBD 1159 if (sc->rawkbd) { 1160 sc->sc_rawbuf[sc->sc_rawcnt++] = (char)data; 1161 1162 if (rc != 0 || sc->sc_rawcnt == sizeof(sc->sc_rawbuf)) { 1163 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rawbuf, 1164 sc->sc_rawcnt); 1165 sc->sc_rawcnt = 0; 1166 } 1167 1168 /* 1169 * Pass audio keys to wskbd_input anyway. 1170 */ 1171 if (rc == 0 || (key != 160 && key != 174 && key != 176)) 1172 return; 1173 } 1174 #endif 1175 if (rc != 0) 1176 wskbd_input(sc->sc_wskbddev, type, key); 1177 } 1178 1179 int 1180 pckbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 1181 { 1182 struct pckbd_softc *sc = v; 1183 1184 switch (cmd) { 1185 case WSKBDIO_GTYPE: 1186 *(int *)data = WSKBD_TYPE_PC_XT; 1187 return 0; 1188 case WSKBDIO_SETLEDS: { 1189 char cmd[2]; 1190 int res; 1191 cmd[0] = KBC_MODEIND; 1192 cmd[1] = pckbd_led_encode(*(int *)data); 1193 sc->sc_ledstate = *(int *)data & (WSKBD_LED_SCROLL | 1194 WSKBD_LED_NUM | WSKBD_LED_CAPS); 1195 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 1196 cmd, 2, 0, 1, 0); 1197 return (res); 1198 } 1199 case WSKBDIO_GETLEDS: 1200 *(int *)data = sc->sc_ledstate; 1201 return (0); 1202 case WSKBDIO_COMPLEXBELL: 1203 #define d ((struct wskbd_bell_data *)data) 1204 /* 1205 * Keyboard can't beep directly; we have an 1206 * externally-provided global hook to do this. 1207 */ 1208 pckbd_bell(d->pitch, d->period, d->volume, 0); 1209 #undef d 1210 return (0); 1211 #ifdef WSDISPLAY_COMPAT_RAWKBD 1212 case WSKBDIO_SETMODE: 1213 sc->rawkbd = (*(int *)data == WSKBD_RAW); 1214 return (0); 1215 #endif 1216 } 1217 return -1; 1218 } 1219 1220 void 1221 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll) 1222 { 1223 1224 if (pckbd_bell_fn != NULL) 1225 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 1226 volume, poll); 1227 } 1228 1229 void 1230 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 1231 { 1232 1233 if (pckbd_bell_fn == NULL) { 1234 pckbd_bell_fn = fn; 1235 pckbd_bell_fn_arg = arg; 1236 } 1237 } 1238 1239 int 1240 pckbd_cnattach(pckbc_tag_t kbctag) 1241 { 1242 pckbd_init(&pckbd_consdata, kbctag, PCKBC_KBD_SLOT, 1); 1243 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 1244 return (0); 1245 } 1246 1247 void 1248 pckbd_cngetc(void *v, u_int *type, int *data) 1249 { 1250 struct pckbd_internal *t = v; 1251 int val; 1252 1253 for (;;) { 1254 val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot); 1255 if (val == -1) 1256 continue; 1257 1258 val = pckbd_scancode_translate(t, val); 1259 if (val == 0) 1260 continue; 1261 1262 if (pckbd_decode(t, val, type, data)) 1263 return; 1264 } 1265 } 1266 1267 void 1268 pckbd_cnpollc(void *v, int on) 1269 { 1270 struct pckbd_internal *t = v; 1271 1272 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on); 1273 1274 /* 1275 * If we enter ukc or ddb before having attached the console 1276 * keyboard we need to probe its scan code set. 1277 */ 1278 if (t->t_table == 0) { 1279 char cmd[1]; 1280 1281 pckbc_flush(t->t_kbctag, t->t_kbcslot); 1282 pckbd_set_xtscancode(t->t_kbctag, t->t_kbcslot, t); 1283 1284 /* Just to be sure. */ 1285 cmd[0] = KBC_ENABLE; 1286 pckbc_poll_cmd(t->t_kbctag, PCKBC_KBD_SLOT, cmd, 1, 0, NULL, 0); 1287 } 1288 } 1289 1290 void 1291 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 1292 { 1293 1294 pckbd_bell(pitch, period, volume, 1); 1295 } 1296 1297 struct cfdriver pckbd_cd = { 1298 NULL, "pckbd", DV_DULL 1299 }; 1300