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