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