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