1 /*- 2 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3 * Copyright (c) 2015 Nahanni Systems Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD: head/usr.sbin/bhyve/atkbdc.c 267611 2014-06-18 17:20:02Z neel $"); 30 31 #include <sys/types.h> 32 33 #include <machine/vmm.h> 34 35 #include <vmmapi.h> 36 37 #include <assert.h> 38 #include <errno.h> 39 #include <stdbool.h> 40 #include <stdlib.h> 41 #include <stdio.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <pthread.h> 45 #include <pthread_np.h> 46 47 #include "acpi.h" 48 #include "inout.h" 49 #include "pci_emul.h" 50 #include "pci_irq.h" 51 #include "pci_lpc.h" 52 #include "ps2kbd.h" 53 #include "ps2mouse.h" 54 55 #define KBD_DATA_PORT 0x60 56 57 #define KBD_STS_CTL_PORT 0x64 58 59 #define KBDC_RESET 0xfe 60 61 #define KBD_DEV_IRQ 1 62 #define AUX_DEV_IRQ 12 63 64 /* controller commands */ 65 #define KBDC_SET_COMMAND_BYTE 0x60 66 #define KBDC_GET_COMMAND_BYTE 0x20 67 #define KBDC_DISABLE_AUX_PORT 0xa7 68 #define KBDC_ENABLE_AUX_PORT 0xa8 69 #define KBDC_TEST_AUX_PORT 0xa9 70 #define KBDC_TEST_CTRL 0xaa 71 #define KBDC_TEST_KBD_PORT 0xab 72 #define KBDC_DISABLE_KBD_PORT 0xad 73 #define KBDC_ENABLE_KBD_PORT 0xae 74 #define KBDC_READ_INPORT 0xc0 75 #define KBDC_READ_OUTPORT 0xd0 76 #define KBDC_WRITE_OUTPORT 0xd1 77 #define KBDC_WRITE_KBD_OUTBUF 0xd2 78 #define KBDC_WRITE_AUX_OUTBUF 0xd3 79 #define KBDC_WRITE_TO_AUX 0xd4 80 81 /* controller command byte (set by KBDC_SET_COMMAND_BYTE) */ 82 #define KBD_TRANSLATION 0x40 83 #define KBD_SYS_FLAG_BIT 0x04 84 #define KBD_DISABLE_KBD_PORT 0x10 85 #define KBD_DISABLE_AUX_PORT 0x20 86 #define KBD_ENABLE_AUX_INT 0x02 87 #define KBD_ENABLE_KBD_INT 0x01 88 #define KBD_KBD_CONTROL_BITS (KBD_DISABLE_KBD_PORT | KBD_ENABLE_KBD_INT) 89 #define KBD_AUX_CONTROL_BITS (KBD_DISABLE_AUX_PORT | KBD_ENABLE_AUX_INT) 90 91 /* controller status bits */ 92 #define KBDS_KBD_BUFFER_FULL 0x01 93 #define KBDS_SYS_FLAG 0x04 94 #define KBDS_CTRL_FLAG 0x08 95 #define KBDS_AUX_BUFFER_FULL 0x20 96 97 /* controller output port */ 98 #define KBDO_KBD_OUTFULL 0x10 99 #define KBDO_AUX_OUTFULL 0x20 100 101 #define RAMSZ 32 102 103 struct kbd_dev { 104 bool irq_active; 105 int irq; 106 107 uint8_t buffer; 108 }; 109 110 struct aux_dev { 111 bool irq_active; 112 int irq; 113 114 uint8_t buffer; 115 }; 116 117 struct atkbdc_softc { 118 struct vmctx *ctx; 119 pthread_mutex_t mtx; 120 121 struct ps2kbd_softc *ps2kbd_sc; 122 struct ps2mouse_softc *ps2mouse_sc; 123 124 uint8_t status; /* status register */ 125 uint8_t outport; /* controller output port */ 126 uint8_t ram[RAMSZ]; /* byte0 = controller config */ 127 128 uint32_t curcmd; /* current command for next byte */ 129 130 struct kbd_dev kbd; 131 struct aux_dev aux; 132 }; 133 134 static void 135 atkbdc_assert_kbd_intr(struct atkbdc_softc *sc) 136 { 137 if (!sc->kbd.irq_active && 138 (sc->ram[0] & KBD_ENABLE_KBD_INT) != 0) { 139 sc->kbd.irq_active = true; 140 vm_isa_assert_irq(sc->ctx, sc->kbd.irq, sc->kbd.irq); 141 } 142 } 143 144 static void 145 atkbdc_deassert_kbd_intr(struct atkbdc_softc *sc) 146 { 147 if (sc->kbd.irq_active) { 148 vm_isa_deassert_irq(sc->ctx, sc->kbd.irq, sc->kbd.irq); 149 sc->kbd.irq_active = false; 150 } 151 } 152 153 static void 154 atkbdc_assert_aux_intr(struct atkbdc_softc *sc) 155 { 156 if (!sc->aux.irq_active && 157 (sc->ram[0] & KBD_ENABLE_AUX_INT) != 0) { 158 sc->aux.irq_active = true; 159 vm_isa_assert_irq(sc->ctx, sc->aux.irq, sc->aux.irq); 160 } 161 } 162 163 static void 164 atkbdc_deassert_aux_intr(struct atkbdc_softc *sc) 165 { 166 if (sc->aux.irq_active) { 167 vm_isa_deassert_irq(sc->ctx, sc->aux.irq, sc->aux.irq); 168 sc->aux.irq_active = false; 169 } 170 } 171 172 static void 173 atkbdc_aux_queue_data(struct atkbdc_softc *sc, uint8_t val) 174 { 175 assert(pthread_mutex_isowned_np(&sc->mtx)); 176 177 sc->aux.buffer = val; 178 sc->status |= (KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL); 179 sc->outport |= KBDO_AUX_OUTFULL; 180 atkbdc_assert_aux_intr(sc); 181 } 182 183 static void 184 atkbdc_kbd_queue_data(struct atkbdc_softc *sc, uint8_t val) 185 { 186 assert(pthread_mutex_isowned_np(&sc->mtx)); 187 188 sc->kbd.buffer = val; 189 sc->status |= KBDS_KBD_BUFFER_FULL; 190 sc->outport |= KBDO_KBD_OUTFULL; 191 atkbdc_assert_kbd_intr(sc); 192 } 193 194 static void 195 atkbdc_aux_read(struct atkbdc_softc *sc) 196 { 197 uint8_t val; 198 199 assert(pthread_mutex_isowned_np(&sc->mtx)); 200 201 if (ps2mouse_read(sc->ps2mouse_sc, &val) != -1) 202 atkbdc_aux_queue_data(sc, val); 203 } 204 205 static void 206 atkbdc_kbd_read(struct atkbdc_softc *sc) 207 { 208 const uint8_t translation[256] = { 209 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 210 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, 211 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 212 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 213 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 214 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, 215 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 216 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, 217 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 218 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 219 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 220 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, 221 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 222 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, 223 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 224 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 225 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 226 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 227 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 228 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 229 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 230 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 231 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 232 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 233 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 234 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 235 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 236 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 237 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 238 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 239 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 240 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 241 }; 242 uint8_t val; 243 uint8_t release = 0; 244 245 assert(pthread_mutex_isowned_np(&sc->mtx)); 246 247 if (sc->ram[0] & KBD_TRANSLATION) { 248 while (ps2kbd_read(sc->ps2kbd_sc, &val) != -1) { 249 if (val == 0xf0) { 250 release = 0x80; 251 continue; 252 } else { 253 val = translation[val] | release; 254 } 255 256 atkbdc_kbd_queue_data(sc, val); 257 break; 258 } 259 } else { 260 if (ps2kbd_read(sc->ps2kbd_sc, &val) != -1) 261 atkbdc_kbd_queue_data(sc, val); 262 } 263 } 264 265 static void 266 atkbdc_aux_poll(struct atkbdc_softc *sc) 267 { 268 if ((sc->outport & KBDO_AUX_OUTFULL) == 0) 269 atkbdc_aux_read(sc); 270 } 271 272 static void 273 atkbdc_kbd_poll(struct atkbdc_softc *sc) 274 { 275 assert(pthread_mutex_isowned_np(&sc->mtx)); 276 277 if ((sc->outport & KBDO_KBD_OUTFULL) == 0) 278 atkbdc_kbd_read(sc); 279 } 280 281 static void 282 atkbdc_poll(struct atkbdc_softc *sc) 283 { 284 atkbdc_aux_poll(sc); 285 atkbdc_kbd_poll(sc); 286 } 287 288 static void 289 atkbdc_dequeue_data(struct atkbdc_softc *sc, uint8_t *buf) 290 { 291 assert(pthread_mutex_isowned_np(&sc->mtx)); 292 293 if (sc->outport & KBDO_AUX_OUTFULL) { 294 *buf = sc->aux.buffer; 295 sc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL); 296 sc->outport &= ~KBDO_AUX_OUTFULL; 297 atkbdc_deassert_aux_intr(sc); 298 299 atkbdc_poll(sc); 300 return; 301 } 302 303 *buf = sc->kbd.buffer; 304 sc->status &= ~KBDS_KBD_BUFFER_FULL; 305 sc->outport &= ~KBDO_KBD_OUTFULL; 306 atkbdc_deassert_kbd_intr(sc); 307 308 atkbdc_poll(sc); 309 } 310 311 static int 312 atkbdc_data_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 313 uint32_t *eax, void *arg) 314 { 315 struct atkbdc_softc *sc; 316 uint8_t buf; 317 int retval; 318 319 if (bytes != 1) 320 return (-1); 321 322 sc = arg; 323 retval = 0; 324 325 pthread_mutex_lock(&sc->mtx); 326 if (in) { 327 sc->curcmd = 0; 328 sc->status &= ~KBDS_CTRL_FLAG; 329 330 /* read device buffer; includes kbd cmd responses */ 331 atkbdc_dequeue_data(sc, &buf); 332 *eax = buf; 333 334 pthread_mutex_unlock(&sc->mtx); 335 return (retval); 336 } 337 338 if (sc->status & KBDS_CTRL_FLAG) { 339 /* 340 * Command byte for the controller. 341 */ 342 switch (sc->curcmd) { 343 case KBDC_SET_COMMAND_BYTE: 344 sc->ram[0] = *eax; 345 if (sc->ram[0] & KBD_SYS_FLAG_BIT) 346 sc->status |= KBDS_SYS_FLAG; 347 else 348 sc->status &= KBDS_SYS_FLAG; 349 if (sc->outport & KBDO_AUX_OUTFULL) 350 atkbdc_assert_aux_intr(sc); 351 else if (sc->outport & KBDO_KBD_OUTFULL) 352 atkbdc_assert_kbd_intr(sc); 353 break; 354 case KBDC_WRITE_OUTPORT: 355 sc->outport = *eax; 356 if (sc->outport & KBDO_AUX_OUTFULL) 357 sc->status |= (KBDS_AUX_BUFFER_FULL | 358 KBDS_KBD_BUFFER_FULL); 359 if (sc->outport & KBDO_KBD_OUTFULL) 360 sc->status |= KBDS_KBD_BUFFER_FULL; 361 break; 362 case KBDC_WRITE_TO_AUX: 363 ps2mouse_write(sc->ps2mouse_sc, *eax); 364 atkbdc_poll(sc); 365 break; 366 case KBDC_WRITE_KBD_OUTBUF: 367 atkbdc_kbd_queue_data(sc, *eax); 368 break; 369 case KBDC_WRITE_AUX_OUTBUF: 370 atkbdc_aux_queue_data(sc, *eax); 371 break; 372 default: 373 /* write to particular RAM byte */ 374 if (sc->curcmd >= 0x61 && sc->curcmd <= 0x7f) { 375 int byten; 376 377 byten = (sc->curcmd - 0x60) & 0x1f; 378 sc->ram[byten] = *eax & 0xff; 379 } 380 break; 381 } 382 383 sc->curcmd = 0; 384 sc->status &= ~KBDS_CTRL_FLAG; 385 386 pthread_mutex_unlock(&sc->mtx); 387 return (retval); 388 } 389 390 /* 391 * Data byte for the device. 392 */ 393 ps2kbd_write(sc->ps2kbd_sc, *eax); 394 atkbdc_poll(sc); 395 396 pthread_mutex_unlock(&sc->mtx); 397 398 return (retval); 399 } 400 401 402 static int 403 atkbdc_sts_ctl_handler(struct vmctx *ctx, int vcpu, int in, int port, 404 int bytes, uint32_t *eax, void *arg) 405 { 406 struct atkbdc_softc *sc; 407 int error, retval; 408 409 if (bytes != 1) 410 return (-1); 411 412 sc = arg; 413 retval = 0; 414 415 pthread_mutex_lock(&sc->mtx); 416 417 if (in) { 418 /* read status register */ 419 *eax = sc->status; 420 pthread_mutex_unlock(&sc->mtx); 421 return (retval); 422 } 423 424 sc->curcmd = 0; 425 sc->status |= KBDS_CTRL_FLAG; 426 427 switch (*eax) { 428 case KBDC_GET_COMMAND_BYTE: 429 atkbdc_kbd_queue_data(sc, sc->ram[0]); 430 break; 431 case KBDC_TEST_CTRL: 432 atkbdc_kbd_queue_data(sc, 0x55); 433 break; 434 case KBDC_TEST_AUX_PORT: 435 case KBDC_TEST_KBD_PORT: 436 atkbdc_kbd_queue_data(sc, 0); 437 break; 438 case KBDC_READ_INPORT: 439 atkbdc_kbd_queue_data(sc, 0); 440 break; 441 case KBDC_READ_OUTPORT: 442 atkbdc_kbd_queue_data(sc, sc->outport); 443 break; 444 case KBDC_SET_COMMAND_BYTE: 445 case KBDC_WRITE_OUTPORT: 446 case KBDC_WRITE_KBD_OUTBUF: 447 case KBDC_WRITE_AUX_OUTBUF: 448 sc->curcmd = *eax; 449 break; 450 case KBDC_DISABLE_KBD_PORT: 451 sc->ram[0] |= KBD_DISABLE_KBD_PORT; 452 break; 453 case KBDC_ENABLE_KBD_PORT: 454 sc->ram[0] &= ~KBD_DISABLE_KBD_PORT; 455 atkbdc_poll(sc); 456 break; 457 case KBDC_WRITE_TO_AUX: 458 sc->curcmd = *eax; 459 break; 460 case KBDC_DISABLE_AUX_PORT: 461 sc->ram[0] |= KBD_DISABLE_AUX_PORT; 462 break; 463 case KBDC_ENABLE_AUX_PORT: 464 sc->ram[0] &= ~KBD_DISABLE_AUX_PORT; 465 break; 466 case KBDC_RESET: /* Pulse "reset" line */ 467 #ifdef __FreeBSD__ 468 error = vm_suspend(ctx, VM_SUSPEND_RESET); 469 assert(error == 0 || errno == EALREADY); 470 #else 471 exit(0); 472 #endif 473 break; 474 default: 475 if (*eax >= 0x21 && *eax <= 0x3f) { 476 /* read "byte N" from RAM */ 477 int byten; 478 479 byten = (*eax - 0x20) & 0x1f; 480 atkbdc_kbd_queue_data(sc, sc->ram[byten]); 481 } 482 break; 483 } 484 485 pthread_mutex_unlock(&sc->mtx); 486 487 return (retval); 488 } 489 490 void 491 atkbdc_event(struct atkbdc_softc *sc) 492 { 493 pthread_mutex_lock(&sc->mtx); 494 atkbdc_poll(sc); 495 pthread_mutex_unlock(&sc->mtx); 496 } 497 498 void 499 atkbdc_init(struct vmctx *ctx) 500 { 501 struct inout_port iop; 502 struct atkbdc_softc *sc; 503 int error; 504 505 sc = calloc(1, sizeof(struct atkbdc_softc)); 506 sc->ctx = ctx; 507 508 pthread_mutex_init(&sc->mtx, NULL); 509 510 bzero(&iop, sizeof(struct inout_port)); 511 iop.name = "atkdbc"; 512 iop.port = KBD_STS_CTL_PORT; 513 iop.size = 1; 514 iop.flags = IOPORT_F_INOUT; 515 iop.handler = atkbdc_sts_ctl_handler; 516 iop.arg = sc; 517 518 error = register_inout(&iop); 519 assert(error == 0); 520 521 bzero(&iop, sizeof(struct inout_port)); 522 iop.name = "atkdbc"; 523 iop.port = KBD_DATA_PORT; 524 iop.size = 1; 525 iop.flags = IOPORT_F_INOUT; 526 iop.handler = atkbdc_data_handler; 527 iop.arg = sc; 528 529 error = register_inout(&iop); 530 assert(error == 0); 531 532 pci_irq_reserve(KBD_DEV_IRQ); 533 sc->kbd.irq = KBD_DEV_IRQ; 534 535 pci_irq_reserve(AUX_DEV_IRQ); 536 sc->aux.irq = AUX_DEV_IRQ; 537 538 sc->ps2kbd_sc = ps2kbd_init(sc); 539 sc->ps2mouse_sc = ps2mouse_init(sc); 540 } 541 542 #ifdef __FreeBSD__ 543 static void 544 atkbdc_dsdt(void) 545 { 546 547 dsdt_line(""); 548 dsdt_line("Device (KBD)"); 549 dsdt_line("{"); 550 dsdt_line(" Name (_HID, EisaId (\"PNP0303\"))"); 551 dsdt_line(" Name (_CRS, ResourceTemplate ()"); 552 dsdt_line(" {"); 553 dsdt_indent(2); 554 dsdt_fixed_ioport(KBD_DATA_PORT, 1); 555 dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1); 556 dsdt_fixed_irq(1); 557 dsdt_unindent(2); 558 dsdt_line(" })"); 559 dsdt_line("}"); 560 561 dsdt_line(""); 562 dsdt_line("Device (MOU)"); 563 dsdt_line("{"); 564 dsdt_line(" Name (_HID, EisaId (\"PNP0F13\"))"); 565 dsdt_line(" Name (_CRS, ResourceTemplate ()"); 566 dsdt_line(" {"); 567 dsdt_indent(2); 568 dsdt_fixed_ioport(KBD_DATA_PORT, 1); 569 dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1); 570 dsdt_fixed_irq(12); 571 dsdt_unindent(2); 572 dsdt_line(" })"); 573 dsdt_line("}"); 574 } 575 LPC_DSDT(atkbdc_dsdt); 576 #endif 577