1 /* $NetBSD: pckbd.c,v 1.16 2007/10/19 12:01:03 ad 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.16 2007/10/19 12:01:03 ad 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 struct device sc_dev; 119 120 struct pckbd_internal *id; 121 int sc_enabled; 122 123 int sc_ledstate; 124 125 struct device *sc_wskbddev; 126 #ifdef WSDISPLAY_COMPAT_RAWKBD 127 int rawkbd; 128 #endif 129 130 void *sc_powerhook; 131 }; 132 133 static int pckbd_is_console(pckbport_tag_t, pckbport_slot_t); 134 static void pckbd_powerhook(int, void *); 135 136 int pckbdprobe(struct device *, struct cfdata *, void *); 137 void pckbdattach(struct device *, struct device *, void *); 138 139 CFATTACH_DECL(pckbd, sizeof(struct pckbd_softc), 140 pckbdprobe, pckbdattach, NULL, NULL); 141 142 int pckbd_enable(void *, int); 143 void pckbd_set_leds(void *, int); 144 int pckbd_ioctl(void *, u_long, void *, int, struct lwp *); 145 146 const struct wskbd_accessops pckbd_accessops = { 147 pckbd_enable, 148 pckbd_set_leds, 149 pckbd_ioctl, 150 }; 151 152 void pckbd_cngetc(void *, u_int *, int *); 153 void pckbd_cnpollc(void *, int); 154 void pckbd_cnbell(void *, u_int, u_int, u_int); 155 156 const struct wskbd_consops pckbd_consops = { 157 pckbd_cngetc, 158 pckbd_cnpollc, 159 pckbd_cnbell, 160 }; 161 162 const struct wskbd_mapdata pckbd_keymapdata = { 163 pckbd_keydesctab, 164 #ifdef PCKBD_LAYOUT 165 PCKBD_LAYOUT, 166 #else 167 KB_US, 168 #endif 169 }; 170 171 /* 172 * Hackish support for a bell on the PC Keyboard; when a suitable feeper 173 * is found, it attaches itself into the pckbd driver here. 174 */ 175 void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int); 176 void *pckbd_bell_fn_arg; 177 178 void pckbd_bell(u_int, u_int, u_int, int); 179 180 int pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t); 181 int pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t, 182 int); 183 void pckbd_input(void *, int); 184 185 static int pckbd_decode(struct pckbd_internal *, int, u_int *, int *); 186 static int pckbd_led_encode(int); 187 static int pckbd_led_decode(int); 188 189 struct pckbd_internal pckbd_consdata; 190 191 int 192 pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot) 193 { 194 int res; 195 u_char cmd[2]; 196 197 /* 198 * Some keyboard/8042 combinations do not seem to work if the keyboard 199 * is set to table 1; in fact, it would appear that some keyboards just 200 * ignore the command altogether. So by default, we use the AT scan 201 * codes and have the 8042 translate them. Unfortunately, this is 202 * known to not work on some PS/2 machines. We try desperately to deal 203 * with this by checking the (lack of a) translate bit in the 8042 and 204 * attempting to set the keyboard to XT mode. If this all fails, well, 205 * tough luck. 206 * 207 * XXX It would perhaps be a better choice to just use AT scan codes 208 * and not bother with this. 209 */ 210 if (pckbport_xt_translation(kbctag, kbcslot, 1)) { 211 /* The 8042 is translating for us; use AT codes. */ 212 cmd[0] = KBC_SETTABLE; 213 cmd[1] = 2; 214 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0); 215 if (res) { 216 u_char cmdb[1]; 217 #ifdef DEBUG 218 printf("pckbd: error setting scanset 2\n"); 219 #endif 220 /* 221 * XXX at least one keyboard is reported to lock up 222 * if a "set table" is attempted, thus the "reset". 223 * XXX ignore errors, scanset 2 should be 224 * default anyway. 225 */ 226 cmdb[0] = KBC_RESET; 227 (void)pckbport_poll_cmd(kbctag, kbcslot, cmdb, 1, 1, 0, 1); 228 pckbport_flush(kbctag, kbcslot); 229 res = 0; 230 } 231 } else { 232 /* Stupid 8042; set keyboard to XT codes. */ 233 cmd[0] = KBC_SETTABLE; 234 cmd[1] = 1; 235 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0); 236 #ifdef DEBUG 237 if (res) 238 printf("pckbd: error setting scanset 1\n"); 239 #endif 240 } 241 return res; 242 } 243 244 static int 245 pckbd_is_console(pckbport_tag_t tag, pckbport_slot_t slot) 246 { 247 248 return pckbd_consdata.t_isconsole && 249 tag == pckbd_consdata.t_kbctag && slot == pckbd_consdata.t_kbcslot; 250 } 251 252 static void 253 pckbd_powerhook(int why, void *opaque) 254 { 255 struct pckbd_softc *sc; 256 int res; 257 u_char cmd[1], resp[1]; 258 259 sc = (struct pckbd_softc *)opaque; 260 261 switch (why) { 262 case PWR_STANDBY: 263 case PWR_SUSPEND: 264 printf("%s: suspending...\n", sc->sc_dev.dv_xname); 265 /* XXX duped from pckbd_enable, but we want to disable it 266 * even if it's the console kbd 267 */ 268 cmd[0] = KBC_DISABLE; 269 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 270 cmd, 1, 0, 1, 0); 271 if (res) 272 printf("pckbd_disable: command error\n"); 273 274 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 275 276 sc->sc_enabled = 0; 277 break; 278 case PWR_RESUME: 279 printf("%s: resuming...\n", sc->sc_dev.dv_xname); 280 281 /* XXX jmcneill reset the keyboard */ 282 cmd[0] = KBC_RESET; 283 res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 284 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", resp[0]); 291 292 pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot); 293 294 pckbd_set_xtscancode(sc->id->t_kbctag, sc->id->t_kbcslot); 295 296 pckbd_enable(sc, 1); 297 break; 298 } 299 300 return; 301 } 302 303 /* 304 * these are both bad jokes 305 */ 306 int 307 pckbdprobe(struct device *parent, struct cfdata *cf, void *aux) 308 { 309 struct pckbport_attach_args *pa = aux; 310 int res; 311 u_char cmd[1], resp[1]; 312 313 /* 314 * XXX There are rumours that a keyboard can be connected 315 * to the aux port as well. For me, this didn't work. 316 * For further experiments, allow it if explicitly 317 * wired in the config file. 318 */ 319 if ((pa->pa_slot != PCKBPORT_KBD_SLOT) && 320 (cf->cf_loc[PCKBPORTCF_SLOT] == PCKBPORTCF_SLOT_DEFAULT)) 321 return 0; 322 323 /* Flush any garbage. */ 324 pckbport_flush(pa->pa_tag, pa->pa_slot); 325 326 /* Reset the keyboard. */ 327 cmd[0] = KBC_RESET; 328 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1); 329 if (res) { 330 #ifdef DEBUG 331 printf("pckbdprobe: reset error %d\n", res); 332 #endif 333 /* 334 * There is probably no keyboard connected. 335 * Let the probe succeed if the keyboard is used 336 * as console input - it can be connected later. 337 */ 338 return pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0; 339 } 340 if (resp[0] != KBR_RSTDONE) { 341 printf("pckbdprobe: reset response 0x%x\n", resp[0]); 342 return 0; 343 } 344 345 /* 346 * Some keyboards seem to leave a second ack byte after the reset. 347 * This is kind of stupid, but we account for them anyway by just 348 * flushing the buffer. 349 */ 350 pckbport_flush(pa->pa_tag, pa->pa_slot); 351 352 if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot)) 353 return 0; 354 355 return 2; 356 } 357 358 void 359 pckbdattach(struct device *parent, struct device *self, void *aux) 360 { 361 struct pckbd_softc *sc = device_private(self); 362 struct pckbport_attach_args *pa = aux; 363 struct wskbddev_attach_args a; 364 int isconsole; 365 u_char cmd[1]; 366 367 printf("\n"); 368 369 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot); 370 371 if (isconsole) { 372 sc->id = &pckbd_consdata; 373 374 /* 375 * Some keyboards are not enabled after a reset, 376 * so make sure it is enabled now. 377 */ 378 cmd[0] = KBC_ENABLE; 379 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 380 cmd, 1, 0, 0, 0); 381 sc->sc_enabled = 1; 382 } else { 383 sc->id = malloc(sizeof(struct pckbd_internal), 384 M_DEVBUF, M_WAITOK); 385 (void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0); 386 387 /* no interrupts until enabled */ 388 cmd[0] = KBC_DISABLE; 389 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 390 cmd, 1, 0, 0, 0); 391 sc->sc_enabled = 0; 392 } 393 394 sc->id->t_sc = sc; 395 396 pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot, 397 pckbd_input, sc, sc->sc_dev.dv_xname); 398 399 a.console = isconsole; 400 401 a.keymap = &pckbd_keymapdata; 402 403 a.accessops = &pckbd_accessops; 404 a.accesscookie = sc; 405 406 sc->sc_powerhook = powerhook_establish(sc->sc_dev.dv_xname, 407 pckbd_powerhook, sc); 408 if (sc->sc_powerhook == NULL) 409 aprint_error("%s: unable to install powerhook\n", 410 sc->sc_dev.dv_xname); 411 412 /* 413 * Attach the wskbd, saving a handle to it. 414 * XXX XXX XXX 415 */ 416 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 417 } 418 419 int 420 pckbd_enable(void *v, int on) 421 { 422 struct pckbd_softc *sc = v; 423 int res; 424 u_char cmd[1]; 425 426 if (on) { 427 if (sc->sc_enabled) { 428 #ifdef DIAGNOSTIC 429 printf("pckbd_enable: bad enable\n"); 430 #endif 431 return EBUSY; 432 } 433 434 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 435 436 cmd[0] = KBC_ENABLE; 437 res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 438 cmd, 1, 0, NULL, 0); 439 if (res) { 440 printf("pckbd_enable: command error\n"); 441 return (res); 442 } 443 444 res = pckbd_set_xtscancode(sc->id->t_kbctag, 445 sc->id->t_kbcslot); 446 if (res) 447 return res; 448 449 sc->sc_enabled = 1; 450 } else { 451 if (sc->id->t_isconsole) 452 return EBUSY; 453 454 cmd[0] = KBC_DISABLE; 455 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 456 cmd, 1, 0, 1, 0); 457 if (res) { 458 printf("pckbd_disable: command error\n"); 459 return res; 460 } 461 462 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 463 464 sc->sc_enabled = 0; 465 } 466 467 return 0; 468 } 469 470 static int 471 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) 472 { 473 int key; 474 475 if (datain == KBR_EXTENDED0) { 476 id->t_extended0 = 1; 477 return 0; 478 } else if (datain == KBR_EXTENDED1) { 479 id->t_extended1 = 2; 480 return 0; 481 } 482 483 /* map extended keys to (unused) codes 128-254 */ 484 key = (datain & 0x7f) | (id->t_extended0 ? 0x80 : 0); 485 id->t_extended0 = 0; 486 487 /* 488 * process PAUSE (also break) key (EXT1 1D 45 EXT1 9D C5): 489 * map to (unused) code 7F 490 */ 491 if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) { 492 id->t_extended1 = 1; 493 return 0; 494 } else if (id->t_extended1 == 1 && 495 (datain == 0x45 || datain == 0xc5)) { 496 id->t_extended1 = 0; 497 key = 0x7f; 498 } else if (id->t_extended1 > 0) { 499 id->t_extended1 = 0; 500 } 501 502 if (datain & 0x80) { 503 id->t_lastchar = 0; 504 *type = WSCONS_EVENT_KEY_UP; 505 } else { 506 /* Always ignore typematic keys */ 507 if (key == id->t_lastchar) 508 return 0; 509 id->t_lastchar = key; 510 *type = WSCONS_EVENT_KEY_DOWN; 511 } 512 513 *dataout = key; 514 return 1; 515 } 516 517 int 518 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag, 519 pckbport_slot_t kbcslot, int console) 520 { 521 522 memset(t, 0, sizeof(struct pckbd_internal)); 523 524 t->t_isconsole = console; 525 t->t_kbctag = kbctag; 526 t->t_kbcslot = kbcslot; 527 528 return pckbd_set_xtscancode(kbctag, kbcslot); 529 } 530 531 static int 532 pckbd_led_encode(int led) 533 { 534 int res; 535 536 res = 0; 537 538 if (led & WSKBD_LED_SCROLL) 539 res |= 0x01; 540 if (led & WSKBD_LED_NUM) 541 res |= 0x02; 542 if (led & WSKBD_LED_CAPS) 543 res |= 0x04; 544 return res; 545 } 546 547 static int 548 pckbd_led_decode(int led) 549 { 550 int res; 551 552 res = 0; 553 if (led & 0x01) 554 res |= WSKBD_LED_SCROLL; 555 if (led & 0x02) 556 res |= WSKBD_LED_NUM; 557 if (led & 0x04) 558 res |= WSKBD_LED_CAPS; 559 return res; 560 } 561 562 void 563 pckbd_set_leds(void *v, int leds) 564 { 565 struct pckbd_softc *sc = v; 566 u_char cmd[2]; 567 568 cmd[0] = KBC_MODEIND; 569 cmd[1] = pckbd_led_encode(leds); 570 sc->sc_ledstate = cmd[1]; 571 572 (void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 573 cmd, 2, 0, 0, 0); 574 } 575 576 /* 577 * Got a console receive interrupt - 578 * the console processor wants to give us a character. 579 */ 580 void 581 pckbd_input(void *vsc, int data) 582 { 583 struct pckbd_softc *sc = vsc; 584 int key; 585 u_int type; 586 587 #ifdef WSDISPLAY_COMPAT_RAWKBD 588 if (sc->rawkbd) { 589 u_char d = data; 590 wskbd_rawinput(sc->sc_wskbddev, &d, 1); 591 return; 592 } 593 #endif 594 if (pckbd_decode(sc->id, data, &type, &key)) 595 wskbd_input(sc->sc_wskbddev, type, key); 596 } 597 598 int 599 pckbd_ioctl(void *v, u_long cmd, void *data, int flag, 600 struct lwp *l) 601 { 602 struct pckbd_softc *sc = v; 603 604 switch (cmd) { 605 case WSKBDIO_GTYPE: 606 *(int *)data = WSKBD_TYPE_PC_XT; 607 return 0; 608 case WSKBDIO_SETLEDS: 609 { 610 int res; 611 u_char cmdb[2]; 612 613 cmdb[0] = KBC_MODEIND; 614 cmdb[1] = pckbd_led_encode(*(int *)data); 615 sc->sc_ledstate = cmdb[1]; 616 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 617 cmdb, 2, 0, 1, 0); 618 return res; 619 } 620 case WSKBDIO_GETLEDS: 621 *(int *)data = pckbd_led_decode(sc->sc_ledstate); 622 return 0; 623 case WSKBDIO_COMPLEXBELL: 624 #define d ((struct wskbd_bell_data *)data) 625 /* 626 * Keyboard can't beep directly; we have an 627 * externally-provided global hook to do this. 628 */ 629 pckbd_bell(d->pitch, d->period, d->volume, 0); 630 #undef d 631 return 0; 632 #ifdef WSDISPLAY_COMPAT_RAWKBD 633 case WSKBDIO_SETMODE: 634 sc->rawkbd = (*(int *)data == WSKBD_RAW); 635 return 0; 636 #endif 637 } 638 return EPASSTHROUGH; 639 } 640 641 void 642 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll) 643 { 644 645 if (pckbd_bell_fn != NULL) 646 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 647 volume, poll); 648 } 649 650 void 651 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 652 { 653 654 if (pckbd_bell_fn == NULL) { 655 pckbd_bell_fn = fn; 656 pckbd_bell_fn_arg = arg; 657 } 658 } 659 660 int 661 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot) 662 { 663 int res; 664 u_char cmd[1]; 665 666 res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1); 667 /* We may allow the console to be attached if no keyboard is present */ 668 #if defined(PCKBD_CNATTACH_MAY_FAIL) 669 if (res) 670 return res; 671 #endif 672 673 /* Just to be sure. */ 674 cmd[0] = KBC_ENABLE; 675 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0); 676 677 #if defined(PCKBD_CNATTACH_MAY_FAIL) 678 if (res) 679 return res; 680 #endif 681 682 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 683 684 return 0; 685 } 686 687 /* ARGSUSED */ 688 void 689 pckbd_cngetc(void *v, u_int *type, int *data) 690 { 691 struct pckbd_internal *t = v; 692 int val; 693 694 for (;;) { 695 val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot); 696 if ((val != -1) && pckbd_decode(t, val, type, data)) 697 return; 698 } 699 } 700 701 void 702 pckbd_cnpollc(void *v, int on) 703 { 704 struct pckbd_internal *t = v; 705 706 pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on); 707 } 708 709 void 710 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 711 { 712 713 pckbd_bell(pitch, period, volume, 1); 714 } 715