pckbd.c revision 1.23
1/* $OpenBSD: pckbd.c,v 1.23 2009/11/23 15:21:41 deraadt 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 90struct 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 106struct 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 122static int pckbd_is_console(pckbc_tag_t, pckbc_slot_t); 123 124int pckbdprobe(struct device *, void *, void *); 125void pckbdattach(struct device *, struct device *, void *); 126int pckbd_activate(struct device *, int); 127 128struct cfattach pckbd_ca = { 129 sizeof(struct pckbd_softc), 130 pckbdprobe, 131 pckbdattach, 132 NULL, 133 pckbd_activate 134}; 135 136int pckbd_enable(void *, int); 137void pckbd_set_leds(void *, int); 138int pckbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 139 140const struct wskbd_accessops pckbd_accessops = { 141 pckbd_enable, 142 pckbd_set_leds, 143 pckbd_ioctl, 144}; 145 146void pckbd_cngetc(void *, u_int *, int *); 147void pckbd_cnpollc(void *, int); 148void pckbd_cnbell(void *, u_int, u_int, u_int); 149 150const struct wskbd_consops pckbd_consops = { 151 pckbd_cngetc, 152 pckbd_cnpollc, 153 pckbd_cnbell, 154}; 155 156const 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 */ 169void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int); 170void *pckbd_bell_fn_arg; 171 172void pckbd_bell(u_int, u_int, u_int, int); 173 174int pckbd_scancode_translate(struct pckbd_internal *, int); 175int pckbd_set_xtscancode(pckbc_tag_t, pckbc_slot_t, 176 struct pckbd_internal *); 177int pckbd_init(struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t, int); 178void pckbd_input(void *, int); 179 180static int pckbd_decode(struct pckbd_internal *, int, 181 u_int *, int *); 182static int pckbd_led_encode(int); 183static int pckbd_led_decode(int); 184 185struct pckbd_internal pckbd_consdata; 186 187int 188pckbd_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 284static int 285pckbd_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 */ 297int 298pckbdprobe(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 362void 363pckbdattach(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 417int 418pckbd_activate(struct device *self, int act) 419{ 420 switch (act) { 421 case DVACT_SUSPEND: 422 pckbd_enable(self, 0); 423 break; 424 case DVACT_RESUME: 425 pckbd_enable(self, 1); 426 break; 427 } 428 return (0); 429} 430 431int 432pckbd_enable(v, on) 433 void *v; 434 int on; 435{ 436 struct pckbd_softc *sc = v; 437 u_char cmd[1]; 438 int res; 439 440 if (on) { 441 if (sc->sc_enabled) 442 return (EBUSY); 443 444 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 445 446 cmd[0] = KBC_ENABLE; 447 res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 448 cmd, 1, 0, NULL, 0); 449 if (res) { 450 printf("pckbd_enable: command error\n"); 451 return (res); 452 } 453 454 res = pckbd_set_xtscancode(sc->id->t_kbctag, 455 sc->id->t_kbcslot, sc->id); 456 if (res) 457 return (res); 458 459 sc->sc_enabled = 1; 460 } else { 461 if (sc->id->t_isconsole) 462 return (EBUSY); 463 464 cmd[0] = KBC_DISABLE; 465 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 466 cmd, 1, 0, 1, 0); 467 if (res) { 468 printf("pckbd_disable: command error\n"); 469 return (res); 470 } 471 472 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 473 474 sc->sc_enabled = 0; 475 } 476 477 return (0); 478} 479 480const u_int8_t pckbd_xtbl[] = { 481/* 0x00 */ 482 0, 483 0x43, /* F9 */ 484 0, 485 0x3f, /* F5 */ 486 0x3d, /* F3 */ 487 0x3b, /* F1 */ 488 0x3c, /* F2 */ 489 0x58, /* F12 */ 490 0x40, /* F6 according to documentation */ 491 0x44, /* F10 */ 492 0x42, /* F8 */ 493 0x40, /* F6 according to experimentation */ 494 0x3e, /* F4 */ 495 0x0f, /* Tab */ 496 0x29, /* ` ~ */ 497 0, 498/* 0x10 */ 499 0, 500 0x38, /* Left Alt */ 501 0x2a, /* Left Shift */ 502 0, 503 0x1d, /* Left Ctrl */ 504 0x10, /* q */ 505 0x02, /* 1 ! */ 506 0, 507 0, 508 0, 509 0x2c, /* z */ 510 0x1f, /* s */ 511 0x1e, /* a */ 512 0x11, /* w */ 513 0x03, /* 2 @ */ 514 0, 515/* 0x20 */ 516 0, 517 0x2e, /* c */ 518 0x2d, /* x */ 519 0x20, /* d */ 520 0x12, /* e */ 521 0x05, /* 4 $ */ 522 0x04, /* 3 # */ 523 0, 524 0, 525 0x39, /* Space */ 526 0x2f, /* v */ 527 0x21, /* f */ 528 0x14, /* t */ 529 0x13, /* r */ 530 0x06, /* 5 % */ 531 0, 532/* 0x30 */ 533 0, 534 0x31, /* n */ 535 0x30, /* b */ 536 0x23, /* h */ 537 0x22, /* g */ 538 0x15, /* y */ 539 0x07, /* 6 ^ */ 540 0, 541 0, 542 0, 543 0x32, /* m */ 544 0x24, /* j */ 545 0x16, /* u */ 546 0x08, /* 7 & */ 547 0x09, /* 8 * */ 548 0, 549/* 0x40 */ 550 0, 551 0x33, /* , < */ 552 0x25, /* k */ 553 0x17, /* i */ 554 0x18, /* o */ 555 0x0b, /* 0 ) */ 556 0x0a, /* 9 ( */ 557 0, 558 0, 559 0x34, /* . > */ 560 0x35, /* / ? */ 561 0x26, /* l */ 562 0x27, /* ; : */ 563 0x19, /* p */ 564 0x0c, /* - _ */ 565 0, 566/* 0x50 */ 567 0, 568 0, 569 0x28, /* ' " */ 570 0, 571 0x1a, /* [ { */ 572 0x0d, /* = + */ 573 0, 574 0, 575 0x3a, /* Caps Lock */ 576 0x36, /* Right Shift */ 577 0x1c, /* Return */ 578 0x1b, /* ] } */ 579 0, 580 0x2b, /* \ | */ 581 0, 582 0, 583/* 0x60 */ 584 0, 585 0, 586 0, 587 0, 588 0, 589 0, 590 0x0e, /* Back Space */ 591 0, 592 0, 593 0x4f, /* KP 1 */ 594 0, 595 0x4b, /* KP 4 */ 596 0x47, /* KP 7 */ 597 0, 598 0, 599 0, 600/* 0x70 */ 601 0x52, /* KP 0 */ 602 0x53, /* KP . */ 603 0x50, /* KP 2 */ 604 0x4c, /* KP 5 */ 605 0x4d, /* KP 6 */ 606 0x48, /* KP 8 */ 607 0x01, /* Escape */ 608 0x45, /* Num Lock */ 609 0x57, /* F11 */ 610 0x4e, /* KP + */ 611 0x51, /* KP 3 */ 612 0x4a, /* KP - */ 613 0x37, /* KP * */ 614 0x49, /* KP 9 */ 615 0x46, /* Scroll Lock */ 616 0, 617/* 0x80 */ 618 0, 619 0, 620 0, 621 0x41, /* F7 (produced as an actual 8 bit code) */ 622 0 /* Alt-Print Screen */ 623}; 624 625const u_int8_t pckbd_xtbl_ext[] = { 626/* 0x00 */ 627 0, 628 0, 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/* 0x10 */ 643 0, 644 0x38, /* Right Alt */ 645 0, /* E0 12, to be ignored */ 646 0, 647 0x1d, /* Right Ctrl */ 648 0, 649 0, 650 0, 651 0, 652 0, 653 0, 654 0, 655 0, 656 0, 657 0, 658 0, 659/* 0x20 */ 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 0, 673 0, 674 0, 675 0, 676/* 0x30 */ 677 0, 678 0, 679 0, 680 0, 681 0, 682 0, 683 0, 684 0, 685 0, 686 0, 687 0, 688 0, 689 0, 690 0, 691 0, 692 0, 693/* 0x40 */ 694 0, 695 0, 696 0, 697 0, 698 0, 699 0, 700 0, 701 0, 702 0, 703 0, 704 0x55, /* KP / */ 705 0, 706 0, 707 0, 708 0, 709 0, 710/* 0x50 */ 711 0, 712 0, 713 0, 714 0, 715 0, 716 0, 717 0, 718 0, 719 0, 720 0, 721 0x1c, /* KP Return */ 722 0, 723 0, 724 0, 725 0, 726 0, 727/* 0x60 */ 728 0, 729 0, 730 0, 731 0, 732 0, 733 0, 734 0, 735 0, 736 0, 737 0x4f, /* End */ 738 0, 739 0x4b, /* Left */ 740 0x47, /* Home */ 741 0, 742 0, 743 0, 744/* 0x70 */ 745 0x52, /* Insert */ 746 0x53, /* Delete */ 747 0x50, /* Down */ 748 0, 749 0x4d, /* Right */ 750 0x48, /* Up */ 751 0, 752 0, 753 0, 754 0, 755 0x51, /* Page Down */ 756 0, 757 0x37, /* Print Screen */ 758 0x49, /* Page Up */ 759 0x46, /* Ctrl-Break */ 760 0 761}; 762 763/* 764 * Translate scan codes from set 2 to set 1 765 */ 766int 767pckbd_scancode_translate(struct pckbd_internal *id, int datain) 768{ 769 if (id->t_translating != 0 || id->t_table == 1) 770 return datain; 771 772 if (datain == KBR_BREAK) { 773 id->t_releasing = 0x80; /* next keycode is a release */ 774 return 0; /* consume scancode */ 775 } 776 777 /* 778 * Convert BREAK sequence (14 77 -> 1D 45) 779 */ 780 if (id->t_extended1 == 2 && datain == 0x14) 781 return 0x1d | id->t_releasing; 782 else if (id->t_extended1 == 1 && datain == 0x77) 783 return 0x77 | id->t_releasing; 784 785 if (id->t_extended != 0) { 786 if (datain >= sizeof pckbd_xtbl_ext) 787 datain = 0; 788 else 789 datain = pckbd_xtbl_ext[datain]; 790 } else { 791 if (datain >= sizeof pckbd_xtbl) 792 datain = 0; 793 else 794 datain = pckbd_xtbl[datain]; 795 } 796 797 if (datain == 0) { 798 /* 799 * We don't know how to translate this scan code, but 800 * we can't silently eat it either (because there might 801 * have been an extended byte transmitted already). 802 * Hopefully this value will be harmless to the upper 803 * layers. 804 */ 805 return 0xff; 806 } 807 808 return datain | id->t_releasing; 809} 810 811static int 812pckbd_decode(id, datain, type, dataout) 813 struct pckbd_internal *id; 814 int datain; 815 u_int *type; 816 int *dataout; 817{ 818 int key; 819 int releasing; 820 821 if (datain == KBR_EXTENDED0) { 822 id->t_extended = 0x80; 823 return 0; 824 } else if (datain == KBR_EXTENDED1) { 825 id->t_extended1 = 2; 826 return 0; 827 } 828 829 releasing = datain & 0x80; 830 datain &= 0x7f; 831 832 /* 833 * process BREAK key sequence (EXT1 1D 45 / EXT1 9D C5): 834 * map to (unused) code 7F 835 */ 836 if (id->t_extended1 == 2 && datain == 0x1d) { 837 id->t_extended1 = 1; 838 return 0; 839 } else if (id->t_extended1 == 1 && datain == 0x45) { 840 id->t_extended1 = 0; 841 datain = 0x7f; 842 } else 843 id->t_extended1 = 0; 844 845 if (id->t_translating != 0 || id->t_table == 1) { 846 id->t_releasing = releasing; 847 } else { 848 /* id->t_releasing computed in pckbd_scancode_translate() */ 849 } 850 851 /* map extended keys to (unused) codes 128-254 */ 852 key = datain | id->t_extended; 853 id->t_extended = 0; 854 855 if (id->t_releasing) { 856 id->t_releasing = 0; 857 id->t_lastchar = 0; 858 *type = WSCONS_EVENT_KEY_UP; 859 } else { 860 /* Always ignore typematic keys */ 861 if (key == id->t_lastchar) 862 return(0); 863 id->t_lastchar = key; 864 *type = WSCONS_EVENT_KEY_DOWN; 865 } 866 867 *dataout = key; 868 return 1; 869} 870 871int 872pckbd_init(t, kbctag, kbcslot, console) 873 struct pckbd_internal *t; 874 pckbc_tag_t kbctag; 875 pckbc_slot_t kbcslot; 876 int console; 877{ 878 bzero(t, sizeof(struct pckbd_internal)); 879 880 t->t_isconsole = console; 881 t->t_kbctag = kbctag; 882 t->t_kbcslot = kbcslot; 883 884 return (pckbd_set_xtscancode(kbctag, kbcslot, t)); 885} 886 887static int 888pckbd_led_encode(led) 889 int led; 890{ 891 int res; 892 893 res = 0; 894 895 if (led & WSKBD_LED_SCROLL) 896 res |= 0x01; 897 if (led & WSKBD_LED_NUM) 898 res |= 0x02; 899 if (led & WSKBD_LED_CAPS) 900 res |= 0x04; 901 return(res); 902} 903 904static int 905pckbd_led_decode(led) 906 int led; 907{ 908 int res; 909 910 res = 0; 911 if (led & 0x01) 912 res |= WSKBD_LED_SCROLL; 913 if (led & 0x02) 914 res |= WSKBD_LED_NUM; 915 if (led & 0x04) 916 res |= WSKBD_LED_CAPS; 917 return(res); 918} 919 920void 921pckbd_set_leds(v, leds) 922 void *v; 923 int leds; 924{ 925 struct pckbd_softc *sc = v; 926 u_char cmd[2]; 927 928 cmd[0] = KBC_MODEIND; 929 cmd[1] = pckbd_led_encode(leds); 930 sc->sc_ledstate = cmd[1]; 931 932 (void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 933 cmd, 2, 0, 0, 0); 934} 935 936/* 937 * Got a console receive interrupt - 938 * the console processor wants to give us a character. 939 */ 940void 941pckbd_input(vsc, data) 942 void *vsc; 943 int data; 944{ 945 struct pckbd_softc *sc = vsc; 946 int rc, type, key; 947 948 data = pckbd_scancode_translate(sc->id, data); 949 if (data == 0) 950 return; 951 952 rc = pckbd_decode(sc->id, data, &type, &key); 953 954#ifdef WSDISPLAY_COMPAT_RAWKBD 955 if (sc->rawkbd) { 956 sc->sc_rawbuf[sc->sc_rawcnt++] = (char)data; 957 958 if (rc != 0 || sc->sc_rawcnt == sizeof(sc->sc_rawbuf)) { 959 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rawbuf, 960 sc->sc_rawcnt); 961 sc->sc_rawcnt = 0; 962 } 963 964 /* 965 * Pass audio keys to wskbd_input anyway. 966 */ 967 if (rc == 0 || (key != 160 && key != 174 && key != 176)) 968 return; 969 } 970#endif 971 if (rc != 0) 972 wskbd_input(sc->sc_wskbddev, type, key); 973} 974 975int 976pckbd_ioctl(v, cmd, data, flag, p) 977 void *v; 978 u_long cmd; 979 caddr_t data; 980 int flag; 981 struct proc *p; 982{ 983 struct pckbd_softc *sc = v; 984 985 switch (cmd) { 986 case WSKBDIO_GTYPE: 987 *(int *)data = WSKBD_TYPE_PC_XT; 988 return 0; 989 case WSKBDIO_SETLEDS: { 990 char cmd[2]; 991 int res; 992 cmd[0] = KBC_MODEIND; 993 cmd[1] = pckbd_led_encode(*(int *)data); 994 sc->sc_ledstate = cmd[1]; 995 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 996 cmd, 2, 0, 1, 0); 997 return (res); 998 } 999 case WSKBDIO_GETLEDS: 1000 *(int *)data = pckbd_led_decode(sc->sc_ledstate); 1001 return (0); 1002 case WSKBDIO_COMPLEXBELL: 1003#define d ((struct wskbd_bell_data *)data) 1004 /* 1005 * Keyboard can't beep directly; we have an 1006 * externally-provided global hook to do this. 1007 */ 1008 pckbd_bell(d->pitch, d->period, d->volume, 0); 1009#undef d 1010 return (0); 1011#ifdef WSDISPLAY_COMPAT_RAWKBD 1012 case WSKBDIO_SETMODE: 1013 sc->rawkbd = (*(int *)data == WSKBD_RAW); 1014 return (0); 1015#endif 1016 } 1017 return -1; 1018} 1019 1020void 1021pckbd_bell(pitch, period, volume, poll) 1022 u_int pitch, period, volume; 1023 int poll; 1024{ 1025 1026 if (pckbd_bell_fn != NULL) 1027 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 1028 volume, poll); 1029} 1030 1031void 1032pckbd_hookup_bell(fn, arg) 1033 void (*fn)(void *, u_int, u_int, u_int, int); 1034 void *arg; 1035{ 1036 1037 if (pckbd_bell_fn == NULL) { 1038 pckbd_bell_fn = fn; 1039 pckbd_bell_fn_arg = arg; 1040 } 1041} 1042 1043int 1044pckbd_cnattach(kbctag, kbcslot) 1045 pckbc_tag_t kbctag; 1046 int kbcslot; 1047{ 1048 char cmd[1]; 1049 int res; 1050 1051 res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1); 1052#if 0 /* we allow the console to be attached if no keyboard is present */ 1053 if (res) 1054 return (res); 1055#endif 1056 1057 /* Just to be sure. */ 1058 cmd[0] = KBC_ENABLE; 1059 res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 0, NULL, 0); 1060#if 0 1061 if (res) 1062 return (res); 1063#endif 1064 1065 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 1066 1067 return (0); 1068} 1069 1070/* ARGSUSED */ 1071void 1072pckbd_cngetc(v, type, data) 1073 void *v; 1074 u_int *type; 1075 int *data; 1076{ 1077 struct pckbd_internal *t = v; 1078 int val; 1079 1080 for (;;) { 1081 val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot); 1082 if (val == -1) 1083 continue; 1084 1085 val = pckbd_scancode_translate(t, val); 1086 if (val == 0) 1087 continue; 1088 1089 if (pckbd_decode(t, val, type, data)) 1090 return; 1091 } 1092} 1093 1094void 1095pckbd_cnpollc(v, on) 1096 void *v; 1097 int on; 1098{ 1099 struct pckbd_internal *t = v; 1100 1101 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on); 1102} 1103 1104void 1105pckbd_cnbell(v, pitch, period, volume) 1106 void *v; 1107 u_int pitch, period, volume; 1108{ 1109 1110 pckbd_bell(pitch, period, volume, 1); 1111} 1112 1113struct cfdriver pckbd_cd = { 1114 NULL, "pckbd", DV_DULL 1115}; 1116