jcs's openbsd hax
openbsd
at jcs 1121 lines 26 kB view raw
1/* $OpenBSD: pckbc.c,v 1.55 2023/08/26 15:01:00 jmc 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/device.h> 34#include <sys/malloc.h> 35#include <sys/errno.h> 36#include <sys/queue.h> 37 38#include <machine/bus.h> 39#include <machine/cpu.h> 40 41#include <dev/ic/i8042reg.h> 42#include <dev/ic/pckbcvar.h> 43 44#include "pckbd.h" 45 46#if NPCKBD > 0 47#include <dev/pckbc/pckbdvar.h> 48#endif 49 50#ifdef PCKBCDEBUG 51#define DPRINTF(x...) do { printf(x); } while (0); 52#else 53#define DPRINTF(x...) 54#endif 55 56/* descriptor for one device command */ 57struct pckbc_devcmd { 58 TAILQ_ENTRY(pckbc_devcmd) next; 59 int flags; 60#define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */ 61#define KBC_CMDFLAG_SLOW 2 62#define KBC_CMDFLAG_QUEUED 4 /* descriptor on cmdqueue */ 63 u_char cmd[4]; 64 int cmdlen, cmdidx, retries; 65 u_char response[4]; 66 int status, responselen, responseidx; 67}; 68 69/* data per slave device */ 70struct pckbc_slotdata { 71 int polling; /* don't read data port in interrupt handler */ 72 TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */ 73 TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */ 74#define NCMD 5 75 struct pckbc_devcmd cmds[NCMD]; 76}; 77 78#define CMD_IN_QUEUE(q) (!TAILQ_EMPTY(&(q)->cmdqueue)) 79 80void pckbc_init_slotdata(struct pckbc_slotdata *); 81int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t, int); 82int pckbc_submatch_locators(struct device *, void *, void *); 83int pckbc_submatch(struct device *, void *, void *); 84int pckbcprint(void *, const char *); 85 86struct pckbc_internal pckbc_consdata; 87int pckbc_console_attached; 88 89int pckbc_console; 90static struct pckbc_slotdata pckbc_cons_slotdata; 91 92static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t); 93 94static int pckbc_get8042cmd(struct pckbc_internal *); 95static int pckbc_put8042cmd(struct pckbc_internal *); 96static int pckbc_send_devcmd(struct pckbc_internal *, pckbc_slot_t, 97 u_char); 98static void pckbc_poll_cmd1(struct pckbc_internal *, pckbc_slot_t, 99 struct pckbc_devcmd *); 100 101void pckbc_cleanqueues(struct pckbc_internal *); 102void pckbc_cleanqueue(struct pckbc_slotdata *); 103void pckbc_cleanup(void *); 104void pckbc_poll(void *); 105int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char); 106void pckbc_start(struct pckbc_internal *, pckbc_slot_t); 107int pckbcintr_internal(struct pckbc_internal *, struct pckbc_softc *); 108 109const char *pckbc_slot_names[] = { "kbd", "aux" }; 110 111#define KBC_DEVCMD_ACK 0xfa 112#define KBC_DEVCMD_RESEND 0xfe 113#define KBC_DEVCMD_BAT_DONE 0xaa 114#define KBC_DEVCMD_BAT_FAIL 0xfc 115 116#define KBD_DELAY DELAY(8) 117 118static inline int 119pckbc_wait_output(bus_space_tag_t iot, 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 131int 132pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val) 133{ 134 if (!pckbc_wait_output(iot, ioh_c)) 135 return (0); 136 bus_space_write_1(iot, ioh_c, 0, val); 137 return (1); 138} 139 140int 141pckbc_poll_data1(bus_space_tag_t iot, bus_space_handle_t ioh_d, 142 bus_space_handle_t ioh_c, pckbc_slot_t slot, int checkaux) 143{ 144 int i; 145 u_char stat; 146 147 /* polls for ~100ms */ 148 for (i = 100; i; i--, delay(1000)) { 149 stat = bus_space_read_1(iot, ioh_c, 0); 150 if (stat & KBS_DIB) { 151 register u_char c; 152 153 KBD_DELAY; 154 CPU_BUSY_CYCLE(); 155 c = bus_space_read_1(iot, ioh_d, 0); 156 if (checkaux && (stat & KBS_AUXDATA)) { 157 if (slot != PCKBC_AUX_SLOT) { 158 DPRINTF("lost aux 0x%x\n", c); 159 continue; 160 } 161 } else { 162 if (slot == PCKBC_AUX_SLOT) { 163 DPRINTF("lost kbd 0x%x\n", c); 164 continue; 165 } else if (stat & KBS_AUXDATA) { 166 DPRINTF("discard aux data 0x%x\n", c); 167 continue; 168 } 169 } 170 return (c); 171 } 172 } 173 return (-1); 174} 175 176/* 177 * Get the current command byte. 178 */ 179static int 180pckbc_get8042cmd(struct pckbc_internal *t) 181{ 182 bus_space_tag_t iot = t->t_iot; 183 bus_space_handle_t ioh_d = t->t_ioh_d; 184 bus_space_handle_t ioh_c = t->t_ioh_c; 185 int data; 186 187 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE)) 188 return (0); 189 data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 190 t->t_haveaux); 191 if (data == -1) 192 return (0); 193 t->t_cmdbyte = data; 194 return (1); 195} 196 197/* 198 * Pass command byte to keyboard controller (8042). 199 */ 200static int 201pckbc_put8042cmd(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 215static int 216pckbc_send_devcmd(struct pckbc_internal *t, pckbc_slot_t slot, u_char val) 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 (slot == PCKBC_AUX_SLOT) { 223 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) 224 return (0); 225 } 226 if (!pckbc_wait_output(iot, ioh_c)) 227 return (0); 228 bus_space_write_1(iot, ioh_d, 0, val); 229 return (1); 230} 231 232int 233pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr) 234{ 235 if (pckbc_console && !pckbc_console_attached && 236 pckbc_consdata.t_iot == iot && 237 pckbc_consdata.t_addr == addr) 238 return (1); 239 return (0); 240} 241 242int 243pckbc_submatch_locators(struct device *parent, void *match, void *aux) 244{ 245 struct cfdata *cf = match; 246 struct pckbc_attach_args *pa = aux; 247 248 if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT && 249 cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot) 250 return (0); 251 return (1); 252} 253 254int 255pckbc_submatch(struct device *parent, void *match, void *aux) 256{ 257 struct cfdata *cf = match; 258 259 if (pckbc_submatch_locators(parent, match, aux) == 0) 260 return (0); 261 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 262} 263 264int 265pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot, int force) 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, pckbcprint, 274 force ? pckbc_submatch_locators : pckbc_submatch) != NULL); 275 276 if ((found || slot == PCKBC_AUX_SLOT) && !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 if (!found && slot == PCKBC_AUX_SLOT) { 284 /* 285 * Some machines don't handle disabling the aux slot 286 * completely and still generate data when the mouse is 287 * moved, so setup a dummy interrupt handler to discard 288 * this slot's data. 289 */ 290 pckbc_set_inputhandler(t, PCKBC_AUX_SLOT, NULL, sc, 291 NULL); 292 found = 1; 293 } 294 } 295 return (found); 296} 297 298void 299pckbc_attach(struct pckbc_softc *sc, int flags) 300{ 301 struct pckbc_internal *t; 302 bus_space_tag_t iot; 303 bus_space_handle_t ioh_d, ioh_c; 304 int haskbd = 0, res; 305 u_char cmdbits = 0; 306 307 t = sc->id; 308 iot = t->t_iot; 309 ioh_d = t->t_ioh_d; 310 ioh_c = t->t_ioh_c; 311 312 if (pckbc_console == 0) { 313 timeout_set(&t->t_cleanup, pckbc_cleanup, t); 314 timeout_set(&t->t_poll, pckbc_poll, t); 315 } 316 317 /* flush */ 318 (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0); 319 320 /* set initial cmd byte */ 321 if (!pckbc_put8042cmd(t)) { 322#if defined(__i386__) || defined(__amd64__) 323 if (!ISSET(flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) { 324 pckbc_release_console(); 325 return; 326 } 327#endif 328 printf("kbc: cmd word write error\n"); 329 return; 330 } 331 332/* 333 * XXX Don't check the keyboard port. There are broken keyboard controllers 334 * which don't pass the test but work normally otherwise. 335 */ 336#if 0 337 /* 338 * check kbd port ok 339 */ 340 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST)) 341 return; 342 res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0); 343 344 /* 345 * Normally, we should get a "0" here. 346 * But there are keyboard controllers behaving differently. 347 */ 348 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) { 349#ifdef PCKBCDEBUG 350 if (res != 0) 351 printf("kbc: returned %x on kbd slot test\n", res); 352#endif 353 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 0)) { 354 cmdbits |= KC8_KENABLE; 355 haskbd = 1; 356 } 357 } else { 358 printf("kbc: kbd port test: %x\n", res); 359 return; 360 } 361#else 362 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 0)) { 363 cmdbits |= KC8_KENABLE; 364 haskbd = 1; 365 } 366#endif /* 0 */ 367 368 /* 369 * Check aux port ok. 370 * Avoid KBC_AUXTEST because it hangs some older controllers 371 * (eg UMC880?). 372 */ 373 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) { 374 printf("kbc: aux echo error 1\n"); 375 goto nomouse; 376 } 377 if (!pckbc_wait_output(iot, ioh_c)) { 378 printf("kbc: aux echo error 2\n"); 379 goto nomouse; 380 } 381 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */ 382 res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1); 383 384 if (ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) { 385 /* 386 * The following code is necessary to find the aux port on the 387 * oqo-1 machine, among others. However if confuses old 388 * (non-ps/2) keyboard controllers (at least UMC880x again). 389 */ 390 if (res == -1) { 391 /* Read of aux echo timed out, try again */ 392 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) 393 goto nomouse; 394 if (!pckbc_wait_output(iot, ioh_c)) 395 goto nomouse; 396 bus_space_write_1(iot, ioh_d, 0, 0x5a); 397 res = pckbc_poll_data1(iot, ioh_d, ioh_c, 398 PCKBC_AUX_SLOT, 1); 399 DPRINTF("kbc: aux echo: %x\n", res); 400 } 401 } 402 403 if (res != -1) { 404 /* 405 * In most cases, the 0x5a gets echoed. 406 * Some old controllers (Gateway 2000 circa 1993) 407 * return 0xfe here. 408 * We are satisfied if there is anything in the 409 * aux output buffer. 410 */ 411 DPRINTF("kbc: aux echo: %x\n", res); 412 t->t_haveaux = 1; 413 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT, 0)) 414 cmdbits |= KC8_MENABLE; 415 } 416#ifdef PCKBCDEBUG 417 else 418 printf("kbc: aux echo test failed\n"); 419#endif 420 421#if defined(__i386__) || defined(__amd64__) 422 if (haskbd == 0 && !ISSET(flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) { 423 if (t->t_haveaux) { 424 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 1)) 425 cmdbits |= KC8_KENABLE; 426 } else { 427 pckbc_release_console(); 428 } 429 } 430#endif 431 432nomouse: 433 /* enable needed interrupts */ 434 t->t_cmdbyte |= cmdbits; 435 if (!pckbc_put8042cmd(t)) 436 printf("kbc: cmd word write error\n"); 437} 438 439int 440pckbcprint(void *aux, const char *pnp) 441{ 442 struct pckbc_attach_args *pa = aux; 443 444 if (!pnp) 445 printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]); 446 return (QUIET); 447} 448 449void 450pckbc_release_console(void) 451{ 452#if defined(__i386__) || defined(__amd64__) 453 /* 454 * If there is no keyboard present, yet we are the console, 455 * we might be on a legacy-free PC where the PS/2 emulated 456 * keyboard was elected as console, but went away as soon 457 * as the USB controller drivers attached. 458 * 459 * In that case, we want to release ourselves from console 460 * duties, unless we have been able to attach a mouse, 461 * which would mean this is a real PS/2 controller 462 * after all. 463 */ 464 if (pckbc_console != 0) { 465 extern void wscn_input_init(int); 466 467 pckbc_console = 0; 468 wscn_input_init(1); 469 } 470#endif 471} 472 473void 474pckbc_init_slotdata(struct pckbc_slotdata *q) 475{ 476 int i; 477 TAILQ_INIT(&q->cmdqueue); 478 TAILQ_INIT(&q->freequeue); 479 480 for (i = 0; i < NCMD; i++) { 481 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next); 482 } 483 q->polling = 0; 484} 485 486void 487pckbc_flush(pckbc_tag_t self, pckbc_slot_t slot) 488{ 489 struct pckbc_internal *t = self; 490 491 (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c, 492 slot, t->t_haveaux); 493} 494 495int 496pckbc_poll_data(pckbc_tag_t self, pckbc_slot_t slot) 497{ 498 struct pckbc_internal *t = self; 499 struct pckbc_slotdata *q = t->t_slotdata[slot]; 500 int c; 501 502 c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c, 503 slot, t->t_haveaux); 504 if (c != -1 && q && CMD_IN_QUEUE(q)) { 505 /* we jumped into a running command - try to 506 deliver the response */ 507 if (pckbc_cmdresponse(t, slot, c)) 508 return (-1); 509 } 510 return (c); 511} 512 513/* 514 * set scancode translation on 515 */ 516int 517pckbc_xt_translation(pckbc_tag_t self, int *table) 518{ 519 struct pckbc_internal *t = self; 520 521#ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */ 522 if ((t->t_flags & PCKBC_CANT_TRANSLATE) != 0) { 523 /* Hardware lacks translation capability. Nothing to do! */ 524 if (t->t_flags & PCKBC_FIXED_SET2) 525 *table = 2; 526 else /* PCKBC_FIXED_SET3 */ 527 *table = 3; 528 return (-1); 529 } 530#endif 531 532 if (t->t_cmdbyte & KC8_TRANS) 533 return (0); 534 535 t->t_cmdbyte |= KC8_TRANS; 536 if (!pckbc_put8042cmd(t)) 537 return (-1); 538 539 /* read back to be sure */ 540 if (!pckbc_get8042cmd(t)) 541 return (-1); 542 543 return (t->t_cmdbyte & KC8_TRANS) ? (0) : (-1); 544} 545 546static struct pckbc_portcmd { 547 u_char cmd_en, cmd_dis; 548} pckbc_portcmd[2] = { 549 { 550 KBC_KBDENABLE, KBC_KBDDISABLE, 551 }, { 552 KBC_AUXENABLE, KBC_AUXDISABLE, 553 } 554}; 555 556void 557pckbc_slot_enable(pckbc_tag_t self, pckbc_slot_t slot, int on) 558{ 559 struct pckbc_internal *t = (struct pckbc_internal *)self; 560 struct pckbc_portcmd *cmd; 561 562 cmd = &pckbc_portcmd[slot]; 563 564 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, 565 on ? cmd->cmd_en : cmd->cmd_dis)) 566 printf("pckbc_slot_enable(%d) failed\n", on); 567 568 if (slot == PCKBC_KBD_SLOT) { 569 if (on) 570 timeout_add_sec(&t->t_poll, 1); 571 else 572 timeout_del(&t->t_poll); 573 } 574} 575 576void 577pckbc_set_poll(pckbc_tag_t self, pckbc_slot_t slot, int on) 578{ 579 struct pckbc_internal *t = (struct pckbc_internal *)self; 580 581 t->t_slotdata[slot]->polling = on; 582 583 if (!on) { 584 int s; 585 586 /* 587 * If disabling polling on a device that's been configured, 588 * make sure there are no bytes left in the FIFO, holding up 589 * the interrupt line. Otherwise we won't get any further 590 * interrupts. 591 */ 592 if (t->t_sc) { 593 s = spltty(); 594 pckbcintr_internal(t, t->t_sc); 595 splx(s); 596 } 597 } 598} 599 600/* 601 * Pass command to device, poll for ACK and data. 602 * to be called at spltty() 603 */ 604static void 605pckbc_poll_cmd1(struct pckbc_internal *t, pckbc_slot_t slot, 606 struct pckbc_devcmd *cmd) 607{ 608 bus_space_tag_t iot = t->t_iot; 609 bus_space_handle_t ioh_d = t->t_ioh_d; 610 bus_space_handle_t ioh_c = t->t_ioh_c; 611 int i, c = 0; 612 613 while (cmd->cmdidx < cmd->cmdlen) { 614 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) { 615 printf("pckbc_cmd: send error\n"); 616 cmd->status = EIO; 617 return; 618 } 619 for (i = 10; i; i--) { /* 1s ??? */ 620 c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot, 621 t->t_haveaux); 622 if (c != -1) 623 break; 624 } 625 626 switch (c) { 627 case KBC_DEVCMD_ACK: 628 cmd->cmdidx++; 629 continue; 630 /* 631 * Some legacy free PCs keep returning Basic Assurance Test 632 * (BAT) instead of something usable, so fail gracefully. 633 */ 634 case KBC_DEVCMD_RESEND: 635 case KBC_DEVCMD_BAT_DONE: 636 case KBC_DEVCMD_BAT_FAIL: 637 DPRINTF("pckbc_cmd: %s\n", 638 c == KBC_DEVCMD_RESEND ? "RESEND": "BAT"); 639 if (cmd->retries++ < 5) 640 continue; 641 642 DPRINTF("pckbc_cmd: cmd failed\n"); 643 cmd->status = ENXIO; 644 return; 645 case -1: 646 DPRINTF("pckbc_cmd: timeout\n"); 647 cmd->status = EIO; 648 return; 649 default: 650 DPRINTF("pckbc_cmd: lost 0x%x\n", c); 651 } 652 } 653 654 while (cmd->responseidx < cmd->responselen) { 655 if (cmd->flags & KBC_CMDFLAG_SLOW) 656 i = 100; /* 10s ??? */ 657 else 658 i = 10; /* 1s ??? */ 659 while (i--) { 660 c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot, 661 t->t_haveaux); 662 if (c != -1) 663 break; 664 } 665 if (c == -1) { 666 DPRINTF("pckbc_cmd: no data\n"); 667 cmd->status = ETIMEDOUT; 668 return; 669 } else 670 cmd->response[cmd->responseidx++] = c; 671 } 672} 673 674/* for use in autoconfiguration */ 675int 676pckbc_poll_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len, 677 int responselen, u_char *respbuf, int slow) 678{ 679 struct pckbc_devcmd nc; 680 681 if ((len > 4) || (responselen > 4)) 682 return (EINVAL); 683 684 bzero(&nc, sizeof(nc)); 685 memcpy(nc.cmd, cmd, len); 686 nc.cmdlen = len; 687 nc.responselen = responselen; 688 nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0); 689 690 pckbc_poll_cmd1(self, slot, &nc); 691 692 if (nc.status == 0 && respbuf) 693 memcpy(respbuf, nc.response, responselen); 694 695 return (nc.status); 696} 697 698/* 699 * Clean up a command queue, throw away everything. 700 */ 701void 702pckbc_cleanqueue(struct pckbc_slotdata *q) 703{ 704 struct pckbc_devcmd *cmd; 705#ifdef PCKBCDEBUG 706 int i; 707#endif 708 709 while ((cmd = TAILQ_FIRST(&q->cmdqueue))) { 710 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 711 cmd->flags &= ~KBC_CMDFLAG_QUEUED; 712#ifdef PCKBCDEBUG 713 printf("pckbc_cleanqueue: removing"); 714 for (i = 0; i < cmd->cmdlen; i++) 715 printf(" %02x", cmd->cmd[i]); 716 printf("\n"); 717#endif 718 /* 719 * A synchronous command on the cmdqueue is currently owned by a 720 * sleeping proc. The same proc is responsible for putting it 721 * back on the freequeue once awake. 722 */ 723 if (cmd->flags & KBC_CMDFLAG_SYNC) 724 continue; 725 726 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 727 } 728} 729 730void 731pckbc_cleanqueues(struct pckbc_internal *t) 732{ 733 if (t->t_slotdata[PCKBC_KBD_SLOT]) 734 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]); 735 if (t->t_slotdata[PCKBC_AUX_SLOT]) 736 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]); 737} 738 739/* 740 * Timeout error handler: clean queues and data port. 741 * XXX could be less invasive. 742 */ 743void 744pckbc_cleanup(void *self) 745{ 746 struct pckbc_internal *t = self; 747 int s; 748 749 printf("pckbc: command timeout\n"); 750 751 s = spltty(); 752 753 pckbc_cleanqueues(t); 754 755 while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) { 756 KBD_DELAY; 757 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 758 } 759 760 /* reset KBC? */ 761 762 splx(s); 763} 764 765/* 766 * Stop the keyboard controller when we are going to suspend 767 */ 768void 769pckbc_stop(struct pckbc_softc *sc) 770{ 771 struct pckbc_internal *t = sc->id; 772 773 timeout_del(&t->t_poll); 774 pckbc_cleanqueues(t); 775 timeout_del(&t->t_cleanup); 776} 777 778/* 779 * Reset the keyboard controller in a violent fashion; normally done 780 * after suspend/resume when we do not trust the machine. 781 */ 782void 783pckbc_reset(struct pckbc_softc *sc) 784{ 785 struct pckbc_internal *t = sc->id; 786 bus_space_tag_t iot = t->t_iot; 787 bus_space_handle_t ioh_d = t->t_ioh_d, ioh_c = t->t_ioh_c; 788 789 pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0); 790 /* KBC selftest */ 791 if (pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST) == 0) 792 return; 793 pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0); 794 (void)pckbc_put8042cmd(t); 795 pckbcintr_internal(t->t_sc->id, t->t_sc); 796} 797 798/* 799 * Pass command to device during normal operation. 800 * to be called at spltty() 801 */ 802void 803pckbc_start(struct pckbc_internal *t, pckbc_slot_t slot) 804{ 805 struct pckbc_slotdata *q = t->t_slotdata[slot]; 806 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue); 807 808 if (q->polling) { 809 do { 810 pckbc_poll_cmd1(t, slot, cmd); 811 if (cmd->status) 812 printf("pckbc_start: command error\n"); 813 814 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 815 cmd->flags &= ~KBC_CMDFLAG_QUEUED; 816 if (cmd->flags & KBC_CMDFLAG_SYNC) { 817 wakeup(cmd); 818 } else { 819 timeout_del(&t->t_cleanup); 820 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 821 } 822 cmd = TAILQ_FIRST(&q->cmdqueue); 823 } while (cmd); 824 return; 825 } 826 827 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) { 828 printf("pckbc_start: send error\n"); 829 /* XXX what now? */ 830 return; 831 } 832} 833 834/* 835 * Handle command responses coming in asynchronously, 836 * return nonzero if valid response. 837 * to be called at spltty() 838 */ 839int 840pckbc_cmdresponse(struct pckbc_internal *t, pckbc_slot_t slot, u_char data) 841{ 842 struct pckbc_slotdata *q = t->t_slotdata[slot]; 843 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue); 844#ifdef DIAGNOSTIC 845 if (!cmd) 846 panic("pckbc_cmdresponse: no active command"); 847#endif 848 if (cmd->cmdidx < cmd->cmdlen) { 849 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND) 850 return (0); 851 852 if (data == KBC_DEVCMD_RESEND) { 853 if (cmd->retries++ < 5) { 854 /* try again last command */ 855 goto restart; 856 } else { 857 DPRINTF("pckbc: cmd failed\n"); 858 cmd->status = ENXIO; 859 /* dequeue */ 860 } 861 } else { 862 if (++cmd->cmdidx < cmd->cmdlen) 863 goto restart; 864 if (cmd->responselen) 865 return (1); 866 /* else dequeue */ 867 } 868 } else if (cmd->responseidx < cmd->responselen) { 869 cmd->response[cmd->responseidx++] = data; 870 if (cmd->responseidx < cmd->responselen) 871 return (1); 872 /* else dequeue */ 873 } else 874 return (0); 875 876 /* dequeue: */ 877 TAILQ_REMOVE(&q->cmdqueue, cmd, next); 878 cmd->flags &= ~KBC_CMDFLAG_QUEUED; 879 if (cmd->flags & KBC_CMDFLAG_SYNC) { 880 wakeup(cmd); 881 } else { 882 timeout_del(&t->t_cleanup); 883 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next); 884 } 885 cmd = TAILQ_FIRST(&q->cmdqueue); 886 if (cmd == NULL) 887 return (1); 888restart: 889 pckbc_start(t, slot); 890 return (1); 891} 892 893/* 894 * Put command into the device's command queue, return zero or errno. 895 */ 896int 897pckbc_enqueue_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len, 898 int responselen, int sync, u_char *respbuf) 899{ 900 struct pckbc_internal *t = self; 901 struct pckbc_slotdata *q = t->t_slotdata[slot]; 902 struct pckbc_devcmd *nc; 903 int s, isactive, res = 0; 904 905 if ((len > 4) || (responselen > 4)) 906 return (EINVAL); 907 s = spltty(); 908 nc = TAILQ_FIRST(&q->freequeue); 909 if (nc) { 910 TAILQ_REMOVE(&q->freequeue, nc, next); 911 } 912 splx(s); 913 if (!nc) 914 return (ENOMEM); 915 916 bzero(nc, sizeof(*nc)); 917 memcpy(nc->cmd, cmd, len); 918 nc->cmdlen = len; 919 nc->responselen = responselen; 920 nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0); 921 922 s = spltty(); 923 924 if (q->polling && sync) { 925 /* 926 * XXX We should poll until the queue is empty. 927 * But we don't come here normally, so make 928 * it simple and throw away everything. 929 */ 930 pckbc_cleanqueue(q); 931 } 932 933 isactive = CMD_IN_QUEUE(q); 934 nc->flags |= KBC_CMDFLAG_QUEUED; 935 TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next); 936 if (!isactive) 937 pckbc_start(t, slot); 938 939 if (q->polling) 940 res = (sync ? nc->status : 0); 941 else if (sync) { 942 if ((res = tsleep_nsec(nc, 0, "kbccmd", SEC_TO_NSEC(1)))) { 943 pckbc_cleanup(t); 944 } else { 945 /* 946 * Under certain circumstances, such as during suspend, 947 * tsleep() becomes a no-op and the command is left on 948 * the cmdqueue. 949 */ 950 if (nc->flags & KBC_CMDFLAG_QUEUED) { 951 TAILQ_REMOVE(&q->cmdqueue, nc, next); 952 nc->flags &= ~KBC_CMDFLAG_QUEUED; 953 } 954 res = nc->status; 955 } 956 } else 957 timeout_add_sec(&t->t_cleanup, 1); 958 959 if (sync) { 960 if (respbuf) 961 memcpy(respbuf, nc->response, responselen); 962 TAILQ_INSERT_TAIL(&q->freequeue, nc, next); 963 } 964 965 splx(s); 966 967 return (res); 968} 969 970void 971pckbc_set_inputhandler(pckbc_tag_t self, pckbc_slot_t slot, pckbc_inputfcn func, 972 void *arg, char *name) 973{ 974 struct pckbc_internal *t = (struct pckbc_internal *)self; 975 struct pckbc_softc *sc = t->t_sc; 976 977 if (slot >= PCKBC_NSLOTS) 978 panic("pckbc_set_inputhandler: bad slot %d", slot); 979 980 sc->inputhandler[slot] = func; 981 sc->inputarg[slot] = arg; 982 sc->subname[slot] = name; 983 984 if (pckbc_console && slot == PCKBC_KBD_SLOT) 985 timeout_add_sec(&t->t_poll, 1); 986} 987 988void 989pckbc_poll(void *v) 990{ 991 struct pckbc_internal *t = v; 992 int s; 993 994 s = spltty(); 995 (void)pckbcintr_internal(t, t->t_sc); 996 timeout_add_sec(&t->t_poll, 1); 997 splx(s); 998} 999 1000int 1001pckbcintr(void *vsc) 1002{ 1003 struct pckbc_softc *sc = (struct pckbc_softc *)vsc; 1004 1005 return (pckbcintr_internal(sc->id, sc)); 1006} 1007 1008int 1009pckbcintr_internal(struct pckbc_internal *t, struct pckbc_softc *sc) 1010{ 1011 u_char stat; 1012 pckbc_slot_t slot; 1013 struct pckbc_slotdata *q; 1014 int served = 0, data; 1015 1016 /* reschedule timeout further into the idle times */ 1017 if (timeout_pending(&t->t_poll)) 1018 timeout_add_sec(&t->t_poll, 1); 1019 1020 for(;;) { 1021 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); 1022 if (!(stat & KBS_DIB)) 1023 break; 1024 1025 served = 1; 1026 1027 slot = (t->t_haveaux && (stat & KBS_AUXDATA)) ? 1028 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT; 1029 q = t->t_slotdata[slot]; 1030 1031 if (!q) { 1032 /* XXX do something for live insertion? */ 1033#ifdef PCKBCDEBUG 1034 printf("pckbcintr: no dev for slot %d\n", slot); 1035#endif 1036 KBD_DELAY; 1037 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 1038 continue; 1039 } 1040 1041 if (q->polling) 1042 break; /* pckbc_poll_data() will get it */ 1043 1044 KBD_DELAY; 1045 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); 1046 1047 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data)) 1048 continue; 1049 1050 if (sc != NULL) { 1051 if (sc->inputhandler[slot]) 1052 (*sc->inputhandler[slot])(sc->inputarg[slot], 1053 data); 1054#ifdef PCKBCDEBUG 1055 else 1056 printf("pckbcintr: slot %d lost %d\n", 1057 slot, data); 1058#endif 1059 } 1060 } 1061 1062 return (served); 1063} 1064 1065int 1066pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr, bus_size_t cmd_offset, 1067 int flags) 1068{ 1069 bus_space_handle_t ioh_d, ioh_c; 1070 int res = 0; 1071 1072 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d)) 1073 return (ENXIO); 1074 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) { 1075 bus_space_unmap(iot, ioh_d, 1); 1076 return (ENXIO); 1077 } 1078 1079 pckbc_consdata.t_iot = iot; 1080 pckbc_consdata.t_ioh_d = ioh_d; 1081 pckbc_consdata.t_ioh_c = ioh_c; 1082 pckbc_consdata.t_addr = addr; 1083 pckbc_consdata.t_flags = flags; 1084 timeout_set(&pckbc_consdata.t_cleanup, pckbc_cleanup, &pckbc_consdata); 1085 timeout_set(&pckbc_consdata.t_poll, pckbc_poll, &pckbc_consdata); 1086 1087 /* flush */ 1088 (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0); 1089 1090 /* selftest? */ 1091 1092 /* init cmd byte, enable ports */ 1093 pckbc_consdata.t_cmdbyte = KC8_CPU; 1094 if (!pckbc_put8042cmd(&pckbc_consdata)) { 1095 printf("kbc: cmd word write error\n"); 1096 res = EIO; 1097 } 1098 1099 if (!res) { 1100#if (NPCKBD > 0) 1101 res = pckbd_cnattach(&pckbc_consdata); 1102#else 1103 res = ENXIO; 1104#endif /* NPCKBD > 0 */ 1105 } 1106 1107 if (res) { 1108 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1); 1109 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1); 1110 } else { 1111 pckbc_consdata.t_slotdata[PCKBC_KBD_SLOT] = &pckbc_cons_slotdata; 1112 pckbc_init_slotdata(&pckbc_cons_slotdata); 1113 pckbc_console = 1; 1114 } 1115 1116 return (res); 1117} 1118 1119struct cfdriver pckbc_cd = { 1120 NULL, "pckbc", DV_DULL 1121};