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