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