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