From 7b76b2af27abe74e8010a880e3a64a54ff192382 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Apr 2023 04:36:28 +0200 Subject: [PATCH] The PS/2 mouse poll is now also a state machine and fixed output port writes on AMI PS/2 keyboard controllers - fixes PS/2 mouse in Windows 3.1 on some machines. --- src/device/keyboard_at.c | 189 ++++++++++++++++++++++++++++----------- src/device/mouse_ps2.c | 41 +++++---- 2 files changed, 161 insertions(+), 69 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index b94343250..b0308529d 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -834,7 +834,6 @@ kbc_ibf_process(atkbd_t *dev) kbc_process_cmd(dev); else { set_enable_kbd(dev, 1); - kbc_queue_reset(4); dev->key_wantcmd = 1; dev->key_dat = dev->ib; dev->kbc_state = KBC_STATE_SCAN_KBD; @@ -1088,6 +1087,8 @@ kbc_poll_kbd(atkbd_t *dev) /* Process the command if needed and then return to main loop #2. */ if (dev->key_wantcmd) { kbd_log("ATkbc: Processing keyboard command...\n"); + kbc_queue_reset(4); + // dev->out_new = -1; kbd_process_cmd(dev); dev->key_wantcmd = 0; } else @@ -1095,48 +1096,141 @@ kbc_poll_kbd(atkbd_t *dev) break; case DEV_STATE_MAIN_2: /* Output from scan queue if needed and then return to main loop #1. */ - if (keyboard_scan && (key_queue_start != key_queue_end)) { + if (keyboard_scan && (dev->out_new == -1) && (key_queue_start != key_queue_end)) { kbd_log("ATkbc: %02X (DATA) on channel 1\n", key_queue[key_queue_start]); dev->out_new = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; } - dev->kbd_state = DEV_STATE_MAIN_1; + if (!keyboard_scan || (key_cmd_queue_start == key_cmd_queue_end)) + dev->kbd_state = DEV_STATE_MAIN_1; break; case DEV_STATE_MAIN_OUT: case DEV_STATE_RESET_OUT: - /* Output command resposne and then return to main loop #2. */ - if (key_cmd_queue_start != key_cmd_queue_end) { + /* Output command response and then return to main loop #2. */ + if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); dev->out_new = key_cmd_queue[key_cmd_queue_start]; key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; } - dev->kbd_state = (dev->kbd_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; + if (key_cmd_queue_start == key_cmd_queue_end) + dev->kbd_state = (dev->kbd_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; break; case DEV_STATE_MAIN_WANT_IN: /* Output command response and then wait for host data. */ - if (key_cmd_queue_start != key_cmd_queue_end) { + if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); dev->out_new = key_cmd_queue[key_cmd_queue_start]; key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; } - dev->kbd_state = DEV_STATE_MAIN_IN; + if (key_cmd_queue_start == key_cmd_queue_end) + dev->kbd_state = DEV_STATE_MAIN_IN; break; case DEV_STATE_MAIN_IN: /* Wait for host data. */ if (dev->key_wantcmd) { kbd_log("ATkbc: Processing keyboard command...\n"); + kbc_queue_reset(4); + // dev->out_new = -1; kbd_process_cmd(dev); dev->key_wantcmd = 0; } break; case DEV_STATE_MAIN_WANT_RESET: /* Output command response and then go to the reset state. */ - if (key_cmd_queue_start != key_cmd_queue_end) { + if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); dev->out_new = key_cmd_queue[key_cmd_queue_start]; key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; } - dev->kbd_state = DEV_STATE_RESET; + if (key_cmd_queue_start == key_cmd_queue_end) + dev->kbd_state = DEV_STATE_RESET; + break; + } +} + +static void +kbc_poll_aux(atkbd_t *dev) +{ + switch (dev->mouse_state) { +#if 0 + case DEV_STATE_RESET: + /* Reset state. */ + if (dev->mouse_reset_delay) { + dev->mouse_reset_delay--; + if (!dev->mouse_reset_delay) { + kbd_log("ATkbc: Sending AA 00 on mouse reset...\n"); + keyboard_at_adddata_mouse_cmd(0xaa); + keyboard_at_adddata_mouse_cmd(0x00); + dev->mouse_state = DEV_STATE_RESET_OUT; + } + } + break; +#endif + case DEV_STATE_MAIN_1: + /* Process the command if needed and then return to main loop #2. */ + if (dev->mouse_wantcmd) { + kbd_log("ATkbc: Processing mouse command...\n"); + kbc_queue_reset(3); + // dev->out_new_mouse = -1; + dev->mouse_state = DEV_STATE_MAIN_OUT; + mouse_write(dev->mouse_dat, mouse_p); + if ((dev->mouse_dat == 0xe8) || (dev->mouse_dat == 0xf3)) + dev->mouse_state = DEV_STATE_MAIN_WANT_IN; + dev->mouse_wantcmd = 0; + } else + dev->mouse_state = DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_2: + /* Output from scan queue if needed and then return to main loop #1. */ + if (mouse_scan && (dev->out_new_mouse == -1) && (mouse_queue_start != mouse_queue_end)) { + kbd_log("ATkbc: %02X (DATA) on channel 2\n", mouse_queue[mouse_queue_start]); + dev->out_new_mouse = mouse_queue[mouse_queue_start]; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } + if (!mouse_scan || (mouse_cmd_queue_start == mouse_cmd_queue_end)) + dev->mouse_state = DEV_STATE_MAIN_1; + break; + case DEV_STATE_MAIN_OUT: + case DEV_STATE_RESET_OUT: + /* Output command response and then return to main loop #2. */ + if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); + dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; + mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + } + if (mouse_cmd_queue_start == mouse_cmd_queue_end) + dev->mouse_state = (dev->mouse_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_WANT_IN: + /* Output command response and then wait for host data. */ + if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); + dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; + mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + } + if (mouse_cmd_queue_start == mouse_cmd_queue_end) + dev->mouse_state = DEV_STATE_MAIN_IN; + break; + case DEV_STATE_MAIN_IN: + /* Wait for host data. */ + if (dev->mouse_wantcmd) { + kbd_log("ATkbc: Processing mouse command...\n"); + kbc_queue_reset(3); + // dev->out_new_mouse = -1; + dev->mouse_state = DEV_STATE_MAIN_OUT; + mouse_write(dev->mouse_dat, mouse_p); + dev->mouse_wantcmd = 0; + } + break; + case DEV_STATE_MAIN_WANT_RESET: + /* Output command response and then go to the reset state. */ + if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); + dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; + mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + } + if (mouse_cmd_queue_start == mouse_cmd_queue_end) + dev->mouse_state = DEV_STATE_RESET; break; } } @@ -1151,38 +1245,15 @@ kbd_poll(void *priv) /* TODO: Use a fuction pointer for this (also needed to the AMI KBC mode switching) and implement the password security state. */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) - kbc_poll_at(dev); - else + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) kbc_poll_ps2(dev); + else + kbc_poll_at(dev); kbc_poll_kbd(dev); - if (dev->mouse_reset_delay) { - dev->mouse_reset_delay--; - if (!dev->mouse_reset_delay) { - kbd_log("ATkbc: Sending AA 00 on mouse reset...\n"); - // keyboard_at_adddata_mouse_cmd(0xaa); - // keyboard_at_adddata_mouse_cmd(0x00); - } - } else if (dev->mouse_wantcmd) { - if ((mouse_cmd_queue_start == mouse_cmd_queue_end) && (dev->out_new == -1) && (dev->mouse_reset_delay == 0)) { - mouse_write(dev->mouse_dat, mouse_p); - // if (dev->mouse_dat == 0xff) - // dev->mouse_reset_delay = RESET_DELAY_TIME; - dev->mouse_wantcmd = 0; - } - } else if (dev->out_new_mouse == -1) { - if (mouse_cmd_queue_start != mouse_cmd_queue_end) { - kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); - dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; - mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; - } else if (mouse_queue_start != mouse_queue_end) { - kbd_log("ATkbc: %02X (DATA) on channel 2\n", mouse_queue[mouse_queue_start]); - dev->out_new_mouse = mouse_queue[mouse_queue_start]; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } - } + if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && mouse_write) + kbc_poll_aux(dev); } static void @@ -1549,8 +1620,7 @@ write_cmd(atkbd_t *dev, uint8_t val) kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); } - if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || - (kbc_ven == KBC_VEN_TG_GREEN) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { /* Update the output port to mirror the IBF and OBF bits, if active. */ write_output(dev, (dev->output_port & 0x0f) | ((val & 0x03) << 4) | ((val & 0x20) ? 0xc0 : 0x00)); } @@ -1685,8 +1755,6 @@ write64_generic(void *priv, uint8_t val) case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - set_enable_mouse(dev, 1); - kbc_queue_reset(3); dev->want60 = 1; dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; @@ -2169,10 +2237,11 @@ kbd_key_reset(atkbd_t *dev, int do_fa) keyboard_mode = (keyboard_mode & 0xfc) | 0x02; set_scancode_map(dev); + keyboard_scan = 1; + if (do_fa) add_data_kbd_raw(dev, 0xfa); - keyboard_scan = 1; dev->reset_delay = RESET_DELAY_TIME; if (do_fa) @@ -2181,14 +2250,30 @@ kbd_key_reset(atkbd_t *dev, int do_fa) dev->kbd_state = DEV_STATE_RESET; } +static void +kbd_aux_reset(atkbd_t *dev, int do_fa) +{ + kbc_queue_reset(2); + + mouse_scan = 1; + + if (!do_fa) + dev->mouse_state = DEV_STATE_MAIN_1; +} + +void +keyboard_at_mouse_reset(void) +{ + atkbd_t *dev = SavedKbd; + + kbd_aux_reset(dev, 1); +} + static void kbd_process_cmd(void *priv) { atkbd_t *dev = (atkbd_t *) priv; - /* Write data to keyboard. */ - dev->mem[0x20] &= ~0x10; - dev->kbd_state = DEV_STATE_MAIN_OUT; if (dev->key_wantdata) { @@ -2579,10 +2664,9 @@ kbc_process_cmd(void *priv) if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { set_enable_mouse(dev, 1); if (mouse_write) { - kbc_queue_reset(3); dev->mouse_wantcmd = 1; dev->mouse_dat = dev->ib; - dev->kbc_state = KBC_STATE_MOUSE; + dev->kbc_state = KBC_STATE_SCAN_MOUSE; } else add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); } @@ -2744,6 +2828,9 @@ kbd_reset(void *priv) /* Reset the keyboard. */ kbd_key_reset(dev, 0); + + /* Reset the mouse. */ + kbd_aux_reset(dev, 0); } /* Reset the AT keyboard - this is needed for the PCI TRC and is done @@ -3173,12 +3260,6 @@ keyboard_at_adddata_mouse_cmd(uint8_t val) kbc_queue_add(dev, val, 3); } -void -keyboard_at_mouse_reset(void) -{ - kbc_queue_reset(2); -} - uint8_t keyboard_at_mouse_pos(void) { diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 1fb2442ac..1c8e0334d 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -85,15 +85,24 @@ static void ps2_report_coordinates(mouse_t *dev, int cmd) { uint8_t buff[3] = { 0x08, 0x00, 0x00 }; + int temp_z; - if (dev->x > 255) + if (dev->x > 255) { dev->x = 255; - if (dev->x < -256) + buff[0] |= 0x40; + } + if (dev->x < -256) { dev->x = -256; - if (dev->y > 255) + buff[0] |= 0x40; + } + if (dev->y > 255) { dev->y = 255; - if (dev->y < -256) + buff[0] |= 0x80; + } + if (dev->y < -256) { dev->y = -256; + buff[0] |= 0x80; + } if (dev->z < -8) dev->z = -8; if (dev->z > 7) @@ -124,13 +133,16 @@ ps2_report_coordinates(mouse_t *dev, int cmd) keyboard_at_adddata_mouse(buff[2]); } if (dev->flags & FLAG_INTMODE) { - int temp_z = dev->z; + temp_z = dev->z & 0x0f; if ((dev->flags & FLAG_5BTN)) { - temp_z &= 0xF; if (mouse_buttons & 8) temp_z |= 0x10; if (mouse_buttons & 16) temp_z |= 0x20; + } else { + /* The wheel coordinate is sign-extended. */ + if (temp_z & 0x08) + temp_z |= 0xf0; } if (cmd) keyboard_at_adddata_mouse_cmd(temp_z); @@ -262,16 +274,15 @@ mouse_reset: dev->last_data[5] = val; - if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8 - && dev->last_data[2] == 0xf3 && dev->last_data[3] == 0xc8 - && dev->last_data[4] == 0xf3 && dev->last_data[5] == 0x50 - && mouse_get_buttons() == 5) { - dev->flags |= FLAG_INTMODE | FLAG_5BTN; - } else if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8 - && dev->last_data[2] == 0xf3 && dev->last_data[3] == 0x64 - && dev->last_data[4] == 0xf3 && dev->last_data[5] == 0x50) { + if ((dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) && + (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0x64) && + (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50)) dev->flags |= FLAG_INTMODE; - } + + if ((dev->flags & FLAG_INTMODE) && (dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) && + (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0xc8) && + (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50)) + dev->flags |= FLAG_5BTN; } }