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