1 /* $OpenBSD: pckbd.c,v 1.43 2016/04/14 07:06:03 mlarkin 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 /* default to have the 8042 translate the keyboard with table 3. */ 218 int table = 3; 219 220 if (pckbc_xt_translation(kbctag)) { 221 #ifdef DEBUG 222 printf("pckbd: enabling of translation failed\n"); 223 #endif 224 /* 225 * Since the keyboard controller can not translate scan 226 * codes to the XT set (#1), we would like to request 227 * this exact set. However it is likely that the 228 * controller does not support it either. 229 * 230 * So try scan code set #2 as well, which this driver 231 * knows how to translate. 232 */ 233 table = 2; 234 if (id != NULL) 235 id->t_translating = 0; 236 } else { 237 if (id != NULL) 238 id->t_translating = 1; 239 } 240 241 /* keep falling back until we hit a table that looks usable. */ 242 for (; table >= 1; table--) { 243 u_char cmd[2]; 244 #ifdef DEBUG 245 printf("pckbd: trying table %d\n", table); 246 #endif 247 cmd[0] = KBC_SETTABLE; 248 cmd[1] = table; 249 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, NULL, 0)) { 250 #ifdef DEBUG 251 printf("pckbd: table set of %d failed\n", table); 252 #endif 253 if (table > 1) { 254 cmd[0] = KBC_RESET; 255 (void)pckbc_poll_cmd(kbctag, kbcslot, cmd, 256 1, 1, NULL, 1); 257 pckbc_flush(kbctag, kbcslot); 258 259 continue; 260 } 261 } 262 263 /* 264 * the 8042 took the table set request, however, not all that 265 * report they can work with table 3 actually work, so ask what 266 * table it reports it's in. 267 */ 268 if (table == 3) { 269 u_char resp[1]; 270 271 cmd[0] = KBC_SETTABLE; 272 cmd[1] = 0; 273 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 1, resp, 0)) { 274 /* 275 * query failed, step down to table 2 to be 276 * safe. 277 */ 278 #ifdef DEBUG 279 printf("pckbd: table 3 verification failed\n"); 280 #endif 281 continue; 282 } else if (resp[0] == 3) { 283 #ifdef DEBUG 284 printf("pckbd: settling on table 3\n"); 285 #endif 286 break; 287 } 288 #ifdef DEBUG 289 else 290 printf("pckbd: table \"%x\" != 3, trying 2\n", 291 resp[0]); 292 #endif 293 } else { 294 #ifdef DEBUG 295 printf("pckbd: settling on table %d\n", table); 296 #endif 297 break; 298 } 299 } 300 301 if (table == 0) 302 return (1); 303 304 if (id != NULL) 305 id->t_table = table; 306 307 return (0); 308 } 309 310 static int 311 pckbd_is_console(pckbc_tag_t tag, pckbc_slot_t slot) 312 { 313 return (pckbd_consdata.t_isconsole && 314 (tag == pckbd_consdata.t_kbctag) && 315 (slot == pckbd_consdata.t_kbcslot)); 316 } 317 318 /* 319 * these are both bad jokes 320 */ 321 int 322 pckbdprobe(struct device *parent, void *match, void *aux) 323 { 324 struct cfdata *cf = match; 325 struct pckbc_attach_args *pa = aux; 326 u_char cmd[1], resp[1]; 327 int res; 328 329 /* 330 * XXX There are rumours that a keyboard can be connected 331 * to the aux port as well. For me, this didn't work. 332 * For further experiments, allow it if explicitly 333 * wired in the config file. 334 */ 335 if ((pa->pa_slot != PCKBC_KBD_SLOT) && 336 (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT)) 337 return (0); 338 339 /* Flush any garbage. */ 340 pckbc_flush(pa->pa_tag, pa->pa_slot); 341 342 /* Reset the keyboard. */ 343 cmd[0] = KBC_RESET; 344 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1); 345 if (res) { 346 #ifdef DEBUG 347 printf("pckbdprobe: reset error %d\n", res); 348 #endif 349 /* 350 * There is probably no keyboard connected. 351 * Let the probe succeed if the keyboard is used 352 * as console input - it can be connected later. 353 */ 354 #if defined(__i386__) || defined(__amd64__) 355 /* 356 * However, on legacy-free PCs, there might really 357 * be no PS/2 connector at all; in that case, do not 358 * even try to attach; ukbd will take over as console. 359 */ 360 if (res == ENXIO) { 361 /* check cf_flags from parent */ 362 struct cfdata *cf = parent->dv_cfdata; 363 if (!ISSET(cf->cf_flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) 364 return 0; 365 } 366 #endif 367 return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0); 368 } 369 if (resp[0] != KBR_RSTDONE) { 370 printf("pckbdprobe: reset response 0x%x\n", resp[0]); 371 return (0); 372 } 373 374 /* 375 * Some keyboards seem to leave a second ack byte after the reset. 376 * This is kind of stupid, but we account for them anyway by just 377 * flushing the buffer. 378 */ 379 pckbc_flush(pa->pa_tag, pa->pa_slot); 380 381 return (2); 382 } 383 384 void 385 pckbdattach(struct device *parent, struct device *self, void *aux) 386 { 387 struct pckbd_softc *sc = (void *)self; 388 struct pckbc_attach_args *pa = aux; 389 int isconsole; 390 struct wskbddev_attach_args a; 391 u_char cmd[1]; 392 393 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot); 394 395 if (isconsole) { 396 sc->id = &pckbd_consdata; 397 if (sc->id->t_table == 0) 398 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id); 399 400 /* 401 * Some keyboards are not enabled after a reset, 402 * so make sure it is enabled now. 403 */ 404 cmd[0] = KBC_ENABLE; 405 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 406 cmd, 1, 0, NULL, 0); 407 sc->sc_enabled = 1; 408 } else { 409 sc->id = malloc(sizeof(struct pckbd_internal), 410 M_DEVBUF, M_WAITOK); 411 pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0); 412 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id); 413 414 /* no interrupts until enabled */ 415 cmd[0] = KBC_DISABLE; 416 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 417 cmd, 1, 0, NULL, 0); 418 sc->sc_enabled = 0; 419 } 420 421 sc->id->t_sc = sc; 422 423 pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot, 424 pckbd_input, sc, sc->sc_dev.dv_xname); 425 426 a.console = isconsole; 427 428 a.keymap = &pckbd_keymapdata; 429 430 a.accessops = &pckbd_accessops; 431 a.accesscookie = sc; 432 433 printf("\n"); 434 435 /* 436 * Attach the wskbd, saving a handle to it. 437 */ 438 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 439 } 440 441 int 442 pckbd_enable(void *v, int on) 443 { 444 struct pckbd_softc *sc = v; 445 u_char cmd[1]; 446 int res; 447 448 if (on) { 449 if (sc->sc_enabled) 450 return (EBUSY); 451 452 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 453 454 cmd[0] = KBC_ENABLE; 455 res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 456 cmd, 1, 0, NULL, 0); 457 if (res) { 458 printf("pckbd_enable: command error\n"); 459 return (res); 460 } 461 462 res = pckbd_set_xtscancode(sc->id->t_kbctag, 463 sc->id->t_kbcslot, sc->id); 464 if (res) 465 return (res); 466 467 sc->sc_enabled = 1; 468 } else { 469 if (sc->id->t_isconsole) 470 return (EBUSY); 471 472 cmd[0] = KBC_DISABLE; 473 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 474 cmd, 1, 0, 1, 0); 475 if (res) { 476 printf("pckbd_disable: command error\n"); 477 return (res); 478 } 479 480 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 481 482 sc->sc_enabled = 0; 483 } 484 485 return (0); 486 } 487 488 const u_int8_t pckbd_xtbl[] = { 489 /* 0x00 */ 490 0, 491 0x43, /* F9 */ 492 0, 493 0x3f, /* F5 */ 494 0x3d, /* F3 */ 495 0x3b, /* F1 */ 496 0x3c, /* F2 */ 497 0x58, /* F12 */ 498 0x40, /* F6 according to documentation */ 499 0x44, /* F10 */ 500 0x42, /* F8 */ 501 0x40, /* F6 according to experimentation */ 502 0x3e, /* F4 */ 503 0x0f, /* Tab */ 504 0x29, /* ` ~ */ 505 0, 506 /* 0x10 */ 507 0, 508 0x38, /* Left Alt */ 509 0x2a, /* Left Shift */ 510 0, 511 0x1d, /* Left Ctrl */ 512 0x10, /* q */ 513 0x02, /* 1 ! */ 514 0, 515 0, 516 0, 517 0x2c, /* z */ 518 0x1f, /* s */ 519 0x1e, /* a */ 520 0x11, /* w */ 521 0x03, /* 2 @ */ 522 0, 523 /* 0x20 */ 524 0, 525 0x2e, /* c */ 526 0x2d, /* x */ 527 0x20, /* d */ 528 0x12, /* e */ 529 0x05, /* 4 $ */ 530 0x04, /* 3 # */ 531 0, 532 0, 533 0x39, /* Space */ 534 0x2f, /* v */ 535 0x21, /* f */ 536 0x14, /* t */ 537 0x13, /* r */ 538 0x06, /* 5 % */ 539 0, 540 /* 0x30 */ 541 0, 542 0x31, /* n */ 543 0x30, /* b */ 544 0x23, /* h */ 545 0x22, /* g */ 546 0x15, /* y */ 547 0x07, /* 6 ^ */ 548 0, 549 0, 550 0, 551 0x32, /* m */ 552 0x24, /* j */ 553 0x16, /* u */ 554 0x08, /* 7 & */ 555 0x09, /* 8 * */ 556 0, 557 /* 0x40 */ 558 0, 559 0x33, /* , < */ 560 0x25, /* k */ 561 0x17, /* i */ 562 0x18, /* o */ 563 0x0b, /* 0 ) */ 564 0x0a, /* 9 ( */ 565 0, 566 0, 567 0x34, /* . > */ 568 0x35, /* / ? */ 569 0x26, /* l */ 570 0x27, /* ; : */ 571 0x19, /* p */ 572 0x0c, /* - _ */ 573 0, 574 /* 0x50 */ 575 0, 576 0, 577 0x28, /* ' " */ 578 0, 579 0x1a, /* [ { */ 580 0x0d, /* = + */ 581 0, 582 0, 583 0x3a, /* Caps Lock */ 584 0x36, /* Right Shift */ 585 0x1c, /* Return */ 586 0x1b, /* ] } */ 587 0, 588 0x2b, /* \ | */ 589 0, 590 0, 591 /* 0x60 */ 592 0, 593 0, 594 0, 595 0, 596 0, 597 0, 598 0x0e, /* Back Space */ 599 0, 600 0, 601 0x4f, /* KP 1 */ 602 0, 603 0x4b, /* KP 4 */ 604 0x47, /* KP 7 */ 605 0, 606 0, 607 0, 608 /* 0x70 */ 609 0x52, /* KP 0 */ 610 0x53, /* KP . */ 611 0x50, /* KP 2 */ 612 0x4c, /* KP 5 */ 613 0x4d, /* KP 6 */ 614 0x48, /* KP 8 */ 615 0x01, /* Escape */ 616 0x45, /* Num Lock */ 617 0x57, /* F11 */ 618 0x4e, /* KP + */ 619 0x51, /* KP 3 */ 620 0x4a, /* KP - */ 621 0x37, /* KP * */ 622 0x49, /* KP 9 */ 623 0x46, /* Scroll Lock */ 624 0, 625 /* 0x80 */ 626 0, 627 0, 628 0, 629 0x41, /* F7 (produced as an actual 8 bit code) */ 630 0 /* Alt-Print Screen */ 631 }; 632 633 const u_int8_t pckbd_xtbl_ext[] = { 634 /* 0x00 */ 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 0, 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 0x55, /* 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 || id->t_table == 1) 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 * Convert BREAK sequence (14 77 -> 1D 45) 787 */ 788 if (id->t_extended1 == 2 && datain == 0x14) 789 return 0x1d | id->t_releasing; 790 else if (id->t_extended1 == 1 && datain == 0x77) 791 return 0x45 | id->t_releasing; 792 793 if (id->t_extended != 0) { 794 if (datain >= sizeof pckbd_xtbl_ext) 795 datain = 0; 796 else 797 datain = pckbd_xtbl_ext[datain]; 798 } else { 799 if (datain >= sizeof pckbd_xtbl) 800 datain = 0; 801 else 802 datain = pckbd_xtbl[datain]; 803 } 804 805 if (datain == 0) { 806 /* 807 * We don't know how to translate this scan code, but 808 * we can't silently eat it either (because there might 809 * have been an extended byte transmitted already). 810 * Hopefully this value will be harmless to the upper 811 * layers. 812 */ 813 return 0xff; 814 } 815 816 return datain | id->t_releasing; 817 } 818 819 static int 820 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) 821 { 822 int key; 823 int releasing; 824 825 if (datain == KBR_EXTENDED0) { 826 id->t_extended = 0x80; 827 return 0; 828 } else if (datain == KBR_EXTENDED1) { 829 id->t_extended1 = 2; 830 return 0; 831 } 832 833 releasing = datain & 0x80; 834 datain &= 0x7f; 835 836 /* 837 * process BREAK key sequence (EXT1 1D 45 / EXT1 9D C5): 838 * map to (unused) code 7F 839 */ 840 if (id->t_extended1 == 2 && datain == 0x1d) { 841 id->t_extended1 = 1; 842 return 0; 843 } else if (id->t_extended1 == 1 && datain == 0x45) { 844 id->t_extended1 = 0; 845 datain = 0x7f; 846 } else 847 id->t_extended1 = 0; 848 849 if (id->t_translating != 0 || id->t_table == 1) { 850 id->t_releasing = releasing; 851 } else { 852 /* id->t_releasing computed in pckbd_scancode_translate() */ 853 } 854 855 /* map extended keys to (unused) codes 128-254 */ 856 key = datain | id->t_extended; 857 id->t_extended = 0; 858 859 if (id->t_releasing) { 860 id->t_releasing = 0; 861 id->t_lastchar = 0; 862 *type = WSCONS_EVENT_KEY_UP; 863 } else { 864 /* Always ignore typematic keys */ 865 if (key == id->t_lastchar) 866 return 0; 867 id->t_lastchar = key; 868 *type = WSCONS_EVENT_KEY_DOWN; 869 } 870 871 *dataout = key; 872 return 1; 873 } 874 875 void 876 pckbd_init(struct pckbd_internal *t, pckbc_tag_t kbctag, pckbc_slot_t kbcslot, 877 int console) 878 { 879 bzero(t, sizeof(struct pckbd_internal)); 880 881 t->t_isconsole = console; 882 t->t_kbctag = kbctag; 883 t->t_kbcslot = kbcslot; 884 } 885 886 static int 887 pckbd_led_encode(int led) 888 { 889 int res; 890 891 res = 0; 892 893 if (led & WSKBD_LED_SCROLL) 894 res |= 0x01; 895 if (led & WSKBD_LED_NUM) 896 res |= 0x02; 897 if (led & WSKBD_LED_CAPS) 898 res |= 0x04; 899 return(res); 900 } 901 902 void 903 pckbd_set_leds(void *v, int leds) 904 { 905 struct pckbd_softc *sc = v; 906 u_char cmd[2]; 907 908 cmd[0] = KBC_MODEIND; 909 cmd[1] = pckbd_led_encode(leds); 910 sc->sc_ledstate = leds; 911 912 (void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 913 cmd, 2, 0, 0, 0); 914 } 915 916 /* 917 * Got a console receive interrupt - 918 * the console processor wants to give us a character. 919 */ 920 void 921 pckbd_input(void *vsc, int data) 922 { 923 struct pckbd_softc *sc = vsc; 924 int rc, type, key; 925 926 data = pckbd_scancode_translate(sc->id, data); 927 if (data == 0) 928 return; 929 930 rc = pckbd_decode(sc->id, data, &type, &key); 931 932 #ifdef WSDISPLAY_COMPAT_RAWKBD 933 if (sc->rawkbd) { 934 sc->sc_rawbuf[sc->sc_rawcnt++] = (char)data; 935 936 if (rc != 0 || sc->sc_rawcnt == sizeof(sc->sc_rawbuf)) { 937 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rawbuf, 938 sc->sc_rawcnt); 939 sc->sc_rawcnt = 0; 940 } 941 942 /* 943 * Pass audio keys to wskbd_input anyway. 944 */ 945 if (rc == 0 || (key != 160 && key != 174 && key != 176)) 946 return; 947 } 948 #endif 949 if (rc != 0) 950 wskbd_input(sc->sc_wskbddev, type, key); 951 } 952 953 int 954 pckbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 955 { 956 struct pckbd_softc *sc = v; 957 958 switch (cmd) { 959 case WSKBDIO_GTYPE: 960 *(int *)data = WSKBD_TYPE_PC_XT; 961 return 0; 962 case WSKBDIO_SETLEDS: { 963 char cmd[2]; 964 int res; 965 cmd[0] = KBC_MODEIND; 966 cmd[1] = pckbd_led_encode(*(int *)data); 967 sc->sc_ledstate = *(int *)data & (WSKBD_LED_SCROLL | 968 WSKBD_LED_NUM | WSKBD_LED_CAPS); 969 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 970 cmd, 2, 0, 1, 0); 971 return (res); 972 } 973 case WSKBDIO_GETLEDS: 974 *(int *)data = sc->sc_ledstate; 975 return (0); 976 case WSKBDIO_COMPLEXBELL: 977 #define d ((struct wskbd_bell_data *)data) 978 /* 979 * Keyboard can't beep directly; we have an 980 * externally-provided global hook to do this. 981 */ 982 pckbd_bell(d->pitch, d->period, d->volume, 0); 983 #undef d 984 return (0); 985 #ifdef WSDISPLAY_COMPAT_RAWKBD 986 case WSKBDIO_SETMODE: 987 sc->rawkbd = (*(int *)data == WSKBD_RAW); 988 return (0); 989 #endif 990 } 991 return -1; 992 } 993 994 void 995 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll) 996 { 997 998 if (pckbd_bell_fn != NULL) 999 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 1000 volume, poll); 1001 } 1002 1003 void 1004 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 1005 { 1006 1007 if (pckbd_bell_fn == NULL) { 1008 pckbd_bell_fn = fn; 1009 pckbd_bell_fn_arg = arg; 1010 } 1011 } 1012 1013 int 1014 pckbd_cnattach(pckbc_tag_t kbctag) 1015 { 1016 1017 pckbd_init(&pckbd_consdata, kbctag, PCKBC_KBD_SLOT, 1); 1018 1019 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 1020 1021 return (0); 1022 } 1023 1024 /* ARGSUSED */ 1025 void 1026 pckbd_cngetc(void *v, u_int *type, int *data) 1027 { 1028 struct pckbd_internal *t = v; 1029 int val; 1030 1031 for (;;) { 1032 val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot); 1033 if (val == -1) 1034 continue; 1035 1036 val = pckbd_scancode_translate(t, val); 1037 if (val == 0) 1038 continue; 1039 1040 if (pckbd_decode(t, val, type, data)) 1041 return; 1042 } 1043 } 1044 1045 void 1046 pckbd_cnpollc(void *v, int on) 1047 { 1048 struct pckbd_internal *t = v; 1049 1050 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on); 1051 1052 /* 1053 * If we enter ukc or ddb before having attached the console 1054 * keyboard we need to probe its scan code set. 1055 */ 1056 if (t->t_table == 0) { 1057 char cmd[1]; 1058 1059 pckbc_flush(t->t_kbctag, t->t_kbcslot); 1060 pckbd_set_xtscancode(t->t_kbctag, t->t_kbcslot, t); 1061 1062 /* Just to be sure. */ 1063 cmd[0] = KBC_ENABLE; 1064 pckbc_poll_cmd(t->t_kbctag, PCKBC_KBD_SLOT, cmd, 1, 0, NULL, 0); 1065 } 1066 } 1067 1068 void 1069 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 1070 { 1071 1072 pckbd_bell(pitch, period, volume, 1); 1073 } 1074 1075 struct cfdriver pckbd_cd = { 1076 NULL, "pckbd", DV_DULL 1077 }; 1078