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