pckbd.c (23970B)
1/* 2 * QEMU PC keyboard emulation 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25#include "qemu/osdep.h" 26#include "qemu/error-report.h" 27#include "qemu/log.h" 28#include "qemu/timer.h" 29#include "hw/isa/isa.h" 30#include "migration/vmstate.h" 31#include "hw/acpi/aml-build.h" 32#include "hw/input/ps2.h" 33#include "hw/irq.h" 34#include "hw/input/i8042.h" 35#include "hw/qdev-properties.h" 36#include "sysemu/reset.h" 37#include "sysemu/runstate.h" 38 39#include "trace.h" 40 41/* Keyboard Controller Commands */ 42#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ 43#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ 44#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ 45#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ 46#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ 47#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ 48#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ 49#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ 50#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ 51#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ 52#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ 53#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ 54#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ 55#define KBD_CCMD_WRITE_OBUF 0xD2 56#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if 57 initiated by the auxiliary device */ 58#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ 59#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ 60#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ 61#define KBD_CCMD_PULSE_BITS_3_0 0xF0 /* Pulse bits 3-0 of the output port P2. */ 62#define KBD_CCMD_RESET 0xFE /* Pulse bit 0 of the output port P2 = CPU reset. */ 63#define KBD_CCMD_NO_OP 0xFF /* Pulse no bits of the output port P2. */ 64 65/* Status Register Bits */ 66#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ 67#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ 68#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ 69#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ 70#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ 71#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ 72#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ 73#define KBD_STAT_PERR 0x80 /* Parity error */ 74 75/* Controller Mode Register Bits */ 76#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ 77#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ 78#define KBD_MODE_SYS 0x04 /* The system flag (?) */ 79#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ 80#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ 81#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ 82#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ 83#define KBD_MODE_RFU 0x80 84 85/* Output Port Bits */ 86#define KBD_OUT_RESET 0x01 /* 1=normal mode, 0=reset */ 87#define KBD_OUT_A20 0x02 /* x86 only */ 88#define KBD_OUT_OBF 0x10 /* Keyboard output buffer full */ 89#define KBD_OUT_MOUSE_OBF 0x20 /* Mouse output buffer full */ 90 91/* OSes typically write 0xdd/0xdf to turn the A20 line off and on. 92 * We make the default value of the outport include these four bits, 93 * so that the subsection is rarely necessary. 94 */ 95#define KBD_OUT_ONES 0xcc 96 97#define KBD_PENDING_KBD_COMPAT 0x01 98#define KBD_PENDING_AUX_COMPAT 0x02 99#define KBD_PENDING_CTRL_KBD 0x04 100#define KBD_PENDING_CTRL_AUX 0x08 101#define KBD_PENDING_KBD KBD_MODE_DISABLE_KBD /* 0x10 */ 102#define KBD_PENDING_AUX KBD_MODE_DISABLE_MOUSE /* 0x20 */ 103 104#define KBD_MIGR_TIMER_PENDING 0x1 105 106#define KBD_OBSRC_KBD 0x01 107#define KBD_OBSRC_MOUSE 0x02 108#define KBD_OBSRC_CTRL 0x04 109 110typedef struct KBDState { 111 uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ 112 uint8_t status; 113 uint8_t mode; 114 uint8_t outport; 115 uint32_t migration_flags; 116 uint32_t obsrc; 117 bool outport_present; 118 bool extended_state; 119 bool extended_state_loaded; 120 /* Bitmask of devices with data available. */ 121 uint8_t pending; 122 uint8_t obdata; 123 uint8_t cbdata; 124 uint8_t pending_tmp; 125 void *kbd; 126 void *mouse; 127 QEMUTimer *throttle_timer; 128 129 qemu_irq irq_kbd; 130 qemu_irq irq_mouse; 131 qemu_irq a20_out; 132 hwaddr mask; 133} KBDState; 134 135/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be 136 incorrect, but it avoids having to simulate exact delays */ 137static void kbd_update_irq_lines(KBDState *s) 138{ 139 int irq_kbd_level, irq_mouse_level; 140 141 irq_kbd_level = 0; 142 irq_mouse_level = 0; 143 144 if (s->status & KBD_STAT_OBF) { 145 if (s->status & KBD_STAT_MOUSE_OBF) { 146 if (s->mode & KBD_MODE_MOUSE_INT) { 147 irq_mouse_level = 1; 148 } 149 } else { 150 if ((s->mode & KBD_MODE_KBD_INT) && 151 !(s->mode & KBD_MODE_DISABLE_KBD)) { 152 irq_kbd_level = 1; 153 } 154 } 155 } 156 qemu_set_irq(s->irq_kbd, irq_kbd_level); 157 qemu_set_irq(s->irq_mouse, irq_mouse_level); 158} 159 160static void kbd_deassert_irq(KBDState *s) 161{ 162 s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); 163 s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF); 164 kbd_update_irq_lines(s); 165} 166 167static uint8_t kbd_pending(KBDState *s) 168{ 169 if (s->extended_state) { 170 return s->pending & (~s->mode | ~(KBD_PENDING_KBD | KBD_PENDING_AUX)); 171 } else { 172 return s->pending; 173 } 174} 175 176/* update irq and KBD_STAT_[MOUSE_]OBF */ 177static void kbd_update_irq(KBDState *s) 178{ 179 uint8_t pending = kbd_pending(s); 180 181 s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); 182 s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF); 183 if (pending) { 184 s->status |= KBD_STAT_OBF; 185 s->outport |= KBD_OUT_OBF; 186 if (pending & KBD_PENDING_CTRL_KBD) { 187 s->obsrc = KBD_OBSRC_CTRL; 188 } else if (pending & KBD_PENDING_CTRL_AUX) { 189 s->status |= KBD_STAT_MOUSE_OBF; 190 s->outport |= KBD_OUT_MOUSE_OBF; 191 s->obsrc = KBD_OBSRC_CTRL; 192 } else if (pending & KBD_PENDING_KBD) { 193 s->obsrc = KBD_OBSRC_KBD; 194 } else { 195 s->status |= KBD_STAT_MOUSE_OBF; 196 s->outport |= KBD_OUT_MOUSE_OBF; 197 s->obsrc = KBD_OBSRC_MOUSE; 198 } 199 } 200 kbd_update_irq_lines(s); 201} 202 203static void kbd_safe_update_irq(KBDState *s) 204{ 205 /* 206 * with KBD_STAT_OBF set, a call to kbd_read_data() will eventually call 207 * kbd_update_irq() 208 */ 209 if (s->status & KBD_STAT_OBF) { 210 return; 211 } 212 /* the throttle timer is pending and will call kbd_update_irq() */ 213 if (s->throttle_timer && timer_pending(s->throttle_timer)) { 214 return; 215 } 216 if (kbd_pending(s)) { 217 kbd_update_irq(s); 218 } 219} 220 221static void kbd_update_kbd_irq(void *opaque, int level) 222{ 223 KBDState *s = opaque; 224 225 if (level) { 226 s->pending |= KBD_PENDING_KBD; 227 } else { 228 s->pending &= ~KBD_PENDING_KBD; 229 } 230 kbd_safe_update_irq(s); 231} 232 233static void kbd_update_aux_irq(void *opaque, int level) 234{ 235 KBDState *s = opaque; 236 237 if (level) { 238 s->pending |= KBD_PENDING_AUX; 239 } else { 240 s->pending &= ~KBD_PENDING_AUX; 241 } 242 kbd_safe_update_irq(s); 243} 244 245static void kbd_throttle_timeout(void *opaque) 246{ 247 KBDState *s = opaque; 248 249 if (kbd_pending(s)) { 250 kbd_update_irq(s); 251 } 252} 253 254static uint64_t kbd_read_status(void *opaque, hwaddr addr, 255 unsigned size) 256{ 257 KBDState *s = opaque; 258 int val; 259 val = s->status; 260 trace_pckbd_kbd_read_status(val); 261 return val; 262} 263 264static void kbd_queue(KBDState *s, int b, int aux) 265{ 266 if (s->extended_state) { 267 s->cbdata = b; 268 s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX; 269 s->pending |= aux ? KBD_PENDING_CTRL_AUX : KBD_PENDING_CTRL_KBD; 270 kbd_safe_update_irq(s); 271 } else { 272 ps2_queue(aux ? s->mouse : s->kbd, b); 273 } 274} 275 276static uint8_t kbd_dequeue(KBDState *s) 277{ 278 uint8_t b = s->cbdata; 279 280 s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX; 281 if (kbd_pending(s)) { 282 kbd_update_irq(s); 283 } 284 return b; 285} 286 287static void outport_write(KBDState *s, uint32_t val) 288{ 289 trace_pckbd_outport_write(val); 290 s->outport = val; 291 qemu_set_irq(s->a20_out, (val >> 1) & 1); 292 if (!(val & 1)) { 293 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 294 } 295} 296 297static void kbd_write_command(void *opaque, hwaddr addr, 298 uint64_t val, unsigned size) 299{ 300 KBDState *s = opaque; 301 302 trace_pckbd_kbd_write_command(val); 303 304 /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed 305 * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE 306 * command specify the output port bits to be pulsed. 307 * 0: Bit should be pulsed. 1: Bit should not be modified. 308 * The only useful version of this command is pulsing bit 0, 309 * which does a CPU reset. 310 */ 311 if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) { 312 if(!(val & 1)) 313 val = KBD_CCMD_RESET; 314 else 315 val = KBD_CCMD_NO_OP; 316 } 317 318 switch(val) { 319 case KBD_CCMD_READ_MODE: 320 kbd_queue(s, s->mode, 0); 321 break; 322 case KBD_CCMD_WRITE_MODE: 323 case KBD_CCMD_WRITE_OBUF: 324 case KBD_CCMD_WRITE_AUX_OBUF: 325 case KBD_CCMD_WRITE_MOUSE: 326 case KBD_CCMD_WRITE_OUTPORT: 327 s->write_cmd = val; 328 break; 329 case KBD_CCMD_MOUSE_DISABLE: 330 s->mode |= KBD_MODE_DISABLE_MOUSE; 331 break; 332 case KBD_CCMD_MOUSE_ENABLE: 333 s->mode &= ~KBD_MODE_DISABLE_MOUSE; 334 kbd_safe_update_irq(s); 335 break; 336 case KBD_CCMD_TEST_MOUSE: 337 kbd_queue(s, 0x00, 0); 338 break; 339 case KBD_CCMD_SELF_TEST: 340 s->status |= KBD_STAT_SELFTEST; 341 kbd_queue(s, 0x55, 0); 342 break; 343 case KBD_CCMD_KBD_TEST: 344 kbd_queue(s, 0x00, 0); 345 break; 346 case KBD_CCMD_KBD_DISABLE: 347 s->mode |= KBD_MODE_DISABLE_KBD; 348 break; 349 case KBD_CCMD_KBD_ENABLE: 350 s->mode &= ~KBD_MODE_DISABLE_KBD; 351 kbd_safe_update_irq(s); 352 break; 353 case KBD_CCMD_READ_INPORT: 354 kbd_queue(s, 0x80, 0); 355 break; 356 case KBD_CCMD_READ_OUTPORT: 357 kbd_queue(s, s->outport, 0); 358 break; 359 case KBD_CCMD_ENABLE_A20: 360 qemu_irq_raise(s->a20_out); 361 s->outport |= KBD_OUT_A20; 362 break; 363 case KBD_CCMD_DISABLE_A20: 364 qemu_irq_lower(s->a20_out); 365 s->outport &= ~KBD_OUT_A20; 366 break; 367 case KBD_CCMD_RESET: 368 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 369 break; 370 case KBD_CCMD_NO_OP: 371 /* ignore that */ 372 break; 373 default: 374 qemu_log_mask(LOG_GUEST_ERROR, 375 "unsupported keyboard cmd=0x%02" PRIx64 "\n", val); 376 break; 377 } 378} 379 380static uint64_t kbd_read_data(void *opaque, hwaddr addr, 381 unsigned size) 382{ 383 KBDState *s = opaque; 384 385 if (s->status & KBD_STAT_OBF) { 386 kbd_deassert_irq(s); 387 if (s->obsrc & KBD_OBSRC_KBD) { 388 if (s->throttle_timer) { 389 timer_mod(s->throttle_timer, 390 qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000); 391 } 392 s->obdata = ps2_read_data(s->kbd); 393 } else if (s->obsrc & KBD_OBSRC_MOUSE) { 394 s->obdata = ps2_read_data(s->mouse); 395 } else if (s->obsrc & KBD_OBSRC_CTRL) { 396 s->obdata = kbd_dequeue(s); 397 } 398 } 399 400 trace_pckbd_kbd_read_data(s->obdata); 401 return s->obdata; 402} 403 404static void kbd_write_data(void *opaque, hwaddr addr, 405 uint64_t val, unsigned size) 406{ 407 KBDState *s = opaque; 408 409 trace_pckbd_kbd_write_data(val); 410 411 switch(s->write_cmd) { 412 case 0: 413 ps2_write_keyboard(s->kbd, val); 414 /* sending data to the keyboard reenables PS/2 communication */ 415 s->mode &= ~KBD_MODE_DISABLE_KBD; 416 kbd_safe_update_irq(s); 417 break; 418 case KBD_CCMD_WRITE_MODE: 419 s->mode = val; 420 ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0); 421 /* 422 * a write to the mode byte interrupt enable flags directly updates 423 * the irq lines 424 */ 425 kbd_update_irq_lines(s); 426 /* 427 * a write to the mode byte disable interface flags may raise 428 * an irq if there is pending data in the PS/2 queues. 429 */ 430 kbd_safe_update_irq(s); 431 break; 432 case KBD_CCMD_WRITE_OBUF: 433 kbd_queue(s, val, 0); 434 break; 435 case KBD_CCMD_WRITE_AUX_OBUF: 436 kbd_queue(s, val, 1); 437 break; 438 case KBD_CCMD_WRITE_OUTPORT: 439 outport_write(s, val); 440 break; 441 case KBD_CCMD_WRITE_MOUSE: 442 ps2_write_mouse(s->mouse, val); 443 /* sending data to the mouse reenables PS/2 communication */ 444 s->mode &= ~KBD_MODE_DISABLE_MOUSE; 445 kbd_safe_update_irq(s); 446 break; 447 default: 448 break; 449 } 450 s->write_cmd = 0; 451} 452 453static void kbd_reset(void *opaque) 454{ 455 KBDState *s = opaque; 456 457 s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; 458 s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; 459 s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES; 460 s->pending = 0; 461 kbd_deassert_irq(s); 462 if (s->throttle_timer) { 463 timer_del(s->throttle_timer); 464 } 465} 466 467static uint8_t kbd_outport_default(KBDState *s) 468{ 469 return KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES 470 | (s->status & KBD_STAT_OBF ? KBD_OUT_OBF : 0) 471 | (s->status & KBD_STAT_MOUSE_OBF ? KBD_OUT_MOUSE_OBF : 0); 472} 473 474static int kbd_outport_post_load(void *opaque, int version_id) 475{ 476 KBDState *s = opaque; 477 s->outport_present = true; 478 return 0; 479} 480 481static bool kbd_outport_needed(void *opaque) 482{ 483 KBDState *s = opaque; 484 return s->outport != kbd_outport_default(s); 485} 486 487static const VMStateDescription vmstate_kbd_outport = { 488 .name = "pckbd_outport", 489 .version_id = 1, 490 .minimum_version_id = 1, 491 .post_load = kbd_outport_post_load, 492 .needed = kbd_outport_needed, 493 .fields = (VMStateField[]) { 494 VMSTATE_UINT8(outport, KBDState), 495 VMSTATE_END_OF_LIST() 496 } 497}; 498 499static int kbd_extended_state_pre_save(void *opaque) 500{ 501 KBDState *s = opaque; 502 503 s->migration_flags = 0; 504 if (s->throttle_timer && timer_pending(s->throttle_timer)) { 505 s->migration_flags |= KBD_MIGR_TIMER_PENDING; 506 } 507 508 return 0; 509} 510 511static int kbd_extended_state_post_load(void *opaque, int version_id) 512{ 513 KBDState *s = opaque; 514 515 if (s->migration_flags & KBD_MIGR_TIMER_PENDING) { 516 kbd_throttle_timeout(s); 517 } 518 s->extended_state_loaded = true; 519 520 return 0; 521} 522 523static bool kbd_extended_state_needed(void *opaque) 524{ 525 KBDState *s = opaque; 526 527 return s->extended_state; 528} 529 530static const VMStateDescription vmstate_kbd_extended_state = { 531 .name = "pckbd/extended_state", 532 .post_load = kbd_extended_state_post_load, 533 .pre_save = kbd_extended_state_pre_save, 534 .needed = kbd_extended_state_needed, 535 .fields = (VMStateField[]) { 536 VMSTATE_UINT32(migration_flags, KBDState), 537 VMSTATE_UINT32(obsrc, KBDState), 538 VMSTATE_UINT8(obdata, KBDState), 539 VMSTATE_UINT8(cbdata, KBDState), 540 VMSTATE_END_OF_LIST() 541 } 542}; 543 544static int kbd_pre_save(void *opaque) 545{ 546 KBDState *s = opaque; 547 548 if (s->extended_state) { 549 s->pending_tmp = s->pending; 550 } else { 551 s->pending_tmp = 0; 552 if (s->pending & KBD_PENDING_KBD) { 553 s->pending_tmp |= KBD_PENDING_KBD_COMPAT; 554 } 555 if (s->pending & KBD_PENDING_AUX) { 556 s->pending_tmp |= KBD_PENDING_AUX_COMPAT; 557 } 558 } 559 return 0; 560} 561 562static int kbd_pre_load(void *opaque) 563{ 564 KBDState *s = opaque; 565 566 s->outport_present = false; 567 s->extended_state_loaded = false; 568 return 0; 569} 570 571static int kbd_post_load(void *opaque, int version_id) 572{ 573 KBDState *s = opaque; 574 if (!s->outport_present) { 575 s->outport = kbd_outport_default(s); 576 } 577 s->pending = s->pending_tmp; 578 if (!s->extended_state_loaded) { 579 s->obsrc = s->status & KBD_STAT_OBF ? 580 (s->status & KBD_STAT_MOUSE_OBF ? KBD_OBSRC_MOUSE : KBD_OBSRC_KBD) : 581 0; 582 if (s->pending & KBD_PENDING_KBD_COMPAT) { 583 s->pending |= KBD_PENDING_KBD; 584 } 585 if (s->pending & KBD_PENDING_AUX_COMPAT) { 586 s->pending |= KBD_PENDING_AUX; 587 } 588 } 589 /* clear all unused flags */ 590 s->pending &= KBD_PENDING_CTRL_KBD | KBD_PENDING_CTRL_AUX | 591 KBD_PENDING_KBD | KBD_PENDING_AUX; 592 return 0; 593} 594 595static const VMStateDescription vmstate_kbd = { 596 .name = "pckbd", 597 .version_id = 3, 598 .minimum_version_id = 3, 599 .pre_load = kbd_pre_load, 600 .post_load = kbd_post_load, 601 .pre_save = kbd_pre_save, 602 .fields = (VMStateField[]) { 603 VMSTATE_UINT8(write_cmd, KBDState), 604 VMSTATE_UINT8(status, KBDState), 605 VMSTATE_UINT8(mode, KBDState), 606 VMSTATE_UINT8(pending_tmp, KBDState), 607 VMSTATE_END_OF_LIST() 608 }, 609 .subsections = (const VMStateDescription*[]) { 610 &vmstate_kbd_outport, 611 &vmstate_kbd_extended_state, 612 NULL 613 } 614}; 615 616/* Memory mapped interface */ 617static uint64_t kbd_mm_readfn(void *opaque, hwaddr addr, unsigned size) 618{ 619 KBDState *s = opaque; 620 621 if (addr & s->mask) 622 return kbd_read_status(s, 0, 1) & 0xff; 623 else 624 return kbd_read_data(s, 0, 1) & 0xff; 625} 626 627static void kbd_mm_writefn(void *opaque, hwaddr addr, 628 uint64_t value, unsigned size) 629{ 630 KBDState *s = opaque; 631 632 if (addr & s->mask) 633 kbd_write_command(s, 0, value & 0xff, 1); 634 else 635 kbd_write_data(s, 0, value & 0xff, 1); 636} 637 638 639static const MemoryRegionOps i8042_mmio_ops = { 640 .read = kbd_mm_readfn, 641 .write = kbd_mm_writefn, 642 .valid.min_access_size = 1, 643 .valid.max_access_size = 4, 644 .endianness = DEVICE_NATIVE_ENDIAN, 645}; 646 647void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, 648 MemoryRegion *region, ram_addr_t size, 649 hwaddr mask) 650{ 651 KBDState *s = g_malloc0(sizeof(KBDState)); 652 653 s->irq_kbd = kbd_irq; 654 s->irq_mouse = mouse_irq; 655 s->mask = mask; 656 657 s->extended_state = true; 658 659 vmstate_register(NULL, 0, &vmstate_kbd, s); 660 661 memory_region_init_io(region, NULL, &i8042_mmio_ops, s, "i8042", size); 662 663 s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); 664 s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); 665 qemu_register_reset(kbd_reset, s); 666} 667 668struct ISAKBDState { 669 ISADevice parent_obj; 670 671 KBDState kbd; 672 bool kbd_throttle; 673 MemoryRegion io[2]; 674}; 675 676void i8042_isa_mouse_fake_event(ISAKBDState *isa) 677{ 678 KBDState *s = &isa->kbd; 679 680 ps2_mouse_fake_event(s->mouse); 681} 682 683void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out) 684{ 685 qdev_connect_gpio_out_named(DEVICE(dev), I8042_A20_LINE, 0, a20_out); 686} 687 688static const VMStateDescription vmstate_kbd_isa = { 689 .name = "pckbd", 690 .version_id = 3, 691 .minimum_version_id = 3, 692 .fields = (VMStateField[]) { 693 VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState), 694 VMSTATE_END_OF_LIST() 695 } 696}; 697 698static const MemoryRegionOps i8042_data_ops = { 699 .read = kbd_read_data, 700 .write = kbd_write_data, 701 .impl = { 702 .min_access_size = 1, 703 .max_access_size = 1, 704 }, 705 .endianness = DEVICE_LITTLE_ENDIAN, 706}; 707 708static const MemoryRegionOps i8042_cmd_ops = { 709 .read = kbd_read_status, 710 .write = kbd_write_command, 711 .impl = { 712 .min_access_size = 1, 713 .max_access_size = 1, 714 }, 715 .endianness = DEVICE_LITTLE_ENDIAN, 716}; 717 718static void i8042_initfn(Object *obj) 719{ 720 ISAKBDState *isa_s = I8042(obj); 721 KBDState *s = &isa_s->kbd; 722 723 memory_region_init_io(isa_s->io + 0, obj, &i8042_data_ops, s, 724 "i8042-data", 1); 725 memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s, 726 "i8042-cmd", 1); 727 728 qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1); 729} 730 731static void i8042_realizefn(DeviceState *dev, Error **errp) 732{ 733 ISADevice *isadev = ISA_DEVICE(dev); 734 ISAKBDState *isa_s = I8042(dev); 735 KBDState *s = &isa_s->kbd; 736 737 isa_init_irq(isadev, &s->irq_kbd, 1); 738 isa_init_irq(isadev, &s->irq_mouse, 12); 739 740 isa_register_ioport(isadev, isa_s->io + 0, 0x60); 741 isa_register_ioport(isadev, isa_s->io + 1, 0x64); 742 743 s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); 744 s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); 745 if (isa_s->kbd_throttle && !isa_s->kbd.extended_state) { 746 warn_report(TYPE_I8042 ": can't enable kbd-throttle without" 747 " extended-state, disabling kbd-throttle"); 748 } else if (isa_s->kbd_throttle) { 749 s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, 750 kbd_throttle_timeout, s); 751 } 752 qemu_register_reset(kbd_reset, s); 753} 754 755static void i8042_build_aml(ISADevice *isadev, Aml *scope) 756{ 757 Aml *kbd; 758 Aml *mou; 759 Aml *crs; 760 761 crs = aml_resource_template(); 762 aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01)); 763 aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01)); 764 aml_append(crs, aml_irq_no_flags(1)); 765 766 kbd = aml_device("KBD"); 767 aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303"))); 768 aml_append(kbd, aml_name_decl("_STA", aml_int(0xf))); 769 aml_append(kbd, aml_name_decl("_CRS", crs)); 770 771 crs = aml_resource_template(); 772 aml_append(crs, aml_irq_no_flags(12)); 773 774 mou = aml_device("MOU"); 775 aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13"))); 776 aml_append(mou, aml_name_decl("_STA", aml_int(0xf))); 777 aml_append(mou, aml_name_decl("_CRS", crs)); 778 779 aml_append(scope, kbd); 780 aml_append(scope, mou); 781} 782 783static Property i8042_properties[] = { 784 DEFINE_PROP_BOOL("extended-state", ISAKBDState, kbd.extended_state, true), 785 DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false), 786 DEFINE_PROP_END_OF_LIST(), 787}; 788 789static void i8042_class_initfn(ObjectClass *klass, void *data) 790{ 791 DeviceClass *dc = DEVICE_CLASS(klass); 792 ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); 793 794 device_class_set_props(dc, i8042_properties); 795 dc->realize = i8042_realizefn; 796 dc->vmsd = &vmstate_kbd_isa; 797 isa->build_aml = i8042_build_aml; 798 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 799} 800 801static const TypeInfo i8042_info = { 802 .name = TYPE_I8042, 803 .parent = TYPE_ISA_DEVICE, 804 .instance_size = sizeof(ISAKBDState), 805 .instance_init = i8042_initfn, 806 .class_init = i8042_class_initfn, 807}; 808 809static void i8042_register_types(void) 810{ 811 type_register_static(&i8042_info); 812} 813 814type_init(i8042_register_types)