1 /* $NetBSD: pckbc.c,v 1.21 2001/12/18 15:50:23 soren Exp $ */ 2 3 /* 4 * Copyright (c) 1998 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Matthias Drochner. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.21 2001/12/18 15:50:23 soren Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/callout.h> 40 #include <sys/kernel.h> 41 #include <sys/proc.h> 42 #include <sys/device.h> 43 #include <sys/malloc.h> 44 #include <sys/errno.h> 45 #include <sys/queue.h> 46 #include <sys/lock.h> 47 48 #include <machine/bus.h> 49 50 #include <dev/ic/i8042reg.h> 51 #include <dev/ic/pckbcvar.h> 52 53 #include "rnd.h" 54 #include "locators.h" 55 56 #ifdef __HAVE_NWSCONS /* XXX: this port uses sys/dev/pckbc */ 57 #include "pckbd.h" 58 #else /* ie: only md drivers attach to pckbc */ 59 #define NPCKBD 0 60 #endif 61 #if (NPCKBD > 0) 62 #include <dev/pckbc/pckbdvar.h> 63 #endif 64 #if NRND > 0 65 #include <sys/rnd.h> 66 #endif 67 68 /* descriptor for one device command */ 69 struct pckbc_devcmd { 70 TAILQ_ENTRY(pckbc_devcmd) next; 71 int flags; 72 #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */ 73 #define KBC_CMDFLAG_SLOW 2 74 u_char cmd[4]; 75 int cmdlen, cmdidx, retries; 76 u_char response[4]; 77 int status, responselen, responseidx; 78 }; 79 80 /* data per slave device */ 81 struct pckbc_slotdata { 82 int polling; /* don't process data in interrupt handler */ 83 int poll_data; /* data read from inr handler if polling */ 84 int poll_stat; /* status read from inr handler if polling */ 85 TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */ 86 TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */ 87 #define NCMD 5 88 struct pckbc_devcmd cmds[NCMD]; 89 #if NRND > 0 90 rndsource_element_t rnd_source; 91 #endif 92 }; 93 94 #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL) 95 96 void pckbc_init_slotdata __P((struct pckbc_slotdata *)); 97 int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t)); 98 int pckbc_submatch __P((struct device *, struct cfdata *, void *)); 99 int pckbcprint __P((void *, const char *)); 100 101 struct pckbc_internal pckbc_consdata; 102 int pckbc_console_attached; 103 104 static int pckbc_console; 105 static struct pckbc_slotdata pckbc_cons_slotdata; 106 107 static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t)); 108 109 static int pckbc_get8042cmd __P((struct pckbc_internal *)); 110 static int pckbc_put8042cmd __P((struct pckbc_internal *)); 111 static int pckbc_send_devcmd __P((struct pckbc_internal *, pckbc_slot_t, 112 u_char)); 113 static void pckbc_poll_cmd1 __P((struct pckbc_internal *, pckbc_slot_t, 114 struct pckbc_devcmd *)); 115 116 void pckbc_cleanqueue __P((struct pckbc_slotdata *)); 117 void pckbc_cleanup __P((void *)); 118 int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char)); 119 void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t)); 120 121 const char * const pckbc_slot_names[] = { "kbd", "aux" }; 122 123 #define KBC_DEVCMD_ACK 0xfa 124 #define KBC_DEVCMD_RESEND 0xfe 125 126 #define KBD_DELAY DELAY(8) 127 128 static inline int 129 pckbc_wait_output(iot, ioh_c) 130 bus_space_tag_t iot; 131 bus_space_handle_t ioh_c; 132 { 133 u_int i; 134 135 for (i = 100000; i; i--) 136 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) { 137 KBD_DELAY; 138 return (1); 139 } 140 return (0); 141 } 142 143 int 144 pckbc_send_cmd(iot, ioh_c, val) 145 bus_space_tag_t iot; 146 bus_space_handle_t ioh_c; 147 u_char val; 148 { 149 if (!pckbc_wait_output(iot, ioh_c)) 150 return (0); 151 bus_space_write_1(iot, ioh_c, 0, val); 152 return (1); 153 } 154 155 /* 156 * Note: the spl games here are to deal with some strange PC kbd controllers 157 * in some system configurations. 158 * This is not canonical way to handle polling input. 159 */ 160 int 161 pckbc_poll_data1(pt, slot, checkaux) 162 pckbc_tag_t pt; 163 pckbc_slot_t slot; 164 int checkaux; 165 { 166 struct pckbc_internal *t = pt; 167 struct pckbc_slotdata *q = t->t_slotdata[slot]; 168 int i, s; 169 u_char stat, c; 170 171 s = splhigh(); 172 173 if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) { 174 stat = q->poll_stat; 175 c = q->poll_data; 176 q->poll_data = -1; 177 q->poll_stat = -1; 178 goto process; 179 } 180 181 /* if 1 port read takes 1us (?), this polls for 100ms */ 182 for (i = 100000; i; i--) { 183 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); 184 if (stat & KBS_DIB) { 185 KBD_DELAY; 186 c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 187 188 process: 189 if (checkaux && (stat & 0x20)) { /* aux data */ 190 if (slot != PCKBC_AUX_SLOT) { 191 #ifdef PCKBCDEBUG 192 printf("lost aux 0x%x\n", c); 193 #endif 194 continue; 195 } 196 } else { 197 if (slot == PCKBC_AUX_SLOT) { 198 #ifdef PCKBCDEBUG 199 printf("lost kbd 0x%x\n", c); 200 #endif 201 continue; 202 } 203 } 204 splx(s); 205 return (c); 206 } 207 } 208 209 splx(s); 210 return (-1); 211 } 212 213 /* 214 * Get the current command byte. 215 */ 216 static int 217 pckbc_get8042cmd(t) 218 struct pckbc_internal *t; 219 { 220 bus_space_tag_t iot = t->t_iot; 221 bus_space_handle_t ioh_c = t->t_ioh_c; 222 int data; 223 224 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE)) 225 return (0); 226 data = pckbc_poll_data1(t, PCKBC_KBD_SLOT, t->t_haveaux); 227 if (data == -1) 228 return (0); 229 t->t_cmdbyte = data; 230 return (1); 231 } 232 233 /* 234 * Pass command byte to keyboard controller (8042). 235 */ 236 static int 237 pckbc_put8042cmd(t) 238 struct pckbc_internal *t; 239 { 240 bus_space_tag_t iot = t->t_iot; 241 bus_space_handle_t ioh_d = t->t_ioh_d; 242 bus_space_handle_t ioh_c = t->t_ioh_c; 243 244 if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE)) 245 return (0); 246 if (!pckbc_wait_output(iot, ioh_c)) 247 return (0); 248 bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte); 249 return (1); 250 } 251 252 static int 253 pckbc_send_devcmd(t, slot, val) 254 struct pckbc_internal *t; 255 pckbc_slot_t slot; 256 u_char val; 257 { 258 bus_space_tag_t iot = t->t_iot; 259 bus_space_handle_t ioh_d = t->t_ioh_d; 260 bus_space_handle_t ioh_c = t->t_ioh_c; 261 262 if (slot == PCKBC_AUX_SLOT) { 263 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) 264 return (0); 265 } 266 if (!pckbc_wait_output(iot, ioh_c)) 267 return (0); 268 bus_space_write_1(iot, ioh_d, 0, val); 269 return (1); 270 } 271 272 int 273 pckbc_is_console(iot, addr) 274 bus_space_tag_t iot; 275 bus_addr_t addr; 276 { 277 if (pckbc_console && !pckbc_console_attached && 278 pckbc_consdata.t_iot == iot && 279 pckbc_consdata.t_addr == addr) 280 return (1); 281 return (0); 282 } 283 284 int 285 pckbc_submatch(parent, cf, aux) 286 struct device *parent; 287 struct cfdata *cf; 288 void *aux; 289 { 290 struct pckbc_attach_args *pa = aux; 291 292 if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT && 293 cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot) 294 return (0); 295 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 296 } 297 298 int 299 pckbc_attach_slot(sc, slot) 300 struct pckbc_softc *sc; 301 pckbc_slot_t slot; 302 { 303 struct pckbc_internal *t = sc->id; 304 struct pckbc_attach_args pa; 305 void *sdata; 306 int found; 307 int alloced = 0; 308 309 pa.pa_tag = t; 310 pa.pa_slot = slot; 311 312 if (t->t_slotdata[slot] == NULL) { 313 sdata = malloc(sizeof(struct pckbc_slotdata), 314 M_DEVBUF, M_NOWAIT); 315 if (sdata == NULL) { 316 printf("%s: no memory\n", sc->sc_dv.dv_xname); 317 return (0); 318 } 319 t->t_slotdata[slot] = sdata; 320 pckbc_init_slotdata(t->t_slotdata[slot]); 321 alloced++; 322 } 323 324 found = (config_found_sm((struct device *)sc, &pa, 325 pckbcprint, pckbc_submatch) != NULL); 326 327 if (!found && alloced) { 328 free(t->t_slotdata[slot], M_DEVBUF); 329 t->t_slotdata[slot] = NULL; 330 } 331 332 #if NRND > 0 333 if (found && (t->t_slotdata[slot] != NULL)) 334 rnd_attach_source(&t->t_slotdata[slot]->rnd_source, 335 sc->subname[slot], RND_TYPE_TTY, 0); 336 #endif 337 return (found); 338 } 339 340 void 341 pckbc_attach(sc) 342 struct pckbc_softc *sc; 343 { 344 struct pckbc_internal *t; 345 bus_space_tag_t iot; 346 bus_space_handle_t ioh_d, ioh_c; 347 int res; 348 u_char cmdbits = 0; 349 350 t = sc->id; 351 iot = t->t_iot; 352 ioh_d = t->t_ioh_d; 353 ioh_c = t->t_ioh_c; 354 355 /* flush */ 356 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0); 357 358 /* set initial cmd byte */ 359 if (!pckbc_put8042cmd(t)) { 360 printf("kbc: cmd word write error\n"); 361 return; 362 } 363 364 /* 365 * XXX Don't check the keyboard port. There are broken keyboard controllers 366 * which don't pass the test but work normally otherwise. 367 */ 368 #if 0 369 /* 370 * check kbd port ok 371 */ 372 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST)) 373 return; 374 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0); 375 376 /* 377 * Normally, we should get a "0" here. 378 * But there are keyboard controllers behaving differently. 379 */ 380 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) { 381 #ifdef PCKBCDEBUG 382 if (res != 0) 383 printf("kbc: returned %x on kbd slot test\n", res); 384 #endif 385 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) 386 cmdbits |= KC8_KENABLE; 387 } else { 388 printf("kbc: kbd port test: %x\n", res); 389 return; 390 } 391 #else 392 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT)) 393 cmdbits |= KC8_KENABLE; 394 #endif /* 0 */ 395 396 /* 397 * Check aux port ok. 398 * Avoid KBC_AUXTEST because it hangs some older controllers 399 * (eg UMC880?). 400 */ 401 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) { 402 printf("kbc: aux echo error 1\n"); 403 goto nomouse; 404 } 405 if (!pckbc_wait_output(iot, ioh_c)) { 406 printf("kbc: aux echo error 2\n"); 407 goto nomouse; 408 } 409 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */ 410 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT, 1); 411 if (res != -1) { 412 /* 413 * In most cases, the 0x5a gets echoed. 414 * Some older controllers (Gateway 2000 circa 1993) 415 * return 0xfe here. 416 * We are satisfied if there is anything in the 417 * aux output buffer. 418 */ 419 t->t_haveaux = 1; 420 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT)) 421 cmdbits |= KC8_MENABLE; 422 } 423 #ifdef PCKBCDEBUG 424 else 425 printf("kbc: aux echo test failed\n"); 426 #endif 427 428 nomouse: 429 /* enable needed interrupts */ 430 t->t_cmdbyte |= cmdbits; 431 if (!pckbc_put8042cmd(t)) 432 printf("kbc: cmd word write error\n"); 433 } 434 435 int 436 pckbcprint(aux, pnp) 437 void *aux; 438 const char *pnp; 439 { 440 struct pckbc_attach_args *pa = aux; 441 442 if (!pnp) 443 printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]); 444 return (QUIET); 445 } 446 447 void 448 pckbc_init_slotdata(q) 449 struct pckbc_slotdata *q; 450 { 451 int i; 452 TAILQ_INIT(&q->cmdqueue); 453 TAILQ_INIT(&q->freequeue); 454 455 for (i = 0; i < NCMD; i++) { 456 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next); 457 } 458 q->polling = 0; 459 } 460 461 void 462 pckbc_flush(self, slot) 463 pckbc_tag_t self; 464 pckbc_slot_t slot; 465 { 466 struct pckbc_internal *t = self; 467 468 (void) pckbc_poll_data1(t, slot, t->t_haveaux); 469 } 470 471 int 472 pckbc_poll_data(self, slot) 473 pckbc_tag_t self; 474 pckbc_slot_t slot; 475 { 476 struct pckbc_internal *t = self; 477 struct pckbc_slotdata *q = t->t_slotdata[slot]; 478 int c; 479 480 c = pckbc_poll_data1(t, slot, t->t_haveaux); 481 if (c != -1 && q && CMD_IN_QUEUE(q)) { 482 /* we jumped into a running command - try to 483 deliver the response */ 484 if (pckbc_cmdresponse(t, slot, c)) 485 return (-1); 486 } 487 return (c); 488 } 489 490 /* 491 * switch scancode translation on / off 492 * return nonzero on success 493 */ 494 int 495 pckbc_xt_translation(self, slot, on) 496 pckbc_tag_t self; 497 pckbc_slot_t slot; 498 int on; 499 { 500 struct pckbc_internal *t = self; 501 int ison; 502 503 if (slot != PCKBC_KBD_SLOT) { 504 /* translation only for kbd slot */ 505 if (on) 506 return (0); 507 else 508 return (1); 509 } 510 511 ison = t->t_cmdbyte & KC8_TRANS; 512 if ((on && ison) || (!on && !ison)) 513 return (1); 514 515 t->t_cmdbyte ^= KC8_TRANS; 516 if (!pckbc_put8042cmd(t)) 517 return (0); 518 519 /* read back to be sure */ 520 if (!pckbc_get8042cmd(t)) 521 return (0); 522 523 ison = t->t_cmdbyte & KC8_TRANS; 524 if ((on && ison) || (!on && !ison)) 525 return (1); 526 return (0); 527 } 528 529 static const struct pckbc_portcmd { 530 u_char cmd_en, cmd_dis; 531 } pckbc_portcmd[2] = { 532 { 533 KBC_KBDENABLE, KBC_KBDDISABLE, 534 }, { 535 KBC_AUXENABLE, KBC_AUXDISABLE, 536 } 537 }; 538 539 void 540 pckbc_slot_enable(self, slot, on) 541 pckbc_tag_t self; 542 pckbc_slot_t slot; 543 int on; 544 { 545 struct pckbc_internal *t = (struct pckbc_internal *)self; 546 const struct pckbc_portcmd *cmd; 547 548 cmd = &pckbc_portcmd[slot]; 549 550 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, 551 on ? cmd->cmd_en : cmd->cmd_dis)) 552 printf("pckbc_slot_enable(%d) failed\n", on); 553 } 554 555 void 556 pckbc_set_poll(self, slot, on) 557 pckbc_tag_t self; 558 pckbc_slot_t slot; 559 int on; 560 { 561 struct pckbc_internal *t = (struct pckbc_internal *)self; 562 563 t->t_slotdata[slot]->polling = on; 564 565 if (on) { 566 t->t_slotdata[slot]->poll_data = -1; 567 t->t_slotdata[slot]->poll_stat = -1; 568 } else { 569 int s; 570 571 /* 572 * If disabling polling on a device that's been configured, 573 * make sure there are no bytes left in the FIFO, holding up 574 * the interrupt line. Otherwise we won't get any further 575 * interrupts. 576 */ 577 if (t->t_sc) { 578 s = spltty(); 579 pckbcintr(t->t_sc); 580 splx(s); 581 } 582 } 583 } 584 585 /* 586 * Pass command to device, poll for ACK and data. 587 * to be called at spltty() 588 */ 589 static void 590 pckbc_poll_cmd1(t, slot, cmd) 591 struct pckbc_internal *t; 592 pckbc_slot_t slot; 593 struct pckbc_devcmd *cmd; 594 { 595 int i, c = 0; 596 597 while (cmd->cmdidx < cmd->cmdlen) { 598 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) { 599 printf("pckbc_cmd: send error\n"); 600 cmd->status = EIO; 601 return; 602 } 603 for (i = 10; i; i--) { /* 1s ??? */ 604 c = pckbc_poll_data1(t, slot, t->t_haveaux); 605 if (c != -1) 606 break; 607 } 608 609 if (c == KBC_DEVCMD_ACK) { 610 cmd->cmdidx++; 611 continue; 612 } 613 if (c == KBC_DEVCMD_RESEND) { 614 #ifdef PCKBCDEBUG 615 printf("pckbc_cmd: RESEND\n"); 616 #endif 617 if (cmd->retries++ < 5) 618 continue; 619 else { 620 #ifdef PCKBCDEBUG 621 printf("pckbc: cmd failed\n"); 622 #endif 623 cmd->status = EIO; 624 return; 625 } 626 } 627 if (c == -1) { 628 #ifdef PCKBCDEBUG 629 printf("pckbc_cmd: timeout\n"); 630 #endif 631 cmd->status = EIO; 632 return; 633 } 634 #ifdef PCKBCDEBUG 635 printf("pckbc_cmd: lost 0x%x\n", c); 636 #endif 637 } 638 639 while (cmd->responseidx < cmd->responselen) { 640 if (cmd->flags & KBC_CMDFLAG_SLOW) 641 i = 100; /* 10s ??? */ 642 else 643 i = 10; /* 1s ??? */ 644 while (i--) { 645 c = pckbc_poll_data1(t, slot, t->t_haveaux); 646 if (c != -1) 647 break; 648 } 649 if (c == -1) { 650 #ifdef PCKBCDEBUG 651 printf("pckbc_cmd: no data\n"); 652 #endif 653 cmd->status = ETIMEDOUT; 654 return; 655 } else 656 cmd->response[cmd->responseidx++] = c; 657 } 658 } 659 660 /* for use in autoconfiguration */ 661 int 662 pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow) 663 pckbc_tag_t self; 664 pckbc_slot_t slot; 665 u_char *cmd; 666 int len, responselen; 667 u_char *respbuf; 668 int slow; 669 { 670 struct pckbc_internal *t = self; 671 struct pckbc_devcmd nc; 672 673 if ((len > 4) || (responselen > 4)) 674 return (EINVAL); 675 676 memset(&nc, 0, sizeof(nc)); 677 memcpy(nc.cmd, cmd, len); 678 nc.cmdlen = len; 679 nc.responselen = responselen; 680 nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0); 681 682 pckbc_poll_cmd1(t, slot, &nc); 683 684 if (nc.status == 0 && respbuf) 685 memcpy(respbuf, nc.response, responselen); 686 687 return (nc.status); 688 } 689 690 /* 691 * Clean up a command queue, throw away everything. 692 */ 693 void 694 pckbc_cleanqueue(q) 695 struct pckbc_slotdata *q; 696 { 697 struct pckbc_devcmd *cmd; 698 #ifdef PCKBCDEBUG 699 int i; 700 #endif 701 702 while ((cmd = TAILQ_FIRST(&q->cmdqueue))) { 703 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 704 #ifdef PCKBCDEBUG 705 printf("pckbc_cleanqueue: removing"); 706 for (i = 0; i < cmd->cmdlen; i++) 707 printf(" %02x", cmd->cmd[i]); 708 printf("\n"); 709 #endif 710 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 711 } 712 } 713 714 /* 715 * Timeout error handler: clean queues and data port. 716 * XXX could be less invasive. 717 */ 718 void 719 pckbc_cleanup(self) 720 void *self; 721 { 722 struct pckbc_internal *t = self; 723 int s; 724 725 printf("pckbc: command timeout\n"); 726 727 s = spltty(); 728 729 if (t->t_slotdata[PCKBC_KBD_SLOT]) 730 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]); 731 if (t->t_slotdata[PCKBC_AUX_SLOT]) 732 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]); 733 734 while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) { 735 KBD_DELAY; 736 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 737 } 738 739 /* reset KBC? */ 740 741 splx(s); 742 } 743 744 /* 745 * Pass command to device during normal operation. 746 * to be called at spltty() 747 */ 748 void 749 pckbc_start(t, slot) 750 struct pckbc_internal *t; 751 pckbc_slot_t slot; 752 { 753 struct pckbc_slotdata *q = t->t_slotdata[slot]; 754 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue); 755 756 if (q->polling) { 757 do { 758 pckbc_poll_cmd1(t, slot, cmd); 759 if (cmd->status) 760 printf("pckbc_start: command error\n"); 761 762 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 763 if (cmd->flags & KBC_CMDFLAG_SYNC) 764 wakeup(cmd); 765 else { 766 callout_stop(&t->t_cleanup); 767 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 768 } 769 cmd = TAILQ_FIRST(&q->cmdqueue); 770 } while (cmd); 771 return; 772 } 773 774 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) { 775 printf("pckbc_start: send error\n"); 776 /* XXX what now? */ 777 return; 778 } 779 } 780 781 /* 782 * Handle command responses coming in asynchonously, 783 * return nonzero if valid response. 784 * to be called at spltty() 785 */ 786 int 787 pckbc_cmdresponse(t, slot, data) 788 struct pckbc_internal *t; 789 pckbc_slot_t slot; 790 u_char data; 791 { 792 struct pckbc_slotdata *q = t->t_slotdata[slot]; 793 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue); 794 #ifdef DIAGNOSTIC 795 if (!cmd) 796 panic("pckbc_cmdresponse: no active command"); 797 #endif 798 if (cmd->cmdidx < cmd->cmdlen) { 799 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND) 800 return (0); 801 802 if (data == KBC_DEVCMD_RESEND) { 803 if (cmd->retries++ < 5) { 804 /* try again last command */ 805 goto restart; 806 } else { 807 printf("pckbc: cmd failed\n"); 808 cmd->status = EIO; 809 /* dequeue */ 810 } 811 } else { 812 if (++cmd->cmdidx < cmd->cmdlen) 813 goto restart; 814 if (cmd->responselen) 815 return (1); 816 /* else dequeue */ 817 } 818 } else if (cmd->responseidx < cmd->responselen) { 819 cmd->response[cmd->responseidx++] = data; 820 if (cmd->responseidx < cmd->responselen) 821 return (1); 822 /* else dequeue */ 823 } else 824 return (0); 825 826 /* dequeue: */ 827 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 828 if (cmd->flags & KBC_CMDFLAG_SYNC) 829 wakeup(cmd); 830 else { 831 callout_stop(&t->t_cleanup); 832 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 833 } 834 if (!CMD_IN_QUEUE(q)) 835 return (1); 836 restart: 837 pckbc_start(t, slot); 838 return (1); 839 } 840 841 /* 842 * Put command into the device's command queue, return zero or errno. 843 */ 844 int 845 pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf) 846 pckbc_tag_t self; 847 pckbc_slot_t slot; 848 u_char *cmd; 849 int len, responselen, sync; 850 u_char *respbuf; 851 { 852 struct pckbc_internal *t = self; 853 struct pckbc_slotdata *q = t->t_slotdata[slot]; 854 struct pckbc_devcmd *nc; 855 int s, isactive, res = 0; 856 857 if ((len > 4) || (responselen > 4)) 858 return (EINVAL); 859 s = spltty(); 860 nc = TAILQ_FIRST(&q->freequeue); 861 if (nc) { 862 TAILQ_REMOVE(&q->freequeue, nc, next); 863 } 864 splx(s); 865 if (!nc) 866 return (ENOMEM); 867 868 memset(nc, 0, sizeof(*nc)); 869 memcpy(nc->cmd, cmd, len); 870 nc->cmdlen = len; 871 nc->responselen = responselen; 872 nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0); 873 874 s = spltty(); 875 876 if (q->polling && sync) { 877 /* 878 * XXX We should poll until the queue is empty. 879 * But we don't come here normally, so make 880 * it simple and throw away everything. 881 */ 882 pckbc_cleanqueue(q); 883 } 884 885 isactive = CMD_IN_QUEUE(q); 886 TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next); 887 if (!isactive) 888 pckbc_start(t, slot); 889 890 if (q->polling) 891 res = (sync ? nc->status : 0); 892 else if (sync) { 893 if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) { 894 TAILQ_REMOVE(&q->cmdqueue, nc, next); 895 pckbc_cleanup(t); 896 } else 897 res = nc->status; 898 } else 899 callout_reset(&t->t_cleanup, hz, pckbc_cleanup, t); 900 901 if (sync) { 902 if (respbuf) 903 memcpy(respbuf, nc->response, responselen); 904 TAILQ_INSERT_TAIL(&q->freequeue, nc, next); 905 } 906 907 splx(s); 908 909 return (res); 910 } 911 912 void 913 pckbc_set_inputhandler(self, slot, func, arg, name) 914 pckbc_tag_t self; 915 pckbc_slot_t slot; 916 pckbc_inputfcn func; 917 void *arg; 918 char *name; 919 { 920 struct pckbc_internal *t = (struct pckbc_internal *)self; 921 struct pckbc_softc *sc = t->t_sc; 922 923 if (slot >= PCKBC_NSLOTS) 924 panic("pckbc_set_inputhandler: bad slot %d", slot); 925 926 (*sc->intr_establish)(sc, slot); 927 928 sc->inputhandler[slot] = func; 929 sc->inputarg[slot] = arg; 930 sc->subname[slot] = name; 931 } 932 933 int 934 pckbcintr(vsc) 935 void *vsc; 936 { 937 struct pckbc_softc *sc = (struct pckbc_softc *)vsc; 938 struct pckbc_internal *t = sc->id; 939 u_char stat; 940 pckbc_slot_t slot; 941 struct pckbc_slotdata *q; 942 int served = 0, data; 943 944 for(;;) { 945 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); 946 if (!(stat & KBS_DIB)) 947 break; 948 949 served = 1; 950 951 slot = (t->t_haveaux && (stat & 0x20)) ? 952 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT; 953 q = t->t_slotdata[slot]; 954 955 if (!q) { 956 /* XXX do something for live insertion? */ 957 printf("pckbcintr: no dev for slot %d\n", slot); 958 KBD_DELAY; 959 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 960 continue; 961 } 962 963 KBD_DELAY; 964 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 965 966 #if NRND > 0 967 rnd_add_uint32(&q->rnd_source, (stat<<8)|data); 968 #endif 969 970 if (q->polling) { 971 q->poll_data = data; 972 q->poll_stat = stat; 973 break; /* pckbc_poll_data() will get it */ 974 } 975 976 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data)) 977 continue; 978 979 if (sc->inputhandler[slot]) 980 (*sc->inputhandler[slot])(sc->inputarg[slot], data); 981 #ifdef PCKBCDEBUG 982 else 983 printf("pckbcintr: slot %d lost %d\n", slot, data); 984 #endif 985 } 986 987 return (served); 988 } 989 990 int 991 pckbc_cnattach(iot, addr, cmd_offset, slot) 992 bus_space_tag_t iot; 993 bus_addr_t addr; 994 bus_size_t cmd_offset; 995 pckbc_slot_t slot; 996 { 997 bus_space_handle_t ioh_d, ioh_c; 998 int res = 0; 999 1000 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d)) 1001 return (ENXIO); 1002 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) { 1003 bus_space_unmap(iot, ioh_d, 1); 1004 return (ENXIO); 1005 } 1006 1007 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata)); 1008 pckbc_consdata.t_iot = iot; 1009 pckbc_consdata.t_ioh_d = ioh_d; 1010 pckbc_consdata.t_ioh_c = ioh_c; 1011 pckbc_consdata.t_addr = addr; 1012 callout_init(&pckbc_consdata.t_cleanup); 1013 1014 /* flush */ 1015 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT, 0); 1016 1017 /* selftest? */ 1018 1019 /* init cmd byte, enable ports */ 1020 pckbc_consdata.t_cmdbyte = KC8_CPU; 1021 if (!pckbc_put8042cmd(&pckbc_consdata)) { 1022 printf("kbc: cmd word write error\n"); 1023 res = EIO; 1024 } 1025 1026 if (!res) { 1027 #if (NPCKBD > 0) 1028 res = pckbd_cnattach(&pckbc_consdata, slot); 1029 #else 1030 /* 1031 * XXX This should be replaced with the `notyet' case 1032 * XXX when all of the old PC-style console drivers 1033 * XXX have gone away. When that happens, all of 1034 * XXX the pckbc_machdep_cnattach() should be purged, 1035 * XXX as well. 1036 */ 1037 #ifdef notyet 1038 res = ENXIO; 1039 #else 1040 res = pckbc_machdep_cnattach(&pckbc_consdata, slot); 1041 #endif 1042 #endif /* NPCKBD > 0 */ 1043 } 1044 1045 if (res) { 1046 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1); 1047 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1); 1048 } else { 1049 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata; 1050 pckbc_init_slotdata(&pckbc_cons_slotdata); 1051 pckbc_console = 1; 1052 } 1053 1054 return (res); 1055 } 1056