1 /* $NetBSD: pckbc.c,v 1.62 2020/05/01 01:34:57 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Ben Harris. 5 * Copyright (c) 1998 6 * Matthias Drochner. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.62 2020/05/01 01:34:57 riastradh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/callout.h> 35 #include <sys/kernel.h> 36 #include <sys/proc.h> 37 #include <sys/device.h> 38 #include <sys/malloc.h> 39 #include <sys/errno.h> 40 #include <sys/queue.h> 41 42 #include <sys/bus.h> 43 44 #include <dev/ic/i8042reg.h> 45 #include <dev/ic/pckbcvar.h> 46 47 #include <dev/pckbport/pckbportvar.h> 48 49 #include "locators.h" 50 51 #include <sys/rndsource.h> 52 53 /* data per slave device */ 54 struct pckbc_slotdata { 55 int polling; /* don't process data in interrupt handler */ 56 int poll_data; /* data read from inr handler if polling */ 57 int poll_stat; /* status read from inr handler if polling */ 58 krndsource_t rnd_source; 59 }; 60 61 static void pckbc_init_slotdata(struct pckbc_slotdata *); 62 static int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t); 63 64 struct pckbc_internal pckbc_consdata; 65 int pckbc_console_attached; 66 67 static int pckbc_console; 68 static struct pckbc_slotdata pckbc_cons_slotdata; 69 70 static int pckbc_xt_translation(void *, pckbport_slot_t, int); 71 static int pckbc_send_devcmd(void *, pckbport_slot_t, u_char); 72 static void pckbc_slot_enable(void *, pckbport_slot_t, int); 73 static void pckbc_intr_establish(void *, pckbport_slot_t); 74 static void pckbc_set_poll(void *, pckbc_slot_t, int on); 75 76 static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t); 77 78 static int pckbc_get8042cmd(struct pckbc_internal *); 79 static int pckbc_put8042cmd(struct pckbc_internal *); 80 81 void pckbc_cleanqueue(struct pckbc_slotdata *); 82 void pckbc_cleanup(void *); 83 int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char); 84 void pckbc_start(struct pckbc_internal *, pckbc_slot_t); 85 86 const char * const pckbc_slot_names[] = { "kbd", "aux" }; 87 88 static struct pckbport_accessops const pckbc_ops = { 89 pckbc_xt_translation, 90 pckbc_send_devcmd, 91 pckbc_poll_data1, 92 pckbc_slot_enable, 93 pckbc_intr_establish, 94 pckbc_set_poll 95 }; 96 97 #define KBD_DELAY DELAY(8) 98 99 static inline int 100 pckbc_wait_output(bus_space_tag_t iot, bus_space_handle_t ioh_c) 101 { 102 u_int i; 103 104 for (i = 100000; i; i--) 105 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) { 106 KBD_DELAY; 107 return (1); 108 } 109 return (0); 110 } 111 112 int 113 pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val) 114 { 115 if (!pckbc_wait_output(iot, ioh_c)) 116 return (0); 117 bus_space_write_1(iot, ioh_c, 0, val); 118 return (1); 119 } 120 121 /* 122 * Note: the spl games here are to deal with some strange PC kbd controllers 123 * in some system configurations. 124 * This is not canonical way to handle polling input. 125 */ 126 int 127 pckbc_poll_data1(void *pt, pckbc_slot_t slot) 128 { 129 struct pckbc_internal *t = pt; 130 struct pckbc_slotdata *q = t->t_slotdata[slot]; 131 int s; 132 u_char stat, c; 133 int i = 100; /* polls for ~100ms */ 134 int checkaux = t->t_haveaux; 135 136 s = splhigh(); 137 138 if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) { 139 stat = q->poll_stat; 140 c = q->poll_data; 141 q->poll_data = -1; 142 q->poll_stat = -1; 143 goto process; 144 } 145 146 for (; i; i--, delay(1000)) { 147 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); 148 if (stat & KBS_DIB) { 149 KBD_DELAY; 150 c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 151 152 process: 153 if (checkaux && (stat & 0x20)) { /* aux data */ 154 if (slot != PCKBC_AUX_SLOT) { 155 #ifdef PCKBCDEBUG 156 printf("pckbc: lost aux 0x%x\n", c); 157 #endif 158 continue; 159 } 160 } else { 161 if (slot == PCKBC_AUX_SLOT) { 162 #ifdef PCKBCDEBUG 163 printf("pckbc: lost kbd 0x%x\n", c); 164 #endif 165 continue; 166 } 167 } 168 splx(s); 169 return (c); 170 } 171 } 172 173 splx(s); 174 return (-1); 175 } 176 177 /* 178 * Get the current command byte. 179 */ 180 static int 181 pckbc_get8042cmd(struct pckbc_internal *t) 182 { 183 bus_space_tag_t iot = t->t_iot; 184 bus_space_handle_t ioh_c = t->t_ioh_c; 185 int data; 186 187 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE)) 188 return (0); 189 data = pckbc_poll_data1(t, PCKBC_KBD_SLOT); 190 if (data == -1) 191 return (0); 192 t->t_cmdbyte = data; 193 return (1); 194 } 195 196 /* 197 * Pass command byte to keyboard controller (8042). 198 */ 199 static int 200 pckbc_put8042cmd(struct pckbc_internal *t) 201 { 202 bus_space_tag_t iot = t->t_iot; 203 bus_space_handle_t ioh_d = t->t_ioh_d; 204 bus_space_handle_t ioh_c = t->t_ioh_c; 205 206 if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE)) 207 return (0); 208 if (!pckbc_wait_output(iot, ioh_c)) 209 return (0); 210 bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte); 211 return (1); 212 } 213 214 static int 215 pckbc_send_devcmd(void *pt, pckbc_slot_t slot, u_char val) 216 { 217 struct pckbc_internal *t = pt; 218 bus_space_tag_t iot = t->t_iot; 219 bus_space_handle_t ioh_d = t->t_ioh_d; 220 bus_space_handle_t ioh_c = t->t_ioh_c; 221 222 if (slot == PCKBC_AUX_SLOT) { 223 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) 224 return (0); 225 } 226 if (!pckbc_wait_output(iot, ioh_c)) 227 return (0); 228 bus_space_write_1(iot, ioh_d, 0, val); 229 return (1); 230 } 231 232 int 233 pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr) 234 { 235 if (pckbc_console && !pckbc_console_attached && 236 bus_space_is_equal(pckbc_consdata.t_iot, iot) && 237 pckbc_consdata.t_addr == addr) 238 return (1); 239 return (0); 240 } 241 242 static int 243 pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot) 244 { 245 struct pckbc_internal *t = sc->id; 246 void *sdata; 247 device_t child; 248 int alloced = 0; 249 250 if (t->t_slotdata[slot] == NULL) { 251 sdata = malloc(sizeof(struct pckbc_slotdata), 252 M_DEVBUF, M_WAITOK); 253 t->t_slotdata[slot] = sdata; 254 pckbc_init_slotdata(t->t_slotdata[slot]); 255 alloced++; 256 } 257 258 child = pckbport_attach_slot(sc->sc_dv, t->t_pt, slot); 259 260 if (child == NULL && alloced) { 261 free(t->t_slotdata[slot], M_DEVBUF); 262 t->t_slotdata[slot] = NULL; 263 } 264 265 if (child != NULL && t->t_slotdata[slot] != NULL) { 266 memset(&t->t_slotdata[slot]->rnd_source, 0, 267 sizeof(t->t_slotdata[slot]->rnd_source)); 268 rnd_attach_source(&t->t_slotdata[slot]->rnd_source, 269 device_xname(child), RND_TYPE_TTY, RND_FLAG_DEFAULT); 270 } 271 272 return child != NULL; 273 } 274 275 void 276 pckbc_attach(struct pckbc_softc *sc) 277 { 278 struct pckbc_internal *t; 279 bus_space_tag_t iot; 280 bus_space_handle_t ioh_d, ioh_c; 281 int res; 282 u_char cmdbits = 0; 283 284 t = sc->id; 285 iot = t->t_iot; 286 ioh_d = t->t_ioh_d; 287 ioh_c = t->t_ioh_c; 288 289 t->t_pt = pckbport_attach(t, &pckbc_ops); 290 if (t->t_pt == NULL) { 291 aprint_error(": attach failed\n"); 292 return; 293 } 294 295 /* flush */ 296 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT); 297 298 /* set initial cmd byte */ 299 if (!pckbc_put8042cmd(t)) { 300 aprint_error("pckbc: cmd word write error\n"); 301 return; 302 } 303 304 /* 305 * XXX Don't check the keyboard port. There are broken keyboard controllers 306 * which don't pass the test but work normally otherwise. 307 */ 308 #if 0 309 /* 310 * check kbd port ok 311 */ 312 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST)) 313 return; 314 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0); 315 316 /* 317 * Normally, we should get a "0" here. 318 * But there are keyboard controllers behaving differently. 319 */ 320 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) { 321 #ifdef PCKBCDEBUG 322 if (res != 0) 323 printf("pckbc: returned %x on kbd slot test\n", res); 324 #endif 325 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) 326 cmdbits |= KC8_KENABLE; 327 } else { 328 printf("pckbc: kbd port test: %x\n", res); 329 return; 330 } 331 #else 332 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) 333 cmdbits |= KC8_KENABLE; 334 #endif /* 0 */ 335 336 /* 337 * Check aux port ok. 338 * Avoid KBC_AUXTEST because it hangs some older controllers 339 * (eg UMC880?). 340 */ 341 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) { 342 aprint_error("pckbc: aux echo error 1\n"); 343 goto nomouse; 344 } 345 if (!pckbc_wait_output(iot, ioh_c)) { 346 aprint_error("pckbc: aux echo error 2\n"); 347 goto nomouse; 348 } 349 t->t_haveaux = 1; 350 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */ 351 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT); 352 353 /* 354 * The following is needed to find the aux port on the Tadpole 355 * SPARCle. 356 */ 357 if (res == -1 && ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) { 358 /* Read of aux echo timed out, try again */ 359 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) 360 goto nomouse; 361 if (!pckbc_wait_output(iot, ioh_c)) 362 goto nomouse; 363 bus_space_write_1(iot, ioh_d, 0, 0x5a); 364 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT); 365 } 366 if (res != -1) { 367 /* 368 * In most cases, the 0x5a gets echoed. 369 * Some older controllers (Gateway 2000 circa 1993) 370 * return 0xfe here. 371 * We are satisfied if there is anything in the 372 * aux output buffer. 373 */ 374 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT)) 375 cmdbits |= KC8_MENABLE; 376 } else { 377 378 #ifdef PCKBCDEBUG 379 printf("pckbc: aux echo test failed\n"); 380 #endif 381 t->t_haveaux = 0; 382 } 383 384 nomouse: 385 /* enable needed interrupts */ 386 t->t_cmdbyte |= cmdbits; 387 if (!pckbc_put8042cmd(t)) 388 aprint_error("pckbc: cmd word write error\n"); 389 } 390 391 static void 392 pckbc_init_slotdata(struct pckbc_slotdata *q) 393 { 394 395 q->polling = 0; 396 } 397 398 /* 399 * switch scancode translation on / off 400 * return nonzero on success 401 */ 402 static int 403 pckbc_xt_translation(void *self, pckbc_slot_t slot, int on) 404 { 405 struct pckbc_internal *t = self; 406 int ison; 407 408 if (ISSET(t->t_flags, PCKBC_CANT_TRANSLATE)) 409 return (-1); 410 411 if (slot != PCKBC_KBD_SLOT) { 412 /* translation only for kbd slot */ 413 if (on) 414 return (0); 415 else 416 return (1); 417 } 418 419 ison = t->t_cmdbyte & KC8_TRANS; 420 if ((on && ison) || (!on && !ison)) 421 return (1); 422 423 t->t_cmdbyte ^= KC8_TRANS; 424 if (!pckbc_put8042cmd(t)) 425 return (0); 426 427 /* read back to be sure */ 428 if (!pckbc_get8042cmd(t)) 429 return (0); 430 431 ison = t->t_cmdbyte & KC8_TRANS; 432 if ((on && ison) || (!on && !ison)) 433 return (1); 434 return (0); 435 } 436 437 static const struct pckbc_portcmd { 438 u_char cmd_en, cmd_dis; 439 } pckbc_portcmd[2] = { 440 { 441 KBC_KBDENABLE, KBC_KBDDISABLE, 442 }, { 443 KBC_AUXENABLE, KBC_AUXDISABLE, 444 } 445 }; 446 447 void 448 pckbc_slot_enable(void *self, pckbc_slot_t slot, int on) 449 { 450 struct pckbc_internal *t = (struct pckbc_internal *)self; 451 const struct pckbc_portcmd *cmd; 452 453 cmd = &pckbc_portcmd[slot]; 454 455 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, 456 on ? cmd->cmd_en : cmd->cmd_dis)) 457 printf("pckbc: pckbc_slot_enable(%d) failed\n", on); 458 } 459 460 static void 461 pckbc_set_poll(void *self, pckbc_slot_t slot, int on) 462 { 463 struct pckbc_internal *t = (struct pckbc_internal *)self; 464 465 t->t_slotdata[slot]->polling = on; 466 467 if (on) { 468 t->t_slotdata[slot]->poll_data = -1; 469 t->t_slotdata[slot]->poll_stat = -1; 470 } else { 471 int s; 472 473 /* 474 * If disabling polling on a device that's been configured, 475 * make sure there are no bytes left in the FIFO, holding up 476 * the interrupt line. Otherwise we won't get any further 477 * interrupts. 478 */ 479 if (t->t_sc) { 480 s = spltty(); 481 pckbcintr(t->t_sc); 482 splx(s); 483 } 484 } 485 } 486 487 static void 488 pckbc_intr_establish(void *pt, pckbport_slot_t slot) 489 { 490 struct pckbc_internal *t = pt; 491 492 (*t->t_sc->intr_establish)(t->t_sc, slot); 493 } 494 495 int 496 pckbcintr_hard(void *vsc) 497 { 498 struct pckbc_softc *sc = (struct pckbc_softc *)vsc; 499 struct pckbc_internal *t = sc->id; 500 u_char stat; 501 pckbc_slot_t slot; 502 struct pckbc_slotdata *q; 503 int served = 0, data, next, s; 504 505 for(;;) { 506 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); 507 if (!(stat & KBS_DIB)) 508 break; 509 510 served = 1; 511 512 slot = (t->t_haveaux && (stat & 0x20)) ? 513 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT; 514 q = t->t_slotdata[slot]; 515 516 if (!q) { 517 /* XXX do something for live insertion? */ 518 printf("pckbc: no dev for slot %d\n", slot); 519 KBD_DELAY; 520 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 521 continue; 522 } 523 524 KBD_DELAY; 525 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 526 527 rnd_add_uint32(&q->rnd_source, (stat<<8)|data); 528 529 if (q->polling) { 530 q->poll_data = data; 531 q->poll_stat = stat; 532 break; /* pckbc_poll_data() will get it */ 533 } 534 535 #if 0 /* XXXBJH */ 536 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data)) 537 continue; 538 #endif 539 540 s = splhigh(); 541 next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE; 542 if (next == t->rbuf_read) { 543 splx(s); 544 break; 545 } 546 t->rbuf[t->rbuf_write].data = data; 547 t->rbuf[t->rbuf_write].slot = slot; 548 t->rbuf_write = next; 549 splx(s); 550 } 551 552 return (served); 553 } 554 555 void 556 pckbcintr_soft(void *vsc) 557 { 558 struct pckbc_softc *sc = vsc; 559 struct pckbc_internal *t = sc->id; 560 int data, slot, s; 561 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS 562 int st; 563 564 st = spltty(); 565 #endif 566 567 s = splhigh(); 568 while (t->rbuf_read != t->rbuf_write) { 569 slot = t->rbuf[t->rbuf_read].slot; 570 data = t->rbuf[t->rbuf_read].data; 571 t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE; 572 splx(s); 573 pckbportintr(t->t_pt, slot, data); 574 s = splhigh(); 575 } 576 splx(s); 577 578 579 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS 580 splx(st); 581 #endif 582 } 583 584 int 585 pckbcintr(void *vsc) 586 { 587 struct pckbc_softc *sc = (struct pckbc_softc *)vsc; 588 struct pckbc_internal *t = sc->id; 589 u_char stat; 590 pckbc_slot_t slot; 591 struct pckbc_slotdata *q; 592 int served = 0, data; 593 594 for(;;) { 595 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); 596 if (!(stat & KBS_DIB)) 597 break; 598 599 slot = (t->t_haveaux && (stat & 0x20)) ? 600 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT; 601 q = t->t_slotdata[slot]; 602 603 if (q != NULL && q->polling) 604 return 0; 605 606 served = 1; 607 KBD_DELAY; 608 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 609 610 if (q != NULL) 611 rnd_add_uint32(&q->rnd_source, (stat<<8)|data); 612 613 pckbportintr(t->t_pt, slot, data); 614 } 615 616 return (served); 617 } 618 619 int 620 pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr, 621 bus_size_t cmd_offset, pckbc_slot_t slot, int flags) 622 { 623 bus_space_handle_t ioh_d, ioh_c; 624 #ifdef PCKBC_CNATTACH_SELFTEST 625 int reply; 626 #endif 627 int res = 0; 628 629 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d)) 630 return (ENXIO); 631 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) { 632 bus_space_unmap(iot, ioh_d, 1); 633 return (ENXIO); 634 } 635 636 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata)); 637 pckbc_consdata.t_iot = iot; 638 pckbc_consdata.t_ioh_d = ioh_d; 639 pckbc_consdata.t_ioh_c = ioh_c; 640 pckbc_consdata.t_addr = addr; 641 pckbc_consdata.t_flags = flags; 642 callout_init(&pckbc_consdata.t_cleanup, 0); 643 644 /* flush */ 645 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT); 646 647 #ifdef PCKBC_CNATTACH_SELFTEST 648 /* 649 * In some machines (e.g. netwinder) pckbc refuses to talk at 650 * all until we request a self-test. 651 */ 652 if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) { 653 printf("pckbc: unable to request selftest\n"); 654 res = EIO; 655 goto out; 656 } 657 658 reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT); 659 if (reply != 0x55) { 660 printf("pckbc: selftest returned 0x%02x\n", reply); 661 res = EIO; 662 goto out; 663 } 664 #endif /* PCKBC_CNATTACH_SELFTEST */ 665 666 /* init cmd byte, enable ports */ 667 pckbc_consdata.t_cmdbyte = KC8_CPU; 668 if (!pckbc_put8042cmd(&pckbc_consdata)) { 669 printf("pckbc: cmd word write error\n"); 670 res = EIO; 671 goto out; 672 } 673 674 res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot); 675 676 out: 677 if (res) { 678 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1); 679 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1); 680 } else { 681 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata; 682 pckbc_init_slotdata(&pckbc_cons_slotdata); 683 pckbc_console = 1; 684 } 685 686 return (res); 687 } 688 689 bool 690 pckbc_resume(device_t dv, const pmf_qual_t *qual) 691 { 692 struct pckbc_softc *sc = device_private(dv); 693 struct pckbc_internal *t; 694 695 t = sc->id; 696 (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT); 697 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, KBC_SELFTEST)) 698 return false; 699 (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT); 700 (void)pckbc_put8042cmd(t); 701 pckbcintr(t->t_sc); 702 703 return true; 704 } 705