1 /* $OpenBSD: pckbd.c,v 1.45 2018/05/22 10:53:47 mpi 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/wskbdvar.h> 85 #include <dev/wscons/wsksymdef.h> 86 #include <dev/wscons/wsksymvar.h> 87 88 #include <dev/pckbc/wskbdmap_mfii.h> 89 90 struct pckbd_internal { 91 int t_isconsole; 92 pckbc_tag_t t_kbctag; 93 pckbc_slot_t t_kbcslot; 94 95 int t_translating; 96 int t_table; 97 98 int t_lastchar; 99 int t_extended; 100 int t_extended1; 101 int t_releasing; 102 103 struct pckbd_softc *t_sc; /* back pointer */ 104 }; 105 106 struct pckbd_softc { 107 struct device sc_dev; 108 109 struct pckbd_internal *id; 110 int sc_enabled; 111 112 int sc_ledstate; 113 114 struct device *sc_wskbddev; 115 #ifdef WSDISPLAY_COMPAT_RAWKBD 116 int rawkbd; 117 u_int sc_rawcnt; 118 char sc_rawbuf[3]; 119 #endif 120 }; 121 122 static int pckbd_is_console(pckbc_tag_t, pckbc_slot_t); 123 124 int pckbdprobe(struct device *, void *, void *); 125 void pckbdattach(struct device *, struct device *, void *); 126 int pckbdactivate(struct device *, int); 127 128 struct cfattach pckbd_ca = { 129 sizeof(struct pckbd_softc), 130 pckbdprobe, 131 pckbdattach, 132 NULL, 133 pckbdactivate 134 }; 135 136 int pckbd_enable(void *, int); 137 void pckbd_set_leds(void *, int); 138 int pckbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 139 140 const struct wskbd_accessops pckbd_accessops = { 141 pckbd_enable, 142 pckbd_set_leds, 143 pckbd_ioctl, 144 }; 145 146 void pckbd_cngetc(void *, u_int *, int *); 147 void pckbd_cnpollc(void *, int); 148 void pckbd_cnbell(void *, u_int, u_int, u_int); 149 150 const struct wskbd_consops pckbd_consops = { 151 pckbd_cngetc, 152 pckbd_cnpollc, 153 pckbd_cnbell, 154 }; 155 156 const struct wskbd_mapdata pckbd_keymapdata = { 157 pckbd_keydesctab, 158 #ifdef PCKBD_LAYOUT 159 PCKBD_LAYOUT, 160 #else 161 KB_US | KB_DEFAULT, 162 #endif 163 }; 164 165 /* 166 * Hackish support for a bell on the PC Keyboard; when a suitable feeper 167 * is found, it attaches itself into the pckbd driver here. 168 */ 169 void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int); 170 void *pckbd_bell_fn_arg; 171 172 void pckbd_bell(u_int, u_int, u_int, int); 173 174 int pckbd_scancode_translate(struct pckbd_internal *, int); 175 int pckbd_set_xtscancode(pckbc_tag_t, pckbc_slot_t, 176 struct pckbd_internal *); 177 void pckbd_init(struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t, int); 178 void pckbd_input(void *, int); 179 180 static int pckbd_decode(struct pckbd_internal *, int, 181 u_int *, int *); 182 static int pckbd_led_encode(int); 183 184 struct pckbd_internal pckbd_consdata; 185 186 int 187 pckbdactivate(struct device *self, int act) 188 { 189 struct pckbd_softc *sc = (struct pckbd_softc *)self; 190 int rv = 0; 191 u_char cmd[1]; 192 193 switch(act) { 194 case DVACT_RESUME: 195 if (sc->sc_enabled) { 196 /* 197 * Some keyboards are not enabled after a reset, 198 * so make sure it is enabled now. 199 */ 200 cmd[0] = KBC_ENABLE; 201 (void) pckbc_poll_cmd(sc->id->t_kbctag, 202 sc->id->t_kbcslot, cmd, 1, 0, NULL, 0); 203 /* XXX - also invoke pckbd_set_xtscancode() too? */ 204 } 205 break; 206 } 207 208 rv = config_activate_children(self, act); 209 210 return (rv); 211 } 212 213 int 214 pckbd_set_xtscancode(pckbc_tag_t kbctag, pckbc_slot_t kbcslot, 215 struct pckbd_internal *id) 216 { 217 int table = 3; 218 219 if (pckbc_xt_translation(kbctag)) { 220 #ifdef DEBUG 221 printf("pckbd: enabling of translation failed\n"); 222 #endif 223 /* 224 * Since the keyboard controller can not translate scan 225 * codes to the XT set (#1), we would like to request 226 * this exact set. However it is likely that the 227 * controller does not support it either. 228 * 229 * So try scan code set #2 as well, which this driver 230 * knows how to translate. 231 */ 232 table = 2; 233 if (id != NULL) 234 id->t_translating = 0; 235 } else { 236 if (id != NULL) { 237 id->t_translating = 1; 238 if (id->t_table == 0) { 239 /* 240 * Don't bother explicitly setting into set 2, 241 * it's the default. 242 */ 243 id->t_table = 2; 244 return (0); 245 } 246 } 247 } 248 249 /* keep falling back until we hit a table that looks usable. */ 250 for (; table >= 1; table--) { 251 u_char cmd[2]; 252 #ifdef DEBUG 253 printf("pckbd: trying table %d\n", table); 254 #endif 255 cmd[0] = KBC_SETTABLE; 256 cmd[1] = table; 257 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, NULL, 0)) { 258 #ifdef DEBUG 259 printf("pckbd: table set of %d failed\n", table); 260 #endif 261 if (table > 1) { 262 cmd[0] = KBC_RESET; 263 (void)pckbc_poll_cmd(kbctag, kbcslot, cmd, 264 1, 1, NULL, 1); 265 pckbc_flush(kbctag, kbcslot); 266 267 continue; 268 } 269 } 270 271 /* 272 * the 8042 took the table set request, however, not all that 273 * report they can work with table 3 actually work, so ask what 274 * table it reports it's in. 275 */ 276 if (table == 3) { 277 u_char resp[1]; 278 279 cmd[0] = KBC_SETTABLE; 280 cmd[1] = 0; 281 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 1, resp, 0)) { 282 /* 283 * query failed, step down to table 2 to be 284 * safe. 285 */ 286 #ifdef DEBUG 287 printf("pckbd: table 3 verification failed\n"); 288 #endif 289 continue; 290 } else if (resp[0] == 3) { 291 #ifdef DEBUG 292 printf("pckbd: settling on table 3\n"); 293 #endif 294 break; 295 } 296 #ifdef DEBUG 297 else 298 printf("pckbd: table \"%x\" != 3, trying 2\n", 299 resp[0]); 300 #endif 301 } else { 302 #ifdef DEBUG 303 printf("pckbd: settling on table %d\n", table); 304 #endif 305 break; 306 } 307 } 308 309 if (table == 0) 310 return (1); 311 312 if (id != NULL) 313 id->t_table = table; 314 315 return (0); 316 } 317 318 static int 319 pckbd_is_console(pckbc_tag_t tag, pckbc_slot_t slot) 320 { 321 return (pckbd_consdata.t_isconsole && 322 (tag == pckbd_consdata.t_kbctag) && 323 (slot == pckbd_consdata.t_kbcslot)); 324 } 325 326 /* 327 * these are both bad jokes 328 */ 329 int 330 pckbdprobe(struct device *parent, void *match, void *aux) 331 { 332 struct cfdata *cf = match; 333 struct pckbc_attach_args *pa = aux; 334 u_char cmd[1], resp[1]; 335 int res; 336 337 /* 338 * XXX There are rumours that a keyboard can be connected 339 * to the aux port as well. For me, this didn't work. 340 * For further experiments, allow it if explicitly 341 * wired in the config file. 342 */ 343 if ((pa->pa_slot != PCKBC_KBD_SLOT) && 344 (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT)) 345 return (0); 346 347 /* Flush any garbage. */ 348 pckbc_flush(pa->pa_tag, pa->pa_slot); 349 350 /* Reset the keyboard. */ 351 cmd[0] = KBC_RESET; 352 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1); 353 if (res) { 354 #ifdef DEBUG 355 printf("pckbdprobe: reset error %d\n", res); 356 #endif 357 /* 358 * There is probably no keyboard connected. 359 * Let the probe succeed if the keyboard is used 360 * as console input - it can be connected later. 361 */ 362 #if defined(__i386__) || defined(__amd64__) 363 /* 364 * However, on legacy-free PCs, there might really 365 * be no PS/2 connector at all; in that case, do not 366 * even try to attach; ukbd will take over as console. 367 */ 368 if (res == ENXIO) { 369 /* check cf_flags from parent */ 370 struct cfdata *cf = parent->dv_cfdata; 371 if (!ISSET(cf->cf_flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) 372 return 0; 373 } 374 #endif 375 return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0); 376 } 377 if (resp[0] != KBR_RSTDONE) { 378 printf("pckbdprobe: reset response 0x%x\n", resp[0]); 379 return (0); 380 } 381 382 /* 383 * Some keyboards seem to leave a second ack byte after the reset. 384 * This is kind of stupid, but we account for them anyway by just 385 * flushing the buffer. 386 */ 387 pckbc_flush(pa->pa_tag, pa->pa_slot); 388 389 return (2); 390 } 391 392 void 393 pckbdattach(struct device *parent, struct device *self, void *aux) 394 { 395 struct pckbd_softc *sc = (void *)self; 396 struct pckbc_attach_args *pa = aux; 397 int isconsole; 398 struct wskbddev_attach_args a; 399 u_char cmd[1]; 400 401 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot); 402 403 if (isconsole) { 404 sc->id = &pckbd_consdata; 405 if (sc->id->t_table == 0) 406 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id); 407 408 /* 409 * Some keyboards are not enabled after a reset, 410 * so make sure it is enabled now. 411 */ 412 cmd[0] = KBC_ENABLE; 413 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 414 cmd, 1, 0, NULL, 0); 415 sc->sc_enabled = 1; 416 } else { 417 sc->id = malloc(sizeof(struct pckbd_internal), 418 M_DEVBUF, M_WAITOK); 419 pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0); 420 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id); 421 422 /* no interrupts until enabled */ 423 cmd[0] = KBC_DISABLE; 424 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 425 cmd, 1, 0, NULL, 0); 426 sc->sc_enabled = 0; 427 } 428 429 sc->id->t_sc = sc; 430 431 pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot, 432 pckbd_input, sc, sc->sc_dev.dv_xname); 433 434 a.console = isconsole; 435 436 a.keymap = &pckbd_keymapdata; 437 438 a.accessops = &pckbd_accessops; 439 a.accesscookie = sc; 440 441 printf("\n"); 442 443 /* 444 * Attach the wskbd, saving a handle to it. 445 */ 446 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 447 } 448 449 int 450 pckbd_enable(void *v, int on) 451 { 452 struct pckbd_softc *sc = v; 453 u_char cmd[1]; 454 int res; 455 456 if (on) { 457 if (sc->sc_enabled) 458 return (EBUSY); 459 460 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 461 462 cmd[0] = KBC_ENABLE; 463 res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 464 cmd, 1, 0, NULL, 0); 465 if (res) { 466 printf("pckbd_enable: command error\n"); 467 return (res); 468 } 469 470 res = pckbd_set_xtscancode(sc->id->t_kbctag, 471 sc->id->t_kbcslot, sc->id); 472 if (res) 473 return (res); 474 475 sc->sc_enabled = 1; 476 } else { 477 if (sc->id->t_isconsole) 478 return (EBUSY); 479 480 cmd[0] = KBC_DISABLE; 481 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 482 cmd, 1, 0, 1, 0); 483 if (res) { 484 printf("pckbd_disable: command error\n"); 485 return (res); 486 } 487 488 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 489 490 sc->sc_enabled = 0; 491 } 492 493 return (0); 494 } 495 496 const u_int8_t pckbd_xtbl[] = { 497 /* 0x00 */ 498 0, 499 0x43, /* F9 */ 500 0, 501 0x3f, /* F5 */ 502 0x3d, /* F3 */ 503 0x3b, /* F1 */ 504 0x3c, /* F2 */ 505 0x58, /* F12 */ 506 0x40, /* F6 according to documentation */ 507 0x44, /* F10 */ 508 0x42, /* F8 */ 509 0x40, /* F6 according to experimentation */ 510 0x3e, /* F4 */ 511 0x0f, /* Tab */ 512 0x29, /* ` ~ */ 513 0, 514 /* 0x10 */ 515 0, 516 0x38, /* Left Alt */ 517 0x2a, /* Left Shift */ 518 0, 519 0x1d, /* Left Ctrl */ 520 0x10, /* q */ 521 0x02, /* 1 ! */ 522 0, 523 0, 524 0, 525 0x2c, /* z */ 526 0x1f, /* s */ 527 0x1e, /* a */ 528 0x11, /* w */ 529 0x03, /* 2 @ */ 530 0, 531 /* 0x20 */ 532 0, 533 0x2e, /* c */ 534 0x2d, /* x */ 535 0x20, /* d */ 536 0x12, /* e */ 537 0x05, /* 4 $ */ 538 0x04, /* 3 # */ 539 0, 540 0, 541 0x39, /* Space */ 542 0x2f, /* v */ 543 0x21, /* f */ 544 0x14, /* t */ 545 0x13, /* r */ 546 0x06, /* 5 % */ 547 0, 548 /* 0x30 */ 549 0, 550 0x31, /* n */ 551 0x30, /* b */ 552 0x23, /* h */ 553 0x22, /* g */ 554 0x15, /* y */ 555 0x07, /* 6 ^ */ 556 0, 557 0, 558 0, 559 0x32, /* m */ 560 0x24, /* j */ 561 0x16, /* u */ 562 0x08, /* 7 & */ 563 0x09, /* 8 * */ 564 0, 565 /* 0x40 */ 566 0, 567 0x33, /* , < */ 568 0x25, /* k */ 569 0x17, /* i */ 570 0x18, /* o */ 571 0x0b, /* 0 ) */ 572 0x0a, /* 9 ( */ 573 0, 574 0, 575 0x34, /* . > */ 576 0x35, /* / ? */ 577 0x26, /* l */ 578 0x27, /* ; : */ 579 0x19, /* p */ 580 0x0c, /* - _ */ 581 0, 582 /* 0x50 */ 583 0, 584 0, 585 0x28, /* ' " */ 586 0, 587 0x1a, /* [ { */ 588 0x0d, /* = + */ 589 0, 590 0, 591 0x3a, /* Caps Lock */ 592 0x36, /* Right Shift */ 593 0x1c, /* Return */ 594 0x1b, /* ] } */ 595 0, 596 0x2b, /* \ | */ 597 0, 598 0, 599 /* 0x60 */ 600 0, 601 0, 602 0, 603 0, 604 0, 605 0, 606 0x0e, /* Back Space */ 607 0, 608 0, 609 0x4f, /* KP 1 */ 610 0, 611 0x4b, /* KP 4 */ 612 0x47, /* KP 7 */ 613 0, 614 0, 615 0, 616 /* 0x70 */ 617 0x52, /* KP 0 */ 618 0x53, /* KP . */ 619 0x50, /* KP 2 */ 620 0x4c, /* KP 5 */ 621 0x4d, /* KP 6 */ 622 0x48, /* KP 8 */ 623 0x01, /* Escape */ 624 0x45, /* Num Lock */ 625 0x57, /* F11 */ 626 0x4e, /* KP + */ 627 0x51, /* KP 3 */ 628 0x4a, /* KP - */ 629 0x37, /* KP * */ 630 0x49, /* KP 9 */ 631 0x46, /* Scroll Lock */ 632 0, 633 /* 0x80 */ 634 0, 635 0, 636 0, 637 0x41, /* F7 (produced as an actual 8 bit code) */ 638 0 /* Alt-Print Screen */ 639 }; 640 641 const u_int8_t pckbd_xtbl_ext[] = { 642 /* 0x00 */ 643 0, 644 0, 645 0, 646 0, 647 0, 648 0, 649 0, 650 0, 651 0, 652 0, 653 0, 654 0, 655 0, 656 0, 657 0, 658 /* 0x10 */ 659 0, 660 0x38, /* Right Alt */ 661 0, /* E0 12, to be ignored */ 662 0, 663 0x1d, /* Right Ctrl */ 664 0, 665 0, 666 0, 667 0, 668 0, 669 0, 670 0, 671 0, 672 0, 673 0, 674 0, 675 /* 0x20 */ 676 0, 677 0, 678 0, 679 0, 680 0, 681 0, 682 0, 683 0, 684 0, 685 0, 686 0, 687 0, 688 0, 689 0, 690 0, 691 0, 692 /* 0x30 */ 693 0, 694 0, 695 0, 696 0, 697 0, 698 0, 699 0, 700 0, 701 0, 702 0, 703 0, 704 0, 705 0, 706 0, 707 0, 708 0, 709 /* 0x40 */ 710 0, 711 0, 712 0, 713 0, 714 0, 715 0, 716 0, 717 0, 718 0, 719 0, 720 0x55, /* KP / */ 721 0, 722 0, 723 0, 724 0, 725 0, 726 /* 0x50 */ 727 0, 728 0, 729 0, 730 0, 731 0, 732 0, 733 0, 734 0, 735 0, 736 0, 737 0x1c, /* KP Return */ 738 0, 739 0, 740 0, 741 0, 742 0, 743 /* 0x60 */ 744 0, 745 0, 746 0, 747 0, 748 0, 749 0, 750 0, 751 0, 752 0, 753 0x4f, /* End */ 754 0, 755 0x4b, /* Left */ 756 0x47, /* Home */ 757 0, 758 0, 759 0, 760 /* 0x70 */ 761 0x52, /* Insert */ 762 0x53, /* Delete */ 763 0x50, /* Down */ 764 0, 765 0x4d, /* Right */ 766 0x48, /* Up */ 767 0, 768 0, 769 0, 770 0, 771 0x51, /* Page Down */ 772 0, 773 0x37, /* Print Screen */ 774 0x49, /* Page Up */ 775 0x46, /* Ctrl-Break */ 776 0 777 }; 778 779 /* 780 * Translate scan codes from set 2 to set 1 781 */ 782 int 783 pckbd_scancode_translate(struct pckbd_internal *id, int datain) 784 { 785 if (id->t_translating != 0 || id->t_table == 1) 786 return datain; 787 788 if (datain == KBR_BREAK) { 789 id->t_releasing = 0x80; /* next keycode is a release */ 790 return 0; /* consume scancode */ 791 } 792 793 /* 794 * Convert BREAK sequence (14 77 -> 1D 45) 795 */ 796 if (id->t_extended1 == 2 && datain == 0x14) 797 return 0x1d | id->t_releasing; 798 else if (id->t_extended1 == 1 && datain == 0x77) 799 return 0x45 | id->t_releasing; 800 801 if (id->t_extended != 0) { 802 if (datain >= sizeof pckbd_xtbl_ext) 803 datain = 0; 804 else 805 datain = pckbd_xtbl_ext[datain]; 806 } else { 807 if (datain >= sizeof pckbd_xtbl) 808 datain = 0; 809 else 810 datain = pckbd_xtbl[datain]; 811 } 812 813 if (datain == 0) { 814 /* 815 * We don't know how to translate this scan code, but 816 * we can't silently eat it either (because there might 817 * have been an extended byte transmitted already). 818 * Hopefully this value will be harmless to the upper 819 * layers. 820 */ 821 return 0xff; 822 } 823 824 return datain | id->t_releasing; 825 } 826 827 static int 828 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) 829 { 830 int key; 831 int releasing; 832 833 if (datain == KBR_EXTENDED0) { 834 id->t_extended = 0x80; 835 return 0; 836 } else if (datain == KBR_EXTENDED1) { 837 id->t_extended1 = 2; 838 return 0; 839 } 840 841 releasing = datain & 0x80; 842 datain &= 0x7f; 843 844 /* 845 * process BREAK key sequence (EXT1 1D 45 / EXT1 9D C5): 846 * map to (unused) code 7F 847 */ 848 if (id->t_extended1 == 2 && datain == 0x1d) { 849 id->t_extended1 = 1; 850 return 0; 851 } else if (id->t_extended1 == 1 && datain == 0x45) { 852 id->t_extended1 = 0; 853 datain = 0x7f; 854 } else 855 id->t_extended1 = 0; 856 857 if (id->t_translating != 0 || id->t_table == 1) { 858 id->t_releasing = releasing; 859 } else { 860 /* id->t_releasing computed in pckbd_scancode_translate() */ 861 } 862 863 /* map extended keys to (unused) codes 128-254 */ 864 key = datain | id->t_extended; 865 id->t_extended = 0; 866 867 if (id->t_releasing) { 868 id->t_releasing = 0; 869 id->t_lastchar = 0; 870 *type = WSCONS_EVENT_KEY_UP; 871 } else { 872 /* Always ignore typematic keys */ 873 if (key == id->t_lastchar) 874 return 0; 875 id->t_lastchar = key; 876 *type = WSCONS_EVENT_KEY_DOWN; 877 } 878 879 *dataout = key; 880 return 1; 881 } 882 883 void 884 pckbd_init(struct pckbd_internal *t, pckbc_tag_t kbctag, pckbc_slot_t kbcslot, 885 int console) 886 { 887 bzero(t, sizeof(struct pckbd_internal)); 888 889 t->t_isconsole = console; 890 t->t_kbctag = kbctag; 891 t->t_kbcslot = kbcslot; 892 } 893 894 static int 895 pckbd_led_encode(int led) 896 { 897 int res; 898 899 res = 0; 900 901 if (led & WSKBD_LED_SCROLL) 902 res |= 0x01; 903 if (led & WSKBD_LED_NUM) 904 res |= 0x02; 905 if (led & WSKBD_LED_CAPS) 906 res |= 0x04; 907 return(res); 908 } 909 910 void 911 pckbd_set_leds(void *v, int leds) 912 { 913 struct pckbd_softc *sc = v; 914 u_char cmd[2]; 915 916 cmd[0] = KBC_MODEIND; 917 cmd[1] = pckbd_led_encode(leds); 918 sc->sc_ledstate = leds; 919 920 (void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 921 cmd, 2, 0, 0, 0); 922 } 923 924 /* 925 * Got a console receive interrupt - 926 * the console processor wants to give us a character. 927 */ 928 void 929 pckbd_input(void *vsc, int data) 930 { 931 struct pckbd_softc *sc = vsc; 932 int rc, type, key; 933 934 data = pckbd_scancode_translate(sc->id, data); 935 if (data == 0) 936 return; 937 938 rc = pckbd_decode(sc->id, data, &type, &key); 939 940 #ifdef WSDISPLAY_COMPAT_RAWKBD 941 if (sc->rawkbd) { 942 sc->sc_rawbuf[sc->sc_rawcnt++] = (char)data; 943 944 if (rc != 0 || sc->sc_rawcnt == sizeof(sc->sc_rawbuf)) { 945 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rawbuf, 946 sc->sc_rawcnt); 947 sc->sc_rawcnt = 0; 948 } 949 950 /* 951 * Pass audio keys to wskbd_input anyway. 952 */ 953 if (rc == 0 || (key != 160 && key != 174 && key != 176)) 954 return; 955 } 956 #endif 957 if (rc != 0) 958 wskbd_input(sc->sc_wskbddev, type, key); 959 } 960 961 int 962 pckbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 963 { 964 struct pckbd_softc *sc = v; 965 966 switch (cmd) { 967 case WSKBDIO_GTYPE: 968 *(int *)data = WSKBD_TYPE_PC_XT; 969 return 0; 970 case WSKBDIO_SETLEDS: { 971 char cmd[2]; 972 int res; 973 cmd[0] = KBC_MODEIND; 974 cmd[1] = pckbd_led_encode(*(int *)data); 975 sc->sc_ledstate = *(int *)data & (WSKBD_LED_SCROLL | 976 WSKBD_LED_NUM | WSKBD_LED_CAPS); 977 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 978 cmd, 2, 0, 1, 0); 979 return (res); 980 } 981 case WSKBDIO_GETLEDS: 982 *(int *)data = sc->sc_ledstate; 983 return (0); 984 case WSKBDIO_COMPLEXBELL: 985 #define d ((struct wskbd_bell_data *)data) 986 /* 987 * Keyboard can't beep directly; we have an 988 * externally-provided global hook to do this. 989 */ 990 pckbd_bell(d->pitch, d->period, d->volume, 0); 991 #undef d 992 return (0); 993 #ifdef WSDISPLAY_COMPAT_RAWKBD 994 case WSKBDIO_SETMODE: 995 sc->rawkbd = (*(int *)data == WSKBD_RAW); 996 return (0); 997 #endif 998 } 999 return -1; 1000 } 1001 1002 void 1003 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll) 1004 { 1005 1006 if (pckbd_bell_fn != NULL) 1007 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 1008 volume, poll); 1009 } 1010 1011 void 1012 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 1013 { 1014 1015 if (pckbd_bell_fn == NULL) { 1016 pckbd_bell_fn = fn; 1017 pckbd_bell_fn_arg = arg; 1018 } 1019 } 1020 1021 int 1022 pckbd_cnattach(pckbc_tag_t kbctag) 1023 { 1024 1025 pckbd_init(&pckbd_consdata, kbctag, PCKBC_KBD_SLOT, 1); 1026 1027 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 1028 1029 return (0); 1030 } 1031 1032 /* ARGSUSED */ 1033 void 1034 pckbd_cngetc(void *v, u_int *type, int *data) 1035 { 1036 struct pckbd_internal *t = v; 1037 int val; 1038 1039 for (;;) { 1040 val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot); 1041 if (val == -1) 1042 continue; 1043 1044 val = pckbd_scancode_translate(t, val); 1045 if (val == 0) 1046 continue; 1047 1048 if (pckbd_decode(t, val, type, data)) 1049 return; 1050 } 1051 } 1052 1053 void 1054 pckbd_cnpollc(void *v, int on) 1055 { 1056 struct pckbd_internal *t = v; 1057 1058 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on); 1059 1060 /* 1061 * If we enter ukc or ddb before having attached the console 1062 * keyboard we need to probe its scan code set. 1063 */ 1064 if (t->t_table == 0) { 1065 char cmd[1]; 1066 1067 pckbc_flush(t->t_kbctag, t->t_kbcslot); 1068 pckbd_set_xtscancode(t->t_kbctag, t->t_kbcslot, t); 1069 1070 /* Just to be sure. */ 1071 cmd[0] = KBC_ENABLE; 1072 pckbc_poll_cmd(t->t_kbctag, PCKBC_KBD_SLOT, cmd, 1, 0, NULL, 0); 1073 } 1074 } 1075 1076 void 1077 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 1078 { 1079 1080 pckbd_bell(pitch, period, volume, 1); 1081 } 1082 1083 struct cfdriver pckbd_cd = { 1084 NULL, "pckbd", DV_DULL 1085 }; 1086