diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 516ed5a397..62a3b29074 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -136,14 +136,19 @@ #define KBD_MIGR_TIMER_PENDING 0x1 +#define KBD_OBSRC_KBD 0x01 +#define KBD_OBSRC_MOUSE 0x02 + typedef struct KBDState { uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ uint8_t status; uint8_t mode; uint8_t outport; uint32_t migration_flags; + uint32_t obsrc; bool outport_present; bool extended_state; + bool extended_state_loaded; /* Bitmask of devices with data available. */ uint8_t pending; uint8_t obdata; @@ -200,6 +205,9 @@ static void kbd_update_irq(KBDState *s) if (s->pending == KBD_PENDING_AUX) { s->status |= KBD_STAT_MOUSE_OBF; s->outport |= KBD_OUT_MOUSE_OBF; + s->obsrc = KBD_OBSRC_MOUSE; + } else { + s->obsrc = KBD_OBSRC_KBD; } } kbd_update_irq_lines(s); @@ -370,18 +378,17 @@ static uint64_t kbd_read_data(void *opaque, hwaddr addr, unsigned size) { KBDState *s = opaque; - uint8_t status = s->status; - if (status & KBD_STAT_OBF) { + if (s->status & KBD_STAT_OBF) { kbd_deassert_irq(s); - if (status & KBD_STAT_MOUSE_OBF) { - s->obdata = ps2_read_data(s->mouse); - } else { + if (s->obsrc & KBD_OBSRC_KBD) { if (s->throttle_timer) { timer_mod(s->throttle_timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000); } s->obdata = ps2_read_data(s->kbd); + } else if (s->obsrc & KBD_OBSRC_MOUSE) { + s->obdata = ps2_read_data(s->mouse); } } @@ -498,6 +505,7 @@ static int kbd_extended_state_post_load(void *opaque, int version_id) if (s->migration_flags & KBD_MIGR_TIMER_PENDING) { kbd_throttle_timeout(s); } + s->extended_state_loaded = true; return 0; } @@ -516,11 +524,20 @@ static const VMStateDescription vmstate_kbd_extended_state = { .needed = kbd_extended_state_needed, .fields = (VMStateField[]) { VMSTATE_UINT32(migration_flags, KBDState), + VMSTATE_UINT32(obsrc, KBDState), VMSTATE_UINT8(obdata, KBDState), VMSTATE_END_OF_LIST() } }; +static int kbd_pre_load(void *opaque) +{ + KBDState *s = opaque; + + s->extended_state_loaded = false; + return 0; +} + static int kbd_post_load(void *opaque, int version_id) { KBDState *s = opaque; @@ -528,6 +545,11 @@ static int kbd_post_load(void *opaque, int version_id) s->outport = kbd_outport_default(s); } s->outport_present = false; + if (!s->extended_state_loaded) { + s->obsrc = s->status & KBD_STAT_OBF ? + (s->status & KBD_STAT_MOUSE_OBF ? KBD_OBSRC_MOUSE : KBD_OBSRC_KBD) : + 0; + } return 0; } @@ -535,6 +557,7 @@ static const VMStateDescription vmstate_kbd = { .name = "pckbd", .version_id = 3, .minimum_version_id = 3, + .pre_load = kbd_pre_load, .post_load = kbd_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(write_cmd, KBDState),