1 /* $NetBSD: pckbd.c,v 1.18 2007/12/09 20:28:13 jmcneill 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.18 2007/12/09 20:28:13 jmcneill 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 131 static int pckbd_is_console(pckbport_tag_t, pckbport_slot_t); 132 133 int pckbdprobe(struct device *, struct cfdata *, void *); 134 void pckbdattach(struct device *, struct device *, void *); 135 136 CFATTACH_DECL(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) 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) 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(struct device *parent, struct cfdata *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(struct device *parent, struct device *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 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot); 368 369 if (isconsole) { 370 sc->id = &pckbd_consdata; 371 372 /* 373 * Some keyboards are not enabled after a reset, 374 * so make sure it is enabled now. 375 */ 376 cmd[0] = KBC_ENABLE; 377 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 378 cmd, 1, 0, 0, 0); 379 sc->sc_enabled = 1; 380 } else { 381 sc->id = malloc(sizeof(struct pckbd_internal), 382 M_DEVBUF, M_WAITOK); 383 (void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0); 384 385 /* no interrupts until enabled */ 386 cmd[0] = KBC_DISABLE; 387 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 388 cmd, 1, 0, 0, 0); 389 sc->sc_enabled = 0; 390 } 391 392 sc->id->t_sc = sc; 393 394 pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot, 395 pckbd_input, sc, sc->sc_dev.dv_xname); 396 397 a.console = isconsole; 398 399 a.keymap = &pckbd_keymapdata; 400 401 a.accessops = &pckbd_accessops; 402 a.accesscookie = sc; 403 404 if (!pmf_device_register(self, pckbd_suspend, pckbd_resume)) 405 aprint_error_dev(self, "couldn't establish power handler\n"); 406 407 /* 408 * Attach the wskbd, saving a handle to it. 409 * XXX XXX XXX 410 */ 411 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 412 } 413 414 int 415 pckbd_enable(void *v, int on) 416 { 417 struct pckbd_softc *sc = v; 418 int res; 419 u_char cmd[1]; 420 421 if (on) { 422 if (sc->sc_enabled) { 423 #ifdef DIAGNOSTIC 424 printf("pckbd_enable: bad enable\n"); 425 #endif 426 return EBUSY; 427 } 428 429 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1); 430 431 cmd[0] = KBC_ENABLE; 432 res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 433 cmd, 1, 0, NULL, 0); 434 if (res) { 435 printf("pckbd_enable: command error\n"); 436 return (res); 437 } 438 439 res = pckbd_set_xtscancode(sc->id->t_kbctag, 440 sc->id->t_kbcslot); 441 if (res) 442 return res; 443 444 sc->sc_enabled = 1; 445 } else { 446 if (sc->id->t_isconsole) 447 return EBUSY; 448 449 cmd[0] = KBC_DISABLE; 450 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 451 cmd, 1, 0, 1, 0); 452 if (res) { 453 printf("pckbd_disable: command error\n"); 454 return res; 455 } 456 457 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0); 458 459 sc->sc_enabled = 0; 460 } 461 462 return 0; 463 } 464 465 static int 466 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) 467 { 468 int key; 469 470 if (datain == KBR_EXTENDED0) { 471 id->t_extended0 = 1; 472 return 0; 473 } else if (datain == KBR_EXTENDED1) { 474 id->t_extended1 = 2; 475 return 0; 476 } 477 478 /* map extended keys to (unused) codes 128-254 */ 479 key = (datain & 0x7f) | (id->t_extended0 ? 0x80 : 0); 480 id->t_extended0 = 0; 481 482 /* 483 * process PAUSE (also break) key (EXT1 1D 45 EXT1 9D C5): 484 * map to (unused) code 7F 485 */ 486 if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) { 487 id->t_extended1 = 1; 488 return 0; 489 } else if (id->t_extended1 == 1 && 490 (datain == 0x45 || datain == 0xc5)) { 491 id->t_extended1 = 0; 492 key = 0x7f; 493 } else if (id->t_extended1 > 0) { 494 id->t_extended1 = 0; 495 } 496 497 if (datain & 0x80) { 498 id->t_lastchar = 0; 499 *type = WSCONS_EVENT_KEY_UP; 500 } else { 501 /* Always ignore typematic keys */ 502 if (key == id->t_lastchar) 503 return 0; 504 id->t_lastchar = key; 505 *type = WSCONS_EVENT_KEY_DOWN; 506 } 507 508 *dataout = key; 509 return 1; 510 } 511 512 int 513 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag, 514 pckbport_slot_t kbcslot, int console) 515 { 516 517 memset(t, 0, sizeof(struct pckbd_internal)); 518 519 t->t_isconsole = console; 520 t->t_kbctag = kbctag; 521 t->t_kbcslot = kbcslot; 522 523 return pckbd_set_xtscancode(kbctag, kbcslot); 524 } 525 526 static int 527 pckbd_led_encode(int led) 528 { 529 int res; 530 531 res = 0; 532 533 if (led & WSKBD_LED_SCROLL) 534 res |= 0x01; 535 if (led & WSKBD_LED_NUM) 536 res |= 0x02; 537 if (led & WSKBD_LED_CAPS) 538 res |= 0x04; 539 return res; 540 } 541 542 static int 543 pckbd_led_decode(int led) 544 { 545 int res; 546 547 res = 0; 548 if (led & 0x01) 549 res |= WSKBD_LED_SCROLL; 550 if (led & 0x02) 551 res |= WSKBD_LED_NUM; 552 if (led & 0x04) 553 res |= WSKBD_LED_CAPS; 554 return res; 555 } 556 557 void 558 pckbd_set_leds(void *v, int leds) 559 { 560 struct pckbd_softc *sc = v; 561 u_char cmd[2]; 562 563 cmd[0] = KBC_MODEIND; 564 cmd[1] = pckbd_led_encode(leds); 565 sc->sc_ledstate = cmd[1]; 566 567 (void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 568 cmd, 2, 0, 0, 0); 569 } 570 571 /* 572 * Got a console receive interrupt - 573 * the console processor wants to give us a character. 574 */ 575 void 576 pckbd_input(void *vsc, int data) 577 { 578 struct pckbd_softc *sc = vsc; 579 int key; 580 u_int type; 581 582 #ifdef WSDISPLAY_COMPAT_RAWKBD 583 if (sc->rawkbd) { 584 u_char d = data; 585 wskbd_rawinput(sc->sc_wskbddev, &d, 1); 586 return; 587 } 588 #endif 589 if (pckbd_decode(sc->id, data, &type, &key)) 590 wskbd_input(sc->sc_wskbddev, type, key); 591 } 592 593 int 594 pckbd_ioctl(void *v, u_long cmd, void *data, int flag, 595 struct lwp *l) 596 { 597 struct pckbd_softc *sc = v; 598 599 switch (cmd) { 600 case WSKBDIO_GTYPE: 601 *(int *)data = WSKBD_TYPE_PC_XT; 602 return 0; 603 case WSKBDIO_SETLEDS: 604 { 605 int res; 606 u_char cmdb[2]; 607 608 cmdb[0] = KBC_MODEIND; 609 cmdb[1] = pckbd_led_encode(*(int *)data); 610 sc->sc_ledstate = cmdb[1]; 611 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot, 612 cmdb, 2, 0, 1, 0); 613 return res; 614 } 615 case WSKBDIO_GETLEDS: 616 *(int *)data = pckbd_led_decode(sc->sc_ledstate); 617 return 0; 618 case WSKBDIO_COMPLEXBELL: 619 #define d ((struct wskbd_bell_data *)data) 620 /* 621 * Keyboard can't beep directly; we have an 622 * externally-provided global hook to do this. 623 */ 624 pckbd_bell(d->pitch, d->period, d->volume, 0); 625 #undef d 626 return 0; 627 #ifdef WSDISPLAY_COMPAT_RAWKBD 628 case WSKBDIO_SETMODE: 629 sc->rawkbd = (*(int *)data == WSKBD_RAW); 630 return 0; 631 #endif 632 } 633 return EPASSTHROUGH; 634 } 635 636 void 637 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll) 638 { 639 640 if (pckbd_bell_fn != NULL) 641 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period, 642 volume, poll); 643 } 644 645 void 646 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) 647 { 648 649 if (pckbd_bell_fn == NULL) { 650 pckbd_bell_fn = fn; 651 pckbd_bell_fn_arg = arg; 652 } 653 } 654 655 int 656 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot) 657 { 658 int res; 659 u_char cmd[1]; 660 661 res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1); 662 /* We may allow the console to be attached if no keyboard is present */ 663 #if defined(PCKBD_CNATTACH_MAY_FAIL) 664 if (res) 665 return res; 666 #endif 667 668 /* Just to be sure. */ 669 cmd[0] = KBC_ENABLE; 670 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0); 671 672 #if defined(PCKBD_CNATTACH_MAY_FAIL) 673 if (res) 674 return res; 675 #endif 676 677 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata); 678 679 return 0; 680 } 681 682 /* ARGSUSED */ 683 void 684 pckbd_cngetc(void *v, u_int *type, int *data) 685 { 686 struct pckbd_internal *t = v; 687 int val; 688 689 for (;;) { 690 val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot); 691 if ((val != -1) && pckbd_decode(t, val, type, data)) 692 return; 693 } 694 } 695 696 void 697 pckbd_cnpollc(void *v, int on) 698 { 699 struct pckbd_internal *t = v; 700 701 pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on); 702 } 703 704 void 705 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 706 { 707 708 pckbd_bell(pitch, period, volume, 1); 709 } 710