1 /* $OpenBSD: pckbc.c,v 1.18 2008/09/10 14:01:22 blambert Exp $ */ 2 /* $NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp $ */ 3 4 /* 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/param.h> 30 #include <sys/systm.h> 31 #include <sys/timeout.h> 32 #include <sys/kernel.h> 33 #include <sys/proc.h> 34 #include <sys/device.h> 35 #include <sys/malloc.h> 36 #include <sys/errno.h> 37 #include <sys/queue.h> 38 #include <sys/lock.h> 39 40 #include <machine/bus.h> 41 42 #include <dev/ic/i8042reg.h> 43 #include <dev/ic/pckbcvar.h> 44 45 #include "pckbd.h" 46 47 #if (NPCKBD > 0) 48 #include <dev/pckbc/pckbdvar.h> 49 #endif 50 51 /* descriptor for one device command */ 52 struct pckbc_devcmd { 53 TAILQ_ENTRY(pckbc_devcmd) next; 54 int flags; 55 #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */ 56 #define KBC_CMDFLAG_SLOW 2 57 u_char cmd[4]; 58 int cmdlen, cmdidx, retries; 59 u_char response[4]; 60 int status, responselen, responseidx; 61 }; 62 63 /* data per slave device */ 64 struct pckbc_slotdata { 65 int polling; /* don't read data port in interrupt handler */ 66 TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */ 67 TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */ 68 #define NCMD 5 69 struct pckbc_devcmd cmds[NCMD]; 70 }; 71 72 #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL) 73 74 void pckbc_init_slotdata(struct pckbc_slotdata *); 75 int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t); 76 int pckbc_submatch(struct device *, void *, void *); 77 int pckbcprint(void *, const char *); 78 79 struct pckbc_internal pckbc_consdata; 80 int pckbc_console_attached; 81 82 static int pckbc_console; 83 static struct pckbc_slotdata pckbc_cons_slotdata; 84 85 static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t); 86 87 static int pckbc_get8042cmd(struct pckbc_internal *); 88 static int pckbc_put8042cmd(struct pckbc_internal *); 89 static int pckbc_send_devcmd(struct pckbc_internal *, pckbc_slot_t, 90 u_char); 91 static void pckbc_poll_cmd1(struct pckbc_internal *, pckbc_slot_t, 92 struct pckbc_devcmd *); 93 94 void pckbc_cleanqueue(struct pckbc_slotdata *); 95 void pckbc_cleanup(void *); 96 void pckbc_poll(void *); 97 int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char); 98 void pckbc_start(struct pckbc_internal *, pckbc_slot_t); 99 int pckbcintr_internal(struct pckbc_internal *, struct pckbc_softc *); 100 101 const char *pckbc_slot_names[] = { "kbd", "aux" }; 102 103 #define KBC_DEVCMD_ACK 0xfa 104 #define KBC_DEVCMD_RESEND 0xfe 105 106 #define KBD_DELAY DELAY(8) 107 108 static inline int 109 pckbc_wait_output(iot, ioh_c) 110 bus_space_tag_t iot; 111 bus_space_handle_t ioh_c; 112 { 113 u_int i; 114 115 for (i = 100000; i; i--) 116 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) { 117 KBD_DELAY; 118 return (1); 119 } 120 return (0); 121 } 122 123 int 124 pckbc_send_cmd(iot, ioh_c, val) 125 bus_space_tag_t iot; 126 bus_space_handle_t ioh_c; 127 u_char val; 128 { 129 if (!pckbc_wait_output(iot, ioh_c)) 130 return (0); 131 bus_space_write_1(iot, ioh_c, 0, val); 132 return (1); 133 } 134 135 int 136 pckbc_poll_data1(iot, ioh_d, ioh_c, slot, checkaux) 137 bus_space_tag_t iot; 138 bus_space_handle_t ioh_d, ioh_c; 139 pckbc_slot_t slot; 140 int checkaux; 141 { 142 int i; 143 u_char stat; 144 145 /* if 1 port read takes 1us (?), this polls for 100ms */ 146 for (i = 100000; i; i--) { 147 stat = bus_space_read_1(iot, ioh_c, 0); 148 if (stat & KBS_DIB) { 149 register u_char c; 150 151 KBD_DELAY; 152 c = bus_space_read_1(iot, ioh_d, 0); 153 if (checkaux && (stat & 0x20)) { /* aux data */ 154 if (slot != PCKBC_AUX_SLOT) { 155 #ifdef PCKBCDEBUG 156 printf("lost aux 0x%x\n", c); 157 #endif 158 continue; 159 } 160 } else { 161 if (slot == PCKBC_AUX_SLOT) { 162 #ifdef PCKBCDEBUG 163 printf("lost kbd 0x%x\n", c); 164 #endif 165 continue; 166 } 167 } 168 return (c); 169 } 170 } 171 return (-1); 172 } 173 174 /* 175 * Get the current command byte. 176 */ 177 static int 178 pckbc_get8042cmd(t) 179 struct pckbc_internal *t; 180 { 181 bus_space_tag_t iot = t->t_iot; 182 bus_space_handle_t ioh_d = t->t_ioh_d; 183 bus_space_handle_t ioh_c = t->t_ioh_c; 184 int data; 185 186 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE)) 187 return (0); 188 data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 189 t->t_haveaux); 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(t) 201 struct pckbc_internal *t; 202 { 203 bus_space_tag_t iot = t->t_iot; 204 bus_space_handle_t ioh_d = t->t_ioh_d; 205 bus_space_handle_t ioh_c = t->t_ioh_c; 206 207 if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE)) 208 return (0); 209 if (!pckbc_wait_output(iot, ioh_c)) 210 return (0); 211 bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte); 212 return (1); 213 } 214 215 static int 216 pckbc_send_devcmd(t, slot, val) 217 struct pckbc_internal *t; 218 pckbc_slot_t slot; 219 u_char val; 220 { 221 bus_space_tag_t iot = t->t_iot; 222 bus_space_handle_t ioh_d = t->t_ioh_d; 223 bus_space_handle_t ioh_c = t->t_ioh_c; 224 225 if (slot == PCKBC_AUX_SLOT) { 226 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) 227 return (0); 228 } 229 if (!pckbc_wait_output(iot, ioh_c)) 230 return (0); 231 bus_space_write_1(iot, ioh_d, 0, val); 232 return (1); 233 } 234 235 int 236 pckbc_is_console(iot, addr) 237 bus_space_tag_t iot; 238 bus_addr_t addr; 239 { 240 if (pckbc_console && !pckbc_console_attached && 241 pckbc_consdata.t_iot == iot && 242 pckbc_consdata.t_addr == addr) 243 return (1); 244 return (0); 245 } 246 247 int 248 pckbc_submatch(parent, match, aux) 249 struct device *parent; 250 void *match; 251 void *aux; 252 { 253 struct cfdata *cf = match; 254 struct pckbc_attach_args *pa = aux; 255 256 if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT && 257 cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot) 258 return (0); 259 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 260 } 261 262 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 int found; 270 271 pa.pa_tag = t; 272 pa.pa_slot = slot; 273 found = (config_found_sm((struct device *)sc, &pa, 274 pckbcprint, pckbc_submatch) != NULL); 275 276 if (found && !t->t_slotdata[slot]) { 277 t->t_slotdata[slot] = malloc(sizeof(struct pckbc_slotdata), 278 M_DEVBUF, M_NOWAIT); 279 if (t->t_slotdata[slot] == NULL) 280 return 0; 281 pckbc_init_slotdata(t->t_slotdata[slot]); 282 } 283 return (found); 284 } 285 286 void 287 pckbc_attach(sc) 288 struct pckbc_softc *sc; 289 { 290 struct pckbc_internal *t; 291 bus_space_tag_t iot; 292 bus_space_handle_t ioh_d, ioh_c; 293 int res; 294 u_char cmdbits = 0; 295 296 t = sc->id; 297 iot = t->t_iot; 298 ioh_d = t->t_ioh_d; 299 ioh_c = t->t_ioh_c; 300 301 if (pckbc_console == 0) { 302 timeout_set(&t->t_cleanup, pckbc_cleanup, t); 303 timeout_set(&t->t_poll, pckbc_poll, t); 304 } 305 306 /* flush */ 307 (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0); 308 309 /* set initial cmd byte */ 310 if (!pckbc_put8042cmd(t)) { 311 printf("kbc: 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(iot, ioh_d, ioh_c, 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("kbc: 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("kbc: 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("kbc: aux echo error 1\n"); 354 goto nomouse; 355 } 356 if (!pckbc_wait_output(iot, ioh_c)) { 357 printf("kbc: aux echo error 2\n"); 358 goto nomouse; 359 } 360 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */ 361 res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1); 362 363 if (ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) { 364 /* 365 * The following code is necessary to find the aux port on the 366 * oqo-1 machine, among others. However if confuses old 367 * (non-ps/2) keyboard controllers (at least UMC880x again). 368 */ 369 if (res == -1) { 370 /* Read of aux echo timed out, try again */ 371 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) 372 goto nomouse; 373 if (!pckbc_wait_output(iot, ioh_c)) 374 goto nomouse; 375 bus_space_write_1(iot, ioh_d, 0, 0x5a); 376 res = pckbc_poll_data1(iot, ioh_d, ioh_c, 377 PCKBC_AUX_SLOT, 1); 378 #ifdef PCKBCDEBUG 379 printf("kbc: aux echo: %x\n", res); 380 #endif 381 } 382 } 383 384 if (res != -1) { 385 /* 386 * In most cases, the 0x5a gets echoed. 387 * Some old controllers (Gateway 2000 circa 1993) 388 * return 0xfe here. 389 * We are satisfied if there is anything in the 390 * aux output buffer. 391 */ 392 #ifdef PCKBCDEBUG 393 printf("kbc: aux echo: %x\n", res); 394 #endif 395 t->t_haveaux = 1; 396 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT)) 397 cmdbits |= KC8_MENABLE; 398 } 399 #ifdef PCKBCDEBUG 400 else 401 printf("kbc: aux echo test failed\n"); 402 #endif 403 404 nomouse: 405 /* enable needed interrupts */ 406 t->t_cmdbyte |= cmdbits; 407 if (!pckbc_put8042cmd(t)) 408 printf("kbc: cmd word write error\n"); 409 } 410 411 int 412 pckbcprint(aux, pnp) 413 void *aux; 414 const char *pnp; 415 { 416 struct pckbc_attach_args *pa = aux; 417 418 if (!pnp) 419 printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]); 420 return (QUIET); 421 } 422 423 void 424 pckbc_init_slotdata(q) 425 struct pckbc_slotdata *q; 426 { 427 int i; 428 TAILQ_INIT(&q->cmdqueue); 429 TAILQ_INIT(&q->freequeue); 430 431 for (i = 0; i < NCMD; i++) { 432 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next); 433 } 434 q->polling = 0; 435 } 436 437 void 438 pckbc_flush(self, slot) 439 pckbc_tag_t self; 440 pckbc_slot_t slot; 441 { 442 struct pckbc_internal *t = self; 443 444 (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c, 445 slot, t->t_haveaux); 446 } 447 448 int 449 pckbc_poll_data(self, slot) 450 pckbc_tag_t self; 451 pckbc_slot_t slot; 452 { 453 struct pckbc_internal *t = self; 454 struct pckbc_slotdata *q = t->t_slotdata[slot]; 455 int c; 456 457 c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c, 458 slot, t->t_haveaux); 459 if (c != -1 && q && CMD_IN_QUEUE(q)) { 460 /* we jumped into a running command - try to 461 deliver the response */ 462 if (pckbc_cmdresponse(t, slot, c)) 463 return (-1); 464 } 465 return (c); 466 } 467 468 /* 469 * switch scancode translation on / off 470 * return nonzero on success 471 */ 472 int 473 pckbc_xt_translation(self, slot, on) 474 pckbc_tag_t self; 475 pckbc_slot_t slot; 476 int on; 477 { 478 struct pckbc_internal *t = self; 479 int ison; 480 481 if (ISSET(t->t_flags, PCKBC_CANT_TRANSLATE) || 482 slot != PCKBC_KBD_SLOT) { 483 /* translation only for kbd slot */ 484 if (on) 485 return (0); 486 else 487 return (1); 488 } 489 490 ison = t->t_cmdbyte & KC8_TRANS; 491 if ((on && ison) || (!on && !ison)) 492 return (1); 493 494 t->t_cmdbyte ^= KC8_TRANS; 495 if (!pckbc_put8042cmd(t)) 496 return (0); 497 498 /* read back to be sure */ 499 if (!pckbc_get8042cmd(t)) 500 return (0); 501 502 ison = t->t_cmdbyte & KC8_TRANS; 503 if ((on && ison) || (!on && !ison)) 504 return (1); 505 return (0); 506 } 507 508 static struct pckbc_portcmd { 509 u_char cmd_en, cmd_dis; 510 } pckbc_portcmd[2] = { 511 { 512 KBC_KBDENABLE, KBC_KBDDISABLE, 513 }, { 514 KBC_AUXENABLE, KBC_AUXDISABLE, 515 } 516 }; 517 518 void 519 pckbc_slot_enable(self, slot, on) 520 pckbc_tag_t self; 521 pckbc_slot_t slot; 522 int on; 523 { 524 struct pckbc_internal *t = (struct pckbc_internal *)self; 525 struct pckbc_portcmd *cmd; 526 527 cmd = &pckbc_portcmd[slot]; 528 529 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, 530 on ? cmd->cmd_en : cmd->cmd_dis)) 531 printf("pckbc_slot_enable(%d) failed\n", on); 532 533 if (slot == PCKBC_KBD_SLOT) { 534 if (on) 535 timeout_add_sec(&t->t_poll, 1); 536 else 537 timeout_del(&t->t_poll); 538 } 539 } 540 541 void 542 pckbc_set_poll(self, slot, on) 543 pckbc_tag_t self; 544 pckbc_slot_t slot; 545 int on; 546 { 547 struct pckbc_internal *t = (struct pckbc_internal *)self; 548 549 t->t_slotdata[slot]->polling = on; 550 551 if (!on) { 552 int s; 553 554 /* 555 * If disabling polling on a device that's been configured, 556 * make sure there are no bytes left in the FIFO, holding up 557 * the interrupt line. Otherwise we won't get any further 558 * interrupts. 559 */ 560 if (t->t_sc) { 561 s = spltty(); 562 pckbcintr_internal(t, t->t_sc); 563 splx(s); 564 } 565 } 566 } 567 568 /* 569 * Pass command to device, poll for ACK and data. 570 * to be called at spltty() 571 */ 572 static void 573 pckbc_poll_cmd1(t, slot, cmd) 574 struct pckbc_internal *t; 575 pckbc_slot_t slot; 576 struct pckbc_devcmd *cmd; 577 { 578 bus_space_tag_t iot = t->t_iot; 579 bus_space_handle_t ioh_d = t->t_ioh_d; 580 bus_space_handle_t ioh_c = t->t_ioh_c; 581 int i, c = 0; 582 583 while (cmd->cmdidx < cmd->cmdlen) { 584 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) { 585 printf("pckbc_cmd: send error\n"); 586 cmd->status = EIO; 587 return; 588 } 589 for (i = 10; i; i--) { /* 1s ??? */ 590 c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot, 591 t->t_haveaux); 592 if (c != -1) 593 break; 594 } 595 596 if (c == KBC_DEVCMD_ACK) { 597 cmd->cmdidx++; 598 continue; 599 } 600 if (c == KBC_DEVCMD_RESEND) { 601 #ifdef PCKBCDEBUG 602 printf("pckbc_cmd: RESEND\n"); 603 #endif 604 if (cmd->retries++ < 5) 605 continue; 606 else { 607 #ifdef PCKBCDEBUG 608 printf("pckbc: cmd failed\n"); 609 #endif 610 cmd->status = EIO; 611 return; 612 } 613 } 614 if (c == -1) { 615 #ifdef PCKBCDEBUG 616 printf("pckbc_cmd: timeout\n"); 617 #endif 618 cmd->status = EIO; 619 return; 620 } 621 #ifdef PCKBCDEBUG 622 printf("pckbc_cmd: lost 0x%x\n", c); 623 #endif 624 } 625 626 while (cmd->responseidx < cmd->responselen) { 627 if (cmd->flags & KBC_CMDFLAG_SLOW) 628 i = 100; /* 10s ??? */ 629 else 630 i = 10; /* 1s ??? */ 631 while (i--) { 632 c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot, 633 t->t_haveaux); 634 if (c != -1) 635 break; 636 } 637 if (c == -1) { 638 #ifdef PCKBCDEBUG 639 printf("pckbc_cmd: no data\n"); 640 #endif 641 cmd->status = ETIMEDOUT; 642 return; 643 } else 644 cmd->response[cmd->responseidx++] = c; 645 } 646 } 647 648 /* for use in autoconfiguration */ 649 int 650 pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow) 651 pckbc_tag_t self; 652 pckbc_slot_t slot; 653 u_char *cmd; 654 int len, responselen; 655 u_char *respbuf; 656 int slow; 657 { 658 struct pckbc_devcmd nc; 659 660 if ((len > 4) || (responselen > 4)) 661 return (EINVAL); 662 663 bzero(&nc, sizeof(nc)); 664 bcopy(cmd, nc.cmd, len); 665 nc.cmdlen = len; 666 nc.responselen = responselen; 667 nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0); 668 669 pckbc_poll_cmd1(self, slot, &nc); 670 671 if (nc.status == 0 && respbuf) 672 bcopy(nc.response, respbuf, responselen); 673 674 return (nc.status); 675 } 676 677 /* 678 * Clean up a command queue, throw away everything. 679 */ 680 void 681 pckbc_cleanqueue(q) 682 struct pckbc_slotdata *q; 683 { 684 struct pckbc_devcmd *cmd; 685 #ifdef PCKBCDEBUG 686 int i; 687 #endif 688 689 while ((cmd = TAILQ_FIRST(&q->cmdqueue))) { 690 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 691 #ifdef PCKBCDEBUG 692 printf("pckbc_cleanqueue: removing"); 693 for (i = 0; i < cmd->cmdlen; i++) 694 printf(" %02x", cmd->cmd[i]); 695 printf("\n"); 696 #endif 697 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 698 } 699 } 700 701 /* 702 * Timeout error handler: clean queues and data port. 703 * XXX could be less invasive. 704 */ 705 void 706 pckbc_cleanup(self) 707 void *self; 708 { 709 struct pckbc_internal *t = self; 710 int s; 711 712 printf("pckbc: command timeout\n"); 713 714 s = spltty(); 715 716 if (t->t_slotdata[PCKBC_KBD_SLOT]) 717 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]); 718 if (t->t_slotdata[PCKBC_AUX_SLOT]) 719 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]); 720 721 while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) { 722 KBD_DELAY; 723 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 724 } 725 726 /* reset KBC? */ 727 728 splx(s); 729 } 730 731 /* 732 * Pass command to device during normal operation. 733 * to be called at spltty() 734 */ 735 void 736 pckbc_start(t, slot) 737 struct pckbc_internal *t; 738 pckbc_slot_t slot; 739 { 740 struct pckbc_slotdata *q = t->t_slotdata[slot]; 741 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue); 742 743 if (q->polling) { 744 do { 745 pckbc_poll_cmd1(t, slot, cmd); 746 if (cmd->status) 747 printf("pckbc_start: command error\n"); 748 749 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 750 if (cmd->flags & KBC_CMDFLAG_SYNC) 751 wakeup(cmd); 752 else { 753 timeout_del(&t->t_cleanup); 754 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 755 } 756 cmd = TAILQ_FIRST(&q->cmdqueue); 757 } while (cmd); 758 return; 759 } 760 761 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) { 762 printf("pckbc_start: send error\n"); 763 /* XXX what now? */ 764 return; 765 } 766 } 767 768 /* 769 * Handle command responses coming in asynchronously, 770 * return nonzero if valid response. 771 * to be called at spltty() 772 */ 773 int 774 pckbc_cmdresponse(t, slot, data) 775 struct pckbc_internal *t; 776 pckbc_slot_t slot; 777 u_char data; 778 { 779 struct pckbc_slotdata *q = t->t_slotdata[slot]; 780 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue); 781 #ifdef DIAGNOSTIC 782 if (!cmd) 783 panic("pckbc_cmdresponse: no active command"); 784 #endif 785 if (cmd->cmdidx < cmd->cmdlen) { 786 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND) 787 return (0); 788 789 if (data == KBC_DEVCMD_RESEND) { 790 if (cmd->retries++ < 5) { 791 /* try again last command */ 792 goto restart; 793 } else { 794 #ifdef PCKBCDEBUG 795 printf("pckbc: cmd failed\n"); 796 #endif 797 cmd->status = EIO; 798 /* dequeue */ 799 } 800 } else { 801 if (++cmd->cmdidx < cmd->cmdlen) 802 goto restart; 803 if (cmd->responselen) 804 return (1); 805 /* else dequeue */ 806 } 807 } else if (cmd->responseidx < cmd->responselen) { 808 cmd->response[cmd->responseidx++] = data; 809 if (cmd->responseidx < cmd->responselen) 810 return (1); 811 /* else dequeue */ 812 } else 813 return (0); 814 815 /* dequeue: */ 816 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 817 if (cmd->flags & KBC_CMDFLAG_SYNC) 818 wakeup(cmd); 819 else { 820 timeout_del(&t->t_cleanup); 821 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 822 } 823 if (!CMD_IN_QUEUE(q)) 824 return (1); 825 restart: 826 pckbc_start(t, slot); 827 return (1); 828 } 829 830 /* 831 * Put command into the device's command queue, return zero or errno. 832 */ 833 int 834 pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf) 835 pckbc_tag_t self; 836 pckbc_slot_t slot; 837 u_char *cmd; 838 int len, responselen, sync; 839 u_char *respbuf; 840 { 841 struct pckbc_internal *t = self; 842 struct pckbc_slotdata *q = t->t_slotdata[slot]; 843 struct pckbc_devcmd *nc; 844 int s, isactive, res = 0; 845 846 if ((len > 4) || (responselen > 4)) 847 return (EINVAL); 848 s = spltty(); 849 nc = TAILQ_FIRST(&q->freequeue); 850 if (nc) { 851 TAILQ_REMOVE(&q->freequeue, nc, next); 852 } 853 splx(s); 854 if (!nc) 855 return (ENOMEM); 856 857 bzero(nc, sizeof(*nc)); 858 bcopy(cmd, nc->cmd, len); 859 nc->cmdlen = len; 860 nc->responselen = responselen; 861 nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0); 862 863 s = spltty(); 864 865 if (q->polling && sync) { 866 /* 867 * XXX We should poll until the queue is empty. 868 * But we don't come here normally, so make 869 * it simple and throw away everything. 870 */ 871 pckbc_cleanqueue(q); 872 } 873 874 isactive = CMD_IN_QUEUE(q); 875 TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next); 876 if (!isactive) 877 pckbc_start(t, slot); 878 879 if (q->polling) 880 res = (sync ? nc->status : 0); 881 else if (sync) { 882 if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) { 883 TAILQ_REMOVE(&q->cmdqueue, nc, next); 884 pckbc_cleanup(t); 885 } else 886 res = nc->status; 887 } else 888 timeout_add_sec(&t->t_cleanup, 1); 889 890 if (sync) { 891 if (respbuf) 892 bcopy(nc->response, respbuf, responselen); 893 TAILQ_INSERT_TAIL(&q->freequeue, nc, next); 894 } 895 896 splx(s); 897 898 return (res); 899 } 900 901 void 902 pckbc_set_inputhandler(self, slot, func, arg, name) 903 pckbc_tag_t self; 904 pckbc_slot_t slot; 905 pckbc_inputfcn func; 906 void *arg; 907 char *name; 908 { 909 struct pckbc_internal *t = (struct pckbc_internal *)self; 910 struct pckbc_softc *sc = t->t_sc; 911 912 if (slot >= PCKBC_NSLOTS) 913 panic("pckbc_set_inputhandler: bad slot %d", slot); 914 915 (*sc->intr_establish)(sc, slot); 916 917 sc->inputhandler[slot] = func; 918 sc->inputarg[slot] = arg; 919 sc->subname[slot] = name; 920 921 if (pckbc_console && slot == PCKBC_KBD_SLOT) 922 timeout_add_sec(&t->t_poll, 1); 923 } 924 925 void 926 pckbc_poll(v) 927 void *v; 928 { 929 struct pckbc_internal *t = v; 930 int s; 931 932 s = spltty(); 933 (void)pckbcintr_internal(t, t->t_sc); 934 timeout_add_sec(&t->t_poll, 1); 935 splx(s); 936 } 937 938 int 939 pckbcintr(vsc) 940 void *vsc; 941 { 942 struct pckbc_softc *sc = (struct pckbc_softc *)vsc; 943 944 return (pckbcintr_internal(sc->id, sc)); 945 } 946 947 int 948 pckbcintr_internal(t, sc) 949 struct pckbc_internal *t; 950 struct pckbc_softc *sc; 951 { 952 u_char stat; 953 pckbc_slot_t slot; 954 struct pckbc_slotdata *q; 955 int served = 0, data; 956 957 /* reschedule timeout further into the idle times */ 958 if (timeout_pending(&t->t_poll)) 959 timeout_add_sec(&t->t_poll, 1); 960 961 for(;;) { 962 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); 963 if (!(stat & KBS_DIB)) 964 break; 965 966 served = 1; 967 968 slot = (t->t_haveaux && (stat & 0x20)) ? 969 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT; 970 q = t->t_slotdata[slot]; 971 972 if (!q) { 973 /* XXX do something for live insertion? */ 974 printf("pckbcintr: no dev for slot %d\n", slot); 975 KBD_DELAY; 976 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 977 continue; 978 } 979 980 if (q->polling) 981 break; /* pckbc_poll_data() will get it */ 982 983 KBD_DELAY; 984 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 985 986 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data)) 987 continue; 988 989 if (sc != NULL) { 990 if (sc->inputhandler[slot]) 991 (*sc->inputhandler[slot])(sc->inputarg[slot], 992 data); 993 #ifdef PCKBCDEBUG 994 else 995 printf("pckbcintr: slot %d lost %d\n", 996 slot, data); 997 #endif 998 } 999 } 1000 1001 return (served); 1002 } 1003 1004 int 1005 pckbc_cnattach(iot, addr, cmd_offset, slot, flags) 1006 bus_space_tag_t iot; 1007 bus_addr_t addr; 1008 bus_size_t cmd_offset; 1009 pckbc_slot_t slot; 1010 int flags; 1011 { 1012 bus_space_handle_t ioh_d, ioh_c; 1013 int res = 0; 1014 1015 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d)) 1016 return (ENXIO); 1017 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) { 1018 bus_space_unmap(iot, ioh_d, 1); 1019 return (ENXIO); 1020 } 1021 1022 pckbc_consdata.t_iot = iot; 1023 pckbc_consdata.t_ioh_d = ioh_d; 1024 pckbc_consdata.t_ioh_c = ioh_c; 1025 pckbc_consdata.t_addr = addr; 1026 pckbc_consdata.t_flags = flags; 1027 timeout_set(&pckbc_consdata.t_cleanup, pckbc_cleanup, &pckbc_consdata); 1028 timeout_set(&pckbc_consdata.t_poll, pckbc_poll, &pckbc_consdata); 1029 1030 /* flush */ 1031 (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0); 1032 1033 /* selftest? */ 1034 1035 /* init cmd byte, enable ports */ 1036 pckbc_consdata.t_cmdbyte = KC8_CPU; 1037 if (!pckbc_put8042cmd(&pckbc_consdata)) { 1038 printf("kbc: cmd word write error\n"); 1039 res = EIO; 1040 } 1041 1042 if (!res) { 1043 #if (NPCKBD > 0) 1044 res = pckbd_cnattach(&pckbc_consdata, slot); 1045 #else 1046 res = ENXIO; 1047 #endif /* NPCKBD > 0 */ 1048 } 1049 1050 if (res) { 1051 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1); 1052 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1); 1053 } else { 1054 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata; 1055 pckbc_init_slotdata(&pckbc_cons_slotdata); 1056 pckbc_console = 1; 1057 } 1058 1059 return (res); 1060 } 1061 1062 struct cfdriver pckbc_cd = { 1063 NULL, "pckbc", DV_DULL 1064 }; 1065