Currently the PS/2 controller command KBD_CCMD_MOUSE_DISABLE doesn't disable the PS/2 mouse communication at all, and the PS/2 controller commands KBD_CCMD_KBD_DISABLE and KBD_CCMD_KBD_ENABLE only disable and enable the keyboard interrupt, which is very different from what a real PS/2 controller does. A guest may notice the difference.
Mask out pending data on disabled queues to correctly disable the PS/2 controller communication. Signed-off-by: Volker Rümelin <vr_q...@t-online.de> --- hw/input/pckbd.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 199367dcab..cf2f4ee27a 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -130,10 +130,12 @@ #define MOUSE_STATUS_ENABLED 0x20 #define MOUSE_STATUS_SCALE21 0x10 -#define KBD_PENDING_KBD 1 -#define KBD_PENDING_AUX 2 +#define KBD_PENDING_KBD_V3 0x01 +#define KBD_PENDING_AUX_V3 0x02 #define KBD_PENDING_CTRL_KBD 0x04 #define KBD_PENDING_CTRL_AUX 0x08 +#define KBD_PENDING_KBD KBD_MODE_DISABLE_KBD /* 0x10 */ +#define KBD_PENDING_AUX KBD_MODE_DISABLE_MOUSE /* 0x20 */ #define KBD_MIGR_TIMER_PENDING 0x1 @@ -197,7 +199,7 @@ static void kbd_deassert_irq(KBDState *s) static uint8_t kbd_pending(KBDState *s) { - return s->pending; + return s->pending & (~s->mode | ~(KBD_PENDING_KBD | KBD_PENDING_AUX)); } /* update irq and KBD_STAT_[MOUSE_]OBF */ @@ -354,6 +356,7 @@ static void kbd_write_command(void *opaque, hwaddr addr, break; case KBD_CCMD_MOUSE_ENABLE: s->mode &= ~KBD_MODE_DISABLE_MOUSE; + kbd_safe_update_irq(s); break; case KBD_CCMD_TEST_MOUSE: kbd_queue(s, 0x00, 0); @@ -433,6 +436,9 @@ static void kbd_write_data(void *opaque, hwaddr addr, switch(s->write_cmd) { case 0: ps2_write_keyboard(s->kbd, val); + /* sending data to the keyboard reenables PS/2 communication */ + s->mode &= ~KBD_MODE_DISABLE_KBD; + kbd_safe_update_irq(s); break; case KBD_CCMD_WRITE_MODE: s->mode = val; @@ -459,6 +465,9 @@ static void kbd_write_data(void *opaque, hwaddr addr, break; case KBD_CCMD_WRITE_MOUSE: ps2_write_mouse(s->mouse, val); + /* sending data to the mouse reenables PS/2 communication */ + s->mode &= ~KBD_MODE_DISABLE_MOUSE; + kbd_safe_update_irq(s); break; default: break; @@ -536,7 +545,16 @@ static int kbd_post_load(void *opaque, int version_id) s->obsrc = s->status & KBD_STAT_OBF ? (s->status & KBD_STAT_MOUSE_OBF ? KBD_OBSRC_MOUSE : KBD_OBSRC_KBD) : 0; + if (s->pending & KBD_PENDING_KBD_V3) { + s->pending |= KBD_PENDING_KBD; + } + if (s->pending & KBD_PENDING_AUX_V3) { + s->pending |= KBD_PENDING_AUX; + } } + /* clear all unused flags */ + s->pending &= KBD_PENDING_CTRL_KBD | KBD_PENDING_CTRL_AUX | + KBD_PENDING_KBD | KBD_PENDING_AUX; if (s->migration_flags & KBD_MIGR_TIMER_PENDING) { kbd_throttle_timeout(s); } -- 2.26.2