1 /* $NetBSD: pckbd.c,v 1.23 2008/03/15 18:59:07 cube Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1990 The Regents of the University of California. 41 * All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * William Jolitz and Don Ahn. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 71 */ 72 73 /* 74 * code to work keyboard for PC-style console 75 */ 76 77 #include <sys/cdefs.h> 78 __KERNEL_RCSID(0, "$NetBSD: pckbd.c,v 1.23 2008/03/15 18:59:07 cube Exp $"); 79 80 #include <sys/param.h> 81 #include <sys/systm.h> 82 #include <sys/device.h> 83 #include <sys/malloc.h> 84 #include <sys/ioctl.h> 85 86 #include <sys/bus.h> 87 88 #include <dev/pckbport/pckbportvar.h> 89 90 #include <dev/wscons/wsconsio.h> 91 #include <dev/wscons/wskbdvar.h> 92 #include <dev/wscons/wsksymdef.h> 93 #include <dev/wscons/wsksymvar.h> 94 95 #include <dev/pckbport/pckbdreg.h> 96 #include <dev/pckbport/pckbdvar.h> 97 #include <dev/pckbport/wskbdmap_mfii.h> 98 99 #include "locators.h" 100 101 #include "opt_pckbd_layout.h" 102 #include "opt_pckbd_cnattach_may_fail.h" 103 #include "opt_wsdisplay_compat.h" 104 105 struct pckbd_internal { 106 int t_isconsole; 107 pckbport_tag_t t_kbctag; 108 pckbport_slot_t t_kbcslot; 109 110 int t_lastchar; 111 int t_extended0; 112 int t_extended1; 113 114 struct pckbd_softc *t_sc; /* back pointer */ 115 }; 116 117 struct pckbd_softc { 118 device_t sc_dev; 119 120 struct pckbd_internal *id; 121 int sc_enabled; 122 123 int sc_ledstate; 124 125 device_t sc_wskbddev; 126 #ifdef WSDISPLAY_COMPAT_RAWKBD 127 int rawkbd; 128 #endif 129 }; 130 131 static int pckbd_is_console(pckbport_tag_t, pckbport_slot_t); 132 133 int pckbdprobe(device_t, cfdata_t, void *); 134 void pckbdattach(device_t, device_t, void *); 135 136 CFATTACH_DECL_NEW(pckbd, sizeof(struct pckbd_softc), 137 pckbdprobe, pckbdattach, NULL, NULL); 138 139 int pckbd_enable(void *, int); 140 void pckbd_set_leds(void *, int); 141 int pckbd_ioctl(void *, u_long, void *, int, struct lwp *); 142 143 const struct wskbd_accessops pckbd_accessops = { 144 pckbd_enable, 145 pckbd_set_leds, 146 pckbd_ioctl, 147 }; 148 149 void pckbd_cngetc(void *, u_int *, int *); 150 void pckbd_cnpollc(void *, int); 151 void pckbd_cnbell(void *, u_int, u_int, u_int); 152 153 const struct wskbd_consops pckbd_consops = { 154 pckbd_cngetc, 155 pckbd_cnpollc, 156 pckbd_cnbell, 157 }; 158 159 const struct wskbd_mapdata pckbd_keymapdata = { 160 pckbd_keydesctab, 161 #ifdef PCKBD_LAYOUT 162 PCKBD_LAYOUT, 163 #else 164 KB_US, 165 #endif 166 }; 167 168 /* 169 * Hackish support for a bell on the PC Keyboard; when a suitable feeper 170 * is found, it attaches itself into the pckbd driver here. 171 */ 172 void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int); 173 void *pckbd_bell_fn_arg; 174 175 void pckbd_bell(u_int, u_int, u_int, int); 176 177 int pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t); 178 int pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t, 179 int); 180 void pckbd_input(void *, int); 181 182 static int pckbd_decode(struct pckbd_internal *, int, u_int *, int *); 183 static int pckbd_led_encode(int); 184 static int pckbd_led_decode(int); 185 186 struct pckbd_internal pckbd_consdata; 187 188 int 189 pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot) 190 { 191 int res; 192 u_char cmd[2]; 193 194 /* 195 * Some keyboard/8042 combinations do not seem to work if the keyboard 196 * is set to table 1; in fact, it would appear that some keyboards just 197 * ignore the command altogether. So by default, we use the AT scan 198 * codes and have the 8042 translate them. Unfortunately, this is 199 * known to not work on some PS/2 machines. We try desperately to deal 200 * with this by checking the (lack of a) translate bit in the 8042 and 201 * attempting to set the keyboard to XT mode. If this all fails, well, 202 * tough luck. 203 * 204 * XXX It would perhaps be a better choice to just use AT scan codes 205 * and not bother with this. 206 */ 207 if (pckbport_xt_translation(kbctag, kbcslot, 1)) { 208 /* The 8042 is translating for us; use AT codes. */ 209 cmd[0] = KBC_SETTABLE; 210 cmd[1] = 2; 211 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0); 212 if (res) { 213 u_char cmdb[1]; 214 #ifdef DEBUG 215 printf("pckbd: error setting scanset 2\n"); 216 #endif 217 /* 218 * XXX at least one keyboard is reported to lock up 219 * if a "set table" is attempted, thus the "reset". 220 * XXX ignore errors, scanset 2 should be 221 * default anyway. 222 */ 223 cmdb[0] = KBC_RESET; 224 (void)pckbport_poll_cmd(kbctag, kbcslot, cmdb, 1, 1, 0, 1); 225 pckbport_flush(kbctag, kbcslot); 226 res = 0; 227 } 228 } else { 229 /* Stupid 8042; set keyboard to XT codes. */ 230 cmd[0] = KBC_SETTABLE; 231 cmd[1] = 1; 232 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0); 233 #ifdef DEBUG 234 if (res) 235 printf("pckbd: error setting scanset 1\n"); 236 #endif 237 } 238 return res; 239 } 240 241 static int 242 pckbd_is_console(pckbport_tag_t tag, pckbport_slot_t slot) 243 { 244 245 return pckbd_consdata.t_isconsole && 246 tag == pckbd_consdata.t_kbctag && slot == pckbd_consdata.t_kbcslot; 247 } 248 249 static bool 250 pckbd_suspend(device_t dv PMF_FN_ARGS) 251 { 252 struct pckbd_softc *sc = device_private(dv); 253 u_char cmd[1]; 254 int res; 255 256 /* XXX duped from pckbd_enable, but we want to disable 257 * it even if it's the console kbd 258 */ 259 cmd[0] = KBC_DISABLE; 260 res = pckbport_enqueue_cmd(sc->id->t_kbctag, 261 sc->id->t_kbcslot, cmd, 1, 0, 1, 0); 262 if (res) 263 return false; 264 265 pckbport_slot_enable(sc->id->t_kbctag, 266 sc->id->t_kbcslot, 0); 267 268 sc->sc_enabled = 0; 269 return true; 270 } 271 272 static bool 273 pckbd_resume(device_t dv PMF_FN_ARGS) 274 { 275 struct pckbd_softc *sc = device_private(dv); 276 u_char cmd[1], resp[1]; 277 int res; 278 279 /* XXX jmcneill reset the keyboard */ 280 pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot); 281 282 cmd[0] = KBC_RESET; 283 res = pckbport_poll_cmd(sc->id->t_kbctag, 284 sc->id->t_kbcslot, cmd, 1, 1, resp, 1); 285 #ifdef DEBUG 286 if (res) 287 printf("pckbdprobe: reset error %d\n", res); 288 #endif 289 if (resp[0] != KBR_RSTDONE) 290 printf("pckbdprobe: reset response 0x%x\n", 291 resp[0]); 292 293 pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot); 294 295 pckbd_enable(sc, 1); 296 297 return true; 298 } 299 300 /* 301 * these are both bad jokes 302 */ 303 int 304 pckbdprobe(device_t parent, cfdata_t cf, void *aux) 305 { 306 struct pckbport_attach_args *pa = aux; 307 int res; 308 u_char cmd[1], resp[1]; 309 310 /* 311 * XXX There are rumours that a keyboard can be connected 312 * to the aux port as well. For me, this didn't work. 313 * For further experiments, allow it if explicitly 314 * wired in the config file. 315 */ 316 if ((pa->pa_slot != PCKBPORT_KBD_SLOT) && 317 (cf->cf_loc[PCKBPORTCF_SLOT] == PCKBPORTCF_SLOT_DEFAULT)) 318 return 0; 319 320 /* Flush any garbage. */ 321 pckbport_flush(pa->pa_tag, pa->pa_slot); 322 323 /* Reset the keyboard. */ 324 cmd[0] = KBC_RESET; 325 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1); 326 if (res) { 327 #ifdef DEBUG 328 printf("pckbdprobe: reset error %d\n", res); 329 #endif 330 /* 331 * There is probably no keyboard connected. 332 * Let the probe succeed if the keyboard is used 333 * as console input - it can be connected later. 334 */ 335 return pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0; 336 } 337 if (resp[0] != KBR_RSTDONE) { 338 printf("pckbdprobe: reset response 0x%x\n", resp[0]); 339 return 0; 340 } 341 342 /* 343 * Some keyboards seem to leave a second ack byte after the reset. 344 * This is kind of stupid, but we account for them anyway by just 345 * flushing the buffer. 346 */ 347 pckbport_flush(pa->pa_tag, pa->pa_slot); 348 349 if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot)) 350 return 0; 351 352 return 2; 353 } 354 355 void 356 pckbdattach(device_t parent, device_t self, void *aux) 357 { 358 struct pckbd_softc *sc = device_private(self); 359 struct pckbport_attach_args *pa = aux; 360 struct wskbddev_attach_args a; 361 int isconsole; 362 u_char cmd[1]; 363 364 aprint_naive("\n"); 365 aprint_normal("\n"); 366 367 sc->sc_dev = self; 368 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot); 369 370 if (isconsole) { 371 sc->id = &pckbd_consdata; 372 373 /* 374 * Some keyboards are not enabled after a reset, 375 * so make sure it is enabled now. 376 */ 377 cmd[0] = KBC_ENABLE; 378 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 379 cmd, 1, 0, 0, 0); 380 sc->sc_enabled = 1; 381 } else { 382 sc->id = malloc(sizeof(struct pckbd_internal), 383 M_DEVBUF, M_WAITOK); 384 (void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0); 385 386 /* no interrupts until enabled */ 387 cmd[0] = KBC_DISABLE; 388 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 389 cmd, 1, 0, 0, 0); 390 sc->sc_enabled = 0; 391 } 392 393 sc->id->t_sc = sc; 394 395 pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot, 396 pckbd_input, sc, device_xname(sc->sc_dev)); 397 398 a.console = isconsole; 399 400 a.keymap = &pckbd_keymapdata; 401 402 a.accessops = &pckbd_accessops; 403 a.accesscookie = sc; 404 405 if (!pmf_device_register(self, pckbd_suspend, pckbd_resume)) 406 aprint_error_dev(self, "couldn't establish power handler\n"); 407 408 /* 409 * Attach the wskbd, saving a handle to it. 410 * XXX XXX XXX 411 */ 412 sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); 413 } 414 415 int 416 pckbd_enable(void *v, int on) 417 { 418 struct pckbd_softc *sc = v; 419 int res; 420 u_char cmd[1]; 421 422 if (on) { 423 if (sc->sc_enabled) { 424 #ifdef DIAGNOSTIC 425 printf("pckbd_enable: bad enable\n"); 426 #endif 427 return EBUSY; 428 } 429 430 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 431 432 cmd[0] = KBC_ENABLE; 433 res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 434 cmd, 1, 0, NULL, 0); 435 if (res) { 436 printf("pckbd_enable: command error\n"); 437 return (res); 438 } 439 440 res = pckbd_set_xtscancode(sc->id->t_kbctag, 441 sc->id->t_kbcslot); 442 if (res) 443 return res; 444 445 sc->sc_enabled = 1; 446 } else { 447 if (sc->id->t_isconsole) 448 return EBUSY; 449 450 cmd[0] = KBC_DISABLE; 451 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 452 cmd, 1, 0, 1, 0); 453 if (res) { 454 printf("pckbd_disable: command error\n"); 455 return res; 456 } 457 458 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 459 460 sc->sc_enabled = 0; 461 } 462 463 return 0; 464 } 465 466 static int 467 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) 468 { 469 int key; 470 471 if (datain == KBR_EXTENDED0) { 472 id->t_extended0 = 1; 473 return 0; 474 } else if (datain == KBR_EXTENDED1) { 475 id->t_extended1 = 2; 476 return 0; 477 } 478 479 /* map extended keys to (unused) codes 128-254 */ 480 key = (datain & 0x7f) | (id->t_extended0 ? 0x80 : 0); 481 id->t_extended0 = 0; 482 483 /* 484 * process PAUSE (also break) key (EXT1 1D 45 EXT1 9D C5): 485 * map to (unused) code 7F 486 */ 487 if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) { 488 id->t_extended1 = 1; 489 return 0; 490 } else if (id->t_extended1 == 1 && 491 (datain == 0x45 || datain == 0xc5)) { 492 id->t_extended1 = 0; 493 key = 0x7f; 494 } else if (id->t_extended1 > 0) { 495 id->t_extended1 = 0; 496 } 497 498 if (datain & 0x80) { 499 id->t_lastchar = 0; 500 *type = WSCONS_EVENT_KEY_UP; 501 } else { 502 /* Always ignore typematic keys */ 503 if (key == id->t_lastchar) 504 return 0; 505 id->t_lastchar = key; 506 *type = WSCONS_EVENT_KEY_DOWN; 507 } 508 509 *dataout = key; 510 return 1; 511 } 512 513 int 514 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag, 515 pckbport_slot_t kbcslot, int console) 516 { 517 518 memset(t, 0, sizeof(struct pckbd_internal)); 519 520 t->t_isconsole = console; 521 t->t_kbctag = kbctag; 522 t->t_kbcslot = kbcslot; 523 524 return pckbd_set_xtscancode(kbctag, kbcslot); 525 } 526 527 static int 528 pckbd_led_encode(int led) 529 { 530 int res; 531 532 res = 0; 533 534 if (led & WSKBD_LED_SCROLL) 535 res |= 0x01; 536 if (led & WSKBD_LED_NUM) 537 res |= 0x02; 538 if (led & WSKBD_LED_CAPS) 539 res |= 0x04; 540 return res; 541 } 542 543 static int 544 pckbd_led_decode(int led) 545 { 546 int res; 547 548 res = 0; 549 if (led & 0x01) 550 res |= WSKBD_LED_SCROLL; 551 if (led & 0x02) 552 res |= WSKBD_LED_NUM; 553 if (led & 0x04) 554 res |= WSKBD_LED_CAPS; 555 return res; 556 } 557 558 void 559 pckbd_set_leds(void *v, int leds) 560 { 561 struct pckbd_softc *sc = v; 562 u_char cmd[2]; 563 564 cmd[0] = KBC_MODEIND; 565 cmd[1] = pckbd_led_encode(leds); 566 sc->sc_ledstate = cmd[1]; 567 568 (void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 569 cmd, 2, 0, 0, 0); 570 } 571 572 /* 573 * Got a console receive interrupt - 574 * the console processor wants to give us a character. 575 */ 576 void 577 pckbd_input(void *vsc, int data) 578 { 579 struct pckbd_softc *sc = vsc; 580 int key; 581 u_int type; 582 583 #ifdef WSDISPLAY_COMPAT_RAWKBD 584 if (sc->rawkbd) { 585 u_char d = data; 586 wskbd_rawinput(sc->sc_wskbddev, &d, 1); 587 return; 588 } 589 #endif 590 if (pckbd_decode(sc->id, data, &type, &key)) 591 wskbd_input(sc->sc_wskbddev, type, key); 592 } 593 594 int 595 pckbd_ioctl(void *v, u_long cmd, void *data, int flag, 596 struct lwp *l) 597 { 598 struct pckbd_softc *sc = v; 599 600 switch (cmd) { 601 case WSKBDIO_GTYPE: 602 *(int *)data = WSKBD_TYPE_PC_XT; 603 return 0; 604 case WSKBDIO_SETLEDS: 605 { 606 int res; 607 u_char cmdb[2]; 608 609 cmdb[0] = KBC_MODEIND; 610 cmdb[1] = pckbd_led_encode(*(int *)data); 611 sc->sc_ledstate = cmdb[1]; 612 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 613 cmdb, 2, 0, 1, 0); 614 return res; 615 } 616 case WSKBDIO_GETLEDS: 617 *(int *)data = pckbd_led_decode(sc->sc_ledstate); 618 return 0; 619 case WSKBDIO_COMPLEXBELL: 620 #define d ((struct wskbd_bell_data *)data) 621 /* 622 * Keyboard can't beep directly; we have an 623 * externally-provided global hook to do this. 624 */ 625 pckbd_bell(d->pitch, d->period, d->volume, 0); 626 #undef d 627 return 0; 628 #ifdef WSDISPLAY_COMPAT_RAWKBD 629 case WSKBDIO_SETMODE: 630 sc->rawkbd = (*(int *)data == WSKBD_RAW); 631 return 0; 632 #endif 633 } 634 return EPASSTHROUGH; 635 } 636 637 void 638 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll) 639 { 640 641 if (pckbd_bell_fn != NULL) 642 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 643 volume, poll); 644 } 645 646 void 647 pckbd_unhook_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 648 { 649 if (pckbd_bell_fn != fn && pckbd_bell_fn_arg != arg) 650 return; 651 pckbd_bell_fn = NULL; 652 pckbd_bell_fn_arg = NULL; 653 } 654 655 void 656 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 657 { 658 659 if (pckbd_bell_fn == NULL) { 660 pckbd_bell_fn = fn; 661 pckbd_bell_fn_arg = arg; 662 } 663 } 664 665 int 666 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot) 667 { 668 int res; 669 u_char cmd[1]; 670 671 res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1); 672 /* We may allow the console to be attached if no keyboard is present */ 673 #if defined(PCKBD_CNATTACH_MAY_FAIL) 674 if (res) 675 return res; 676 #endif 677 678 /* Just to be sure. */ 679 cmd[0] = KBC_ENABLE; 680 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0); 681 682 #if defined(PCKBD_CNATTACH_MAY_FAIL) 683 if (res) 684 return res; 685 #endif 686 687 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 688 689 return 0; 690 } 691 692 /* ARGSUSED */ 693 void 694 pckbd_cngetc(void *v, u_int *type, int *data) 695 { 696 struct pckbd_internal *t = v; 697 int val; 698 699 for (;;) { 700 val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot); 701 if ((val != -1) && pckbd_decode(t, val, type, data)) 702 return; 703 } 704 } 705 706 void 707 pckbd_cnpollc(void *v, int on) 708 { 709 struct pckbd_internal *t = v; 710 711 if (on) { 712 u_char cmd[1]; 713 714 cmd[0] = KBC_ENABLE; 715 (void)pckbport_poll_cmd(t->t_kbctag, t->t_kbcslot, cmd, 716 1, 0, 0, 0); 717 } 718 719 pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on); 720 } 721 722 void 723 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 724 { 725 726 pckbd_bell(pitch, period, volume, 1); 727 } 728