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