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