qemu/hw/input/pckbd.c
<<
>>
Prefs
   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#include "qemu/osdep.h"
  25#include "qemu/log.h"
  26#include "hw/hw.h"
  27#include "hw/isa/isa.h"
  28#include "hw/i386/pc.h"
  29#include "hw/input/ps2.h"
  30#include "hw/input/i8042.h"
  31#include "sysemu/sysemu.h"
  32
  33/* debug PC keyboard */
  34//#define DEBUG_KBD
  35#ifdef DEBUG_KBD
  36#define DPRINTF(fmt, ...)                                       \
  37    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
  38#else
  39#define DPRINTF(fmt, ...)
  40#endif
  41
  42/*      Keyboard Controller Commands */
  43#define KBD_CCMD_READ_MODE      0x20    /* Read mode bits */
  44#define KBD_CCMD_WRITE_MODE     0x60    /* Write mode bits */
  45#define KBD_CCMD_GET_VERSION    0xA1    /* Get controller version */
  46#define KBD_CCMD_MOUSE_DISABLE  0xA7    /* Disable mouse interface */
  47#define KBD_CCMD_MOUSE_ENABLE   0xA8    /* Enable mouse interface */
  48#define KBD_CCMD_TEST_MOUSE     0xA9    /* Mouse interface test */
  49#define KBD_CCMD_SELF_TEST      0xAA    /* Controller self test */
  50#define KBD_CCMD_KBD_TEST       0xAB    /* Keyboard interface test */
  51#define KBD_CCMD_KBD_DISABLE    0xAD    /* Keyboard interface disable */
  52#define KBD_CCMD_KBD_ENABLE     0xAE    /* Keyboard interface enable */
  53#define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
  54#define KBD_CCMD_READ_OUTPORT   0xD0    /* read output port */
  55#define KBD_CCMD_WRITE_OUTPORT  0xD1    /* write output port */
  56#define KBD_CCMD_WRITE_OBUF     0xD2
  57#define KBD_CCMD_WRITE_AUX_OBUF 0xD3    /* Write to output buffer as if
  58                                           initiated by the auxiliary device */
  59#define KBD_CCMD_WRITE_MOUSE    0xD4    /* Write the following byte to the mouse */
  60#define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
  61#define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
  62#define KBD_CCMD_PULSE_BITS_3_0 0xF0    /* Pulse bits 3-0 of the output port P2. */
  63#define KBD_CCMD_RESET          0xFE    /* Pulse bit 0 of the output port P2 = CPU reset. */
  64#define KBD_CCMD_NO_OP          0xFF    /* Pulse no bits of the output port P2. */
  65
  66/* Keyboard Commands */
  67#define KBD_CMD_SET_LEDS        0xED    /* Set keyboard leds */
  68#define KBD_CMD_ECHO            0xEE
  69#define KBD_CMD_GET_ID          0xF2    /* get keyboard ID */
  70#define KBD_CMD_SET_RATE        0xF3    /* Set typematic rate */
  71#define KBD_CMD_ENABLE          0xF4    /* Enable scanning */
  72#define KBD_CMD_RESET_DISABLE   0xF5    /* reset and disable scanning */
  73#define KBD_CMD_RESET_ENABLE    0xF6    /* reset and enable scanning */
  74#define KBD_CMD_RESET           0xFF    /* Reset */
  75
  76/* Keyboard Replies */
  77#define KBD_REPLY_POR           0xAA    /* Power on reset */
  78#define KBD_REPLY_ACK           0xFA    /* Command ACK */
  79#define KBD_REPLY_RESEND        0xFE    /* Command NACK, send the cmd again */
  80
  81/* Status Register Bits */
  82#define KBD_STAT_OBF            0x01    /* Keyboard output buffer full */
  83#define KBD_STAT_IBF            0x02    /* Keyboard input buffer full */
  84#define KBD_STAT_SELFTEST       0x04    /* Self test successful */
  85#define KBD_STAT_CMD            0x08    /* Last write was a command write (0=data) */
  86#define KBD_STAT_UNLOCKED       0x10    /* Zero if keyboard locked */
  87#define KBD_STAT_MOUSE_OBF      0x20    /* Mouse output buffer full */
  88#define KBD_STAT_GTO            0x40    /* General receive/xmit timeout */
  89#define KBD_STAT_PERR           0x80    /* Parity error */
  90
  91/* Controller Mode Register Bits */
  92#define KBD_MODE_KBD_INT        0x01    /* Keyboard data generate IRQ1 */
  93#define KBD_MODE_MOUSE_INT      0x02    /* Mouse data generate IRQ12 */
  94#define KBD_MODE_SYS            0x04    /* The system flag (?) */
  95#define KBD_MODE_NO_KEYLOCK     0x08    /* The keylock doesn't affect the keyboard if set */
  96#define KBD_MODE_DISABLE_KBD    0x10    /* Disable keyboard interface */
  97#define KBD_MODE_DISABLE_MOUSE  0x20    /* Disable mouse interface */
  98#define KBD_MODE_KCC            0x40    /* Scan code conversion to PC format */
  99#define KBD_MODE_RFU            0x80
 100
 101/* Output Port Bits */
 102#define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
 103#define KBD_OUT_A20             0x02    /* x86 only */
 104#define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
 105#define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
 106
 107/* OSes typically write 0xdd/0xdf to turn the A20 line off and on.
 108 * We make the default value of the outport include these four bits,
 109 * so that the subsection is rarely necessary.
 110 */
 111#define KBD_OUT_ONES            0xcc
 112
 113/* Mouse Commands */
 114#define AUX_SET_SCALE11         0xE6    /* Set 1:1 scaling */
 115#define AUX_SET_SCALE21         0xE7    /* Set 2:1 scaling */
 116#define AUX_SET_RES             0xE8    /* Set resolution */
 117#define AUX_GET_SCALE           0xE9    /* Get scaling factor */
 118#define AUX_SET_STREAM          0xEA    /* Set stream mode */
 119#define AUX_POLL                0xEB    /* Poll */
 120#define AUX_RESET_WRAP          0xEC    /* Reset wrap mode */
 121#define AUX_SET_WRAP            0xEE    /* Set wrap mode */
 122#define AUX_SET_REMOTE          0xF0    /* Set remote mode */
 123#define AUX_GET_TYPE            0xF2    /* Get type */
 124#define AUX_SET_SAMPLE          0xF3    /* Set sample rate */
 125#define AUX_ENABLE_DEV          0xF4    /* Enable aux device */
 126#define AUX_DISABLE_DEV         0xF5    /* Disable aux device */
 127#define AUX_SET_DEFAULT         0xF6
 128#define AUX_RESET               0xFF    /* Reset aux device */
 129#define AUX_ACK                 0xFA    /* Command byte ACK. */
 130
 131#define MOUSE_STATUS_REMOTE     0x40
 132#define MOUSE_STATUS_ENABLED    0x20
 133#define MOUSE_STATUS_SCALE21    0x10
 134
 135#define KBD_PENDING_KBD         1
 136#define KBD_PENDING_AUX         2
 137
 138typedef struct KBDState {
 139    uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
 140    uint8_t status;
 141    uint8_t mode;
 142    uint8_t outport;
 143    bool outport_present;
 144    /* Bitmask of devices with data available.  */
 145    uint8_t pending;
 146    void *kbd;
 147    void *mouse;
 148
 149    qemu_irq irq_kbd;
 150    qemu_irq irq_mouse;
 151    qemu_irq a20_out;
 152    hwaddr mask;
 153} KBDState;
 154
 155/* update irq and KBD_STAT_[MOUSE_]OBF */
 156/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
 157   incorrect, but it avoids having to simulate exact delays */
 158static void kbd_update_irq(KBDState *s)
 159{
 160    int irq_kbd_level, irq_mouse_level;
 161
 162    irq_kbd_level = 0;
 163    irq_mouse_level = 0;
 164    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
 165    s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
 166    if (s->pending) {
 167        s->status |= KBD_STAT_OBF;
 168        s->outport |= KBD_OUT_OBF;
 169        /* kbd data takes priority over aux data.  */
 170        if (s->pending == KBD_PENDING_AUX) {
 171            s->status |= KBD_STAT_MOUSE_OBF;
 172            s->outport |= KBD_OUT_MOUSE_OBF;
 173            if (s->mode & KBD_MODE_MOUSE_INT)
 174                irq_mouse_level = 1;
 175        } else {
 176            if ((s->mode & KBD_MODE_KBD_INT) &&
 177                !(s->mode & KBD_MODE_DISABLE_KBD))
 178                irq_kbd_level = 1;
 179        }
 180    }
 181    qemu_set_irq(s->irq_kbd, irq_kbd_level);
 182    qemu_set_irq(s->irq_mouse, irq_mouse_level);
 183}
 184
 185static void kbd_update_kbd_irq(void *opaque, int level)
 186{
 187    KBDState *s = (KBDState *)opaque;
 188
 189    if (level)
 190        s->pending |= KBD_PENDING_KBD;
 191    else
 192        s->pending &= ~KBD_PENDING_KBD;
 193    kbd_update_irq(s);
 194}
 195
 196static void kbd_update_aux_irq(void *opaque, int level)
 197{
 198    KBDState *s = (KBDState *)opaque;
 199
 200    if (level)
 201        s->pending |= KBD_PENDING_AUX;
 202    else
 203        s->pending &= ~KBD_PENDING_AUX;
 204    kbd_update_irq(s);
 205}
 206
 207static uint64_t kbd_read_status(void *opaque, hwaddr addr,
 208                                unsigned size)
 209{
 210    KBDState *s = opaque;
 211    int val;
 212    val = s->status;
 213    DPRINTF("kbd: read status=0x%02x\n", val);
 214    return val;
 215}
 216
 217static void kbd_queue(KBDState *s, int b, int aux)
 218{
 219    if (aux)
 220        ps2_queue(s->mouse, b);
 221    else
 222        ps2_queue(s->kbd, b);
 223}
 224
 225static void outport_write(KBDState *s, uint32_t val)
 226{
 227    DPRINTF("kbd: write outport=0x%02x\n", val);
 228    s->outport = val;
 229    qemu_set_irq(s->a20_out, (val >> 1) & 1);
 230    if (!(val & 1)) {
 231        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 232    }
 233}
 234
 235static void kbd_write_command(void *opaque, hwaddr addr,
 236                              uint64_t val, unsigned size)
 237{
 238    KBDState *s = opaque;
 239
 240    DPRINTF("kbd: write cmd=0x%02" PRIx64 "\n", val);
 241
 242    /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
 243     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
 244     * command specify the output port bits to be pulsed.
 245     * 0: Bit should be pulsed. 1: Bit should not be modified.
 246     * The only useful version of this command is pulsing bit 0,
 247     * which does a CPU reset.
 248     */
 249    if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
 250        if(!(val & 1))
 251            val = KBD_CCMD_RESET;
 252        else
 253            val = KBD_CCMD_NO_OP;
 254    }
 255
 256    switch(val) {
 257    case KBD_CCMD_READ_MODE:
 258        kbd_queue(s, s->mode, 0);
 259        break;
 260    case KBD_CCMD_WRITE_MODE:
 261    case KBD_CCMD_WRITE_OBUF:
 262    case KBD_CCMD_WRITE_AUX_OBUF:
 263    case KBD_CCMD_WRITE_MOUSE:
 264    case KBD_CCMD_WRITE_OUTPORT:
 265        s->write_cmd = val;
 266        break;
 267    case KBD_CCMD_MOUSE_DISABLE:
 268        s->mode |= KBD_MODE_DISABLE_MOUSE;
 269        break;
 270    case KBD_CCMD_MOUSE_ENABLE:
 271        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
 272        break;
 273    case KBD_CCMD_TEST_MOUSE:
 274        kbd_queue(s, 0x00, 0);
 275        break;
 276    case KBD_CCMD_SELF_TEST:
 277        s->status |= KBD_STAT_SELFTEST;
 278        kbd_queue(s, 0x55, 0);
 279        break;
 280    case KBD_CCMD_KBD_TEST:
 281        kbd_queue(s, 0x00, 0);
 282        break;
 283    case KBD_CCMD_KBD_DISABLE:
 284        s->mode |= KBD_MODE_DISABLE_KBD;
 285        kbd_update_irq(s);
 286        break;
 287    case KBD_CCMD_KBD_ENABLE:
 288        s->mode &= ~KBD_MODE_DISABLE_KBD;
 289        kbd_update_irq(s);
 290        break;
 291    case KBD_CCMD_READ_INPORT:
 292        kbd_queue(s, 0x80, 0);
 293        break;
 294    case KBD_CCMD_READ_OUTPORT:
 295        kbd_queue(s, s->outport, 0);
 296        break;
 297    case KBD_CCMD_ENABLE_A20:
 298        qemu_irq_raise(s->a20_out);
 299        s->outport |= KBD_OUT_A20;
 300        break;
 301    case KBD_CCMD_DISABLE_A20:
 302        qemu_irq_lower(s->a20_out);
 303        s->outport &= ~KBD_OUT_A20;
 304        break;
 305    case KBD_CCMD_RESET:
 306        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 307        break;
 308    case KBD_CCMD_NO_OP:
 309        /* ignore that */
 310        break;
 311    default:
 312        qemu_log_mask(LOG_GUEST_ERROR,
 313                      "unsupported keyboard cmd=0x%02" PRIx64 "\n", val);
 314        break;
 315    }
 316}
 317
 318static uint64_t kbd_read_data(void *opaque, hwaddr addr,
 319                              unsigned size)
 320{
 321    KBDState *s = opaque;
 322    uint32_t val;
 323
 324    if (s->pending == KBD_PENDING_AUX)
 325        val = ps2_read_data(s->mouse);
 326    else
 327        val = ps2_read_data(s->kbd);
 328
 329    DPRINTF("kbd: read data=0x%02x\n", val);
 330    return val;
 331}
 332
 333static void kbd_write_data(void *opaque, hwaddr addr,
 334                           uint64_t val, unsigned size)
 335{
 336    KBDState *s = opaque;
 337
 338    DPRINTF("kbd: write data=0x%02" PRIx64 "\n", val);
 339
 340    switch(s->write_cmd) {
 341    case 0:
 342        ps2_write_keyboard(s->kbd, val);
 343        break;
 344    case KBD_CCMD_WRITE_MODE:
 345        s->mode = val;
 346        ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
 347        /* ??? */
 348        kbd_update_irq(s);
 349        break;
 350    case KBD_CCMD_WRITE_OBUF:
 351        kbd_queue(s, val, 0);
 352        break;
 353    case KBD_CCMD_WRITE_AUX_OBUF:
 354        kbd_queue(s, val, 1);
 355        break;
 356    case KBD_CCMD_WRITE_OUTPORT:
 357        outport_write(s, val);
 358        break;
 359    case KBD_CCMD_WRITE_MOUSE:
 360        ps2_write_mouse(s->mouse, val);
 361        break;
 362    default:
 363        break;
 364    }
 365    s->write_cmd = 0;
 366}
 367
 368static void kbd_reset(void *opaque)
 369{
 370    KBDState *s = opaque;
 371
 372    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
 373    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
 374    s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES;
 375    s->outport_present = false;
 376}
 377
 378static uint8_t kbd_outport_default(KBDState *s)
 379{
 380    return KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES
 381           | (s->status & KBD_STAT_OBF ? KBD_OUT_OBF : 0)
 382           | (s->status & KBD_STAT_MOUSE_OBF ? KBD_OUT_MOUSE_OBF : 0);
 383}
 384
 385static int kbd_outport_post_load(void *opaque, int version_id)
 386{
 387    KBDState *s = opaque;
 388    s->outport_present = true;
 389    return 0;
 390}
 391
 392static bool kbd_outport_needed(void *opaque)
 393{
 394    KBDState *s = opaque;
 395    return s->outport != kbd_outport_default(s);
 396}
 397
 398static const VMStateDescription vmstate_kbd_outport = {
 399    .name = "pckbd_outport",
 400    .version_id = 1,
 401    .minimum_version_id = 1,
 402    .post_load = kbd_outport_post_load,
 403    .needed = kbd_outport_needed,
 404    .fields = (VMStateField[]) {
 405        VMSTATE_UINT8(outport, KBDState),
 406        VMSTATE_END_OF_LIST()
 407    }
 408};
 409
 410static int kbd_post_load(void *opaque, int version_id)
 411{
 412    KBDState *s = opaque;
 413    if (!s->outport_present) {
 414        s->outport = kbd_outport_default(s);
 415    }
 416    s->outport_present = false;
 417    return 0;
 418}
 419
 420static const VMStateDescription vmstate_kbd = {
 421    .name = "pckbd",
 422    .version_id = 3,
 423    .minimum_version_id = 3,
 424    .post_load = kbd_post_load,
 425    .fields = (VMStateField[]) {
 426        VMSTATE_UINT8(write_cmd, KBDState),
 427        VMSTATE_UINT8(status, KBDState),
 428        VMSTATE_UINT8(mode, KBDState),
 429        VMSTATE_UINT8(pending, KBDState),
 430        VMSTATE_END_OF_LIST()
 431    },
 432    .subsections = (const VMStateDescription*[]) {
 433        &vmstate_kbd_outport,
 434        NULL
 435    }
 436};
 437
 438/* Memory mapped interface */
 439static uint64_t kbd_mm_readfn(void *opaque, hwaddr addr, unsigned size)
 440{
 441    KBDState *s = opaque;
 442
 443    if (addr & s->mask)
 444        return kbd_read_status(s, 0, 1) & 0xff;
 445    else
 446        return kbd_read_data(s, 0, 1) & 0xff;
 447}
 448
 449static void kbd_mm_writefn(void *opaque, hwaddr addr,
 450                           uint64_t value, unsigned size)
 451{
 452    KBDState *s = opaque;
 453
 454    if (addr & s->mask)
 455        kbd_write_command(s, 0, value & 0xff, 1);
 456    else
 457        kbd_write_data(s, 0, value & 0xff, 1);
 458}
 459
 460
 461static const MemoryRegionOps i8042_mmio_ops = {
 462    .read = kbd_mm_readfn,
 463    .write = kbd_mm_writefn,
 464    .valid.min_access_size = 1,
 465    .valid.max_access_size = 4,
 466    .endianness = DEVICE_NATIVE_ENDIAN,
 467};
 468
 469void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
 470                   MemoryRegion *region, ram_addr_t size,
 471                   hwaddr mask)
 472{
 473    KBDState *s = g_malloc0(sizeof(KBDState));
 474
 475    s->irq_kbd = kbd_irq;
 476    s->irq_mouse = mouse_irq;
 477    s->mask = mask;
 478
 479    vmstate_register(NULL, 0, &vmstate_kbd, s);
 480
 481    memory_region_init_io(region, NULL, &i8042_mmio_ops, s, "i8042", size);
 482
 483    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
 484    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
 485    qemu_register_reset(kbd_reset, s);
 486}
 487
 488#define I8042(obj) OBJECT_CHECK(ISAKBDState, (obj), TYPE_I8042)
 489
 490typedef struct ISAKBDState {
 491    ISADevice parent_obj;
 492
 493    KBDState kbd;
 494    MemoryRegion io[2];
 495} ISAKBDState;
 496
 497void i8042_isa_mouse_fake_event(void *opaque)
 498{
 499    ISADevice *dev = opaque;
 500    ISAKBDState *isa = I8042(dev);
 501    KBDState *s = &isa->kbd;
 502
 503    ps2_mouse_fake_event(s->mouse);
 504}
 505
 506void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out)
 507{
 508    qdev_connect_gpio_out_named(DEVICE(dev), I8042_A20_LINE, 0, a20_out);
 509}
 510
 511static const VMStateDescription vmstate_kbd_isa = {
 512    .name = "pckbd",
 513    .version_id = 3,
 514    .minimum_version_id = 3,
 515    .fields = (VMStateField[]) {
 516        VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
 517        VMSTATE_END_OF_LIST()
 518    }
 519};
 520
 521static const MemoryRegionOps i8042_data_ops = {
 522    .read = kbd_read_data,
 523    .write = kbd_write_data,
 524    .impl = {
 525        .min_access_size = 1,
 526        .max_access_size = 1,
 527    },
 528    .endianness = DEVICE_LITTLE_ENDIAN,
 529};
 530
 531static const MemoryRegionOps i8042_cmd_ops = {
 532    .read = kbd_read_status,
 533    .write = kbd_write_command,
 534    .impl = {
 535        .min_access_size = 1,
 536        .max_access_size = 1,
 537    },
 538    .endianness = DEVICE_LITTLE_ENDIAN,
 539};
 540
 541static void i8042_initfn(Object *obj)
 542{
 543    ISAKBDState *isa_s = I8042(obj);
 544    KBDState *s = &isa_s->kbd;
 545
 546    memory_region_init_io(isa_s->io + 0, obj, &i8042_data_ops, s,
 547                          "i8042-data", 1);
 548    memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s,
 549                          "i8042-cmd", 1);
 550
 551    qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1);
 552}
 553
 554static void i8042_realizefn(DeviceState *dev, Error **errp)
 555{
 556    ISADevice *isadev = ISA_DEVICE(dev);
 557    ISAKBDState *isa_s = I8042(dev);
 558    KBDState *s = &isa_s->kbd;
 559
 560    isa_init_irq(isadev, &s->irq_kbd, 1);
 561    isa_init_irq(isadev, &s->irq_mouse, 12);
 562
 563    isa_register_ioport(isadev, isa_s->io + 0, 0x60);
 564    isa_register_ioport(isadev, isa_s->io + 1, 0x64);
 565
 566    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
 567    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
 568    qemu_register_reset(kbd_reset, s);
 569}
 570
 571static void i8042_class_initfn(ObjectClass *klass, void *data)
 572{
 573    DeviceClass *dc = DEVICE_CLASS(klass);
 574
 575    dc->realize = i8042_realizefn;
 576    dc->vmsd = &vmstate_kbd_isa;
 577}
 578
 579static const TypeInfo i8042_info = {
 580    .name          = TYPE_I8042,
 581    .parent        = TYPE_ISA_DEVICE,
 582    .instance_size = sizeof(ISAKBDState),
 583    .instance_init = i8042_initfn,
 584    .class_init    = i8042_class_initfn,
 585};
 586
 587static void i8042_register_types(void)
 588{
 589    type_register_static(&i8042_info);
 590}
 591
 592type_init(i8042_register_types)
 593