From 949e145be3de6713bcaf932cbc218d4e5afdf283 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 4 Aug 2020 04:01:54 +0200 Subject: [PATCH] Rewrite of AT keyboard controller polling. --- src/chipset/intel_piix.c | 2 + src/device/keyboard_at.c | 255 +++++++++++++++++++++++------------ src/device/mouse_ps2.c | 4 +- src/include/86box/keyboard.h | 2 + 4 files changed, 172 insertions(+), 91 deletions(-) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index c5e751c78..2b3b1e812 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -886,6 +886,8 @@ piix_read(int func, int addr, void *priv) if ((func <= dev->max_func) || ((func == 1) && (dev->max_func == 0))) { fregs = (uint8_t *) dev->regs[func]; ret = fregs[addr]; + if ((func == 0) && (addr == 0x4e)) + ret |= keyboard_at_get_mouse_scan(); piix_log("PIIX function %i read: %02X from %02X\n", func, ret, addr); } diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index dfcc1947b..40409d265 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -97,7 +97,10 @@ typedef struct { uint8_t mem[0x100]; - int out_new, out_delayed; + int out_new; +#ifdef USE_OUT_DELAYED + int out_delayed; +#endif int last_irq, reset_delay; uint32_t flags; @@ -125,17 +128,11 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; -int mouse_queue_start = 0, - mouse_queue_end = 0; - -static uint8_t key_ctrl_queue[16]; -static int key_ctrl_queue_start = 0, - key_ctrl_queue_end = 0; -static uint8_t key_queue[16]; -static int key_queue_start = 0, - key_queue_end = 0; -static uint8_t mouse_queue[16]; +static uint8_t kbc_queue_pos, channel_queue_pos[3]; +static uint16_t kbc_queue[48]; +static uint8_t kbd_last_scan_code; +static uint8_t channel_queue[3][16]; static void (*mouse_write)(uint8_t val, void *priv) = NULL; static void *mouse_p = NULL; static uint8_t sc_or = 0; @@ -624,72 +621,95 @@ set_scancode_map(atkbd_t *dev) } +static void +kbc_queue_add(uint8_t val, uint8_t channel) +{ + if ((channel > 0x03) || (kbc_queue_pos >= 48)) + return; + kbd_log("kbc_queue[%02X] = %04X;\n", kbc_queue_pos, val | (channel << 8)); + kbc_queue[kbc_queue_pos] = val | (channel << 8); + kbc_queue_pos++; +} + + +static int +channel_queue_get(uint8_t channel) +{ + int i, ret; + + if (channel_queue_pos[channel] != 0) { + ret = channel_queue[channel][0]; + kbd_log("channel_queue_get(%i): ret = %02X;\n", (uint32_t) channel, (uint32_t) channel_queue[channel][0]); + for (i = 0; i < 15; i++) + channel_queue[channel][i] = channel_queue[channel][i + 1]; + channel_queue_pos[channel]--; + } else + ret = -1; + + return ret; +} + + +static void +channel_queue_check(uint8_t channel) +{ + int val; + + if (channel >= 0x03) + return; + + if ((channel == 0x01) && !keyboard_scan) + return; + if ((channel == 0x02) && !mouse_scan) + return; + + val = channel_queue_get(channel); + if (val == -1) + return; + kbc_queue_add(val & 0xff, channel); +} + + static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t irq_table[4] = { 0x0000, 0x0002, 0x1000, 0xffff }; + int i, channel = (dev->out_new >> 8) & 0x03; + uint16_t irq = irq_table[channel]; timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd[B]: out_new = %i, out_delayed = %i, STAT_OFULL = %i, qs = %i, qe = %i, last_irq = %08X\n", - dev->out_new, dev->out_delayed, !!(dev->status & STAT_OFULL), key_ctrl_queue_start, key_ctrl_queue_end, dev->last_irq); -#endif + channel_queue_check(0x00); /* Transfer the next controller byte to the controller queue if there is any. */ + channel_queue_check(0x01); /* Transfer the next keyboard byte to the controller queue if there is any. */ + channel_queue_check(0x02); /* Transfer the next mouse byte to the controller queue if there is any. */ - if ((dev->out_new != -1) && !dev->last_irq) { + if ((channel != 0x03) && !dev->last_irq) { dev->wantirq = 0; - if (dev->out_new & 0x100) { - if (mouse_scan) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: want mouse data\n"); -#endif - if (dev->mem[0] & 0x02) - picint(0x1000); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status |= STAT_OFULL; - dev->status &= ~STAT_IFULL; - dev->status |= STAT_MFULL; - dev->last_irq = 0x1000; - } else - dev->out_new = -1; - } else { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: want keyboard data\n"); -#endif - if (dev->mem[0] & 0x01) - picint(2); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status |= STAT_OFULL; - dev->status &= ~STAT_IFULL; + + if ((channel == 0) || (dev->mem[0] & channel)) + picint(irq); + dev->out = dev->out_new & 0xff; + dev->out_new = 0xffff; + dev->status |= STAT_OFULL; + dev->status &= ~STAT_IFULL; + if (channel == 0x02) + dev->status |= STAT_MFULL; + else dev->status &= ~STAT_MFULL; - dev->last_irq = 2; - } + dev->last_irq = irq; } -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd[A]: out_new = %i, out_delayed = %i, STAT_OFULL = %i, qs = %i, qe = %i, last_irq = %08X\n", - dev->out_new, dev->out_delayed, !!(dev->status & STAT_OFULL), key_ctrl_queue_start, key_ctrl_queue_end, dev->last_irq); + if ((dev->out_new == 0xffff) && !(dev->status & STAT_OFULL) && (kbc_queue_pos != 0)) { + dev->out_new = kbc_queue[0]; + for (i = 0; i < 47; i++) + kbc_queue[i] = kbc_queue[i + 1]; + kbc_queue_pos = (kbc_queue_pos - 1) & 0xff; +#ifdef USE_OUT_DELAYED + } else if (!(dev->status & STAT_OFULL) && dev->out_new == 0xffff && dev->out_delayed != 0xffff) { + dev->out_new = dev->out_delayed; + dev->out_delayed = 0xffff; #endif - - if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { - dev->out_new = dev->out_delayed; - dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && dev->out_delayed != -1) { - dev->out_new = dev->out_delayed; - dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1/* && !(dev->mem[0] & 0x20)*/ && - (mouse_queue_start != mouse_queue_end)) { - dev->out_new = mouse_queue[mouse_queue_start] | 0x100; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && - !(dev->mem[0]&0x10) && (key_queue_start != key_queue_end)) { - dev->out_new = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; } if (dev->reset_delay) { @@ -706,16 +726,34 @@ add_data(atkbd_t *dev, uint8_t val) #ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: add to queue\n"); #endif - key_ctrl_queue[key_ctrl_queue_end] = val; - key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - if (! (dev->out_new & 0x300)) { + if (channel_queue_pos[0] < 16) { + kbd_log("channel_queue[0][channel_queue_pos[0]] = %02X;\n", (uint32_t) val); + channel_queue[0][channel_queue_pos[0]] = val; + channel_queue_pos[0]++; + } + +#ifdef USE_OUT_DELAYED + if (((dev->out_new & 0x0300) == 0x0100) || ((dev->out_new & 0x0300) == 0x0200)) { #ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: delay\n"); #endif dev->out_delayed = dev->out_new; - dev->out_new = -1; + dev->out_new = 0xffff; } +#endif +} + + +static void +add_data_kbd_queue(uint8_t val) +{ + if (!keyboard_scan || (channel_queue_pos[1] >= 16)) + return; + kbd_log("channel_queue[1][channel_queue_pos[1]] = %02X;\n", (uint32_t) val); + channel_queue[1][channel_queue_pos[1]] = val; + channel_queue_pos[1]++; + kbd_last_scan_code = val; } @@ -748,11 +786,8 @@ add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) #ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("%02X", send); #endif - key_queue[key_queue_end] = send; - key_queue_end = (key_queue_end + 1) & 0xf; -#ifdef ENABLE_KEYBOARD_AT_LOG - if (i < (len - 1)) kbd_log(" "); -#endif + + add_data_kbd_queue(send); } #ifdef ENABLE_KEYBOARD_AT_LOG @@ -998,8 +1033,7 @@ add_data_kbd(uint16_t val) kbd_log("%02X\n", val); #endif - key_queue[key_queue_end] = (translate ? (nont_to_t[val] | sc_or) : val); - key_queue_end = (key_queue_end + 1) & 0xf; + add_data_kbd_queue(translate ? (nont_to_t[val] | sc_or) : val); break; } @@ -1779,6 +1813,9 @@ kbd_write(uint16_t port, uint8_t val, void *priv) * mess up with this, and repeat the command * code many times. Fun! */ +/* Sure, but it is perfectly valid for a command parameter to be identical + to the command itself, and this would mess with that. */ +#if 0 if (val == dev->key_command) { #if 1 /* Respond NAK and ignore it. */ @@ -1789,6 +1826,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) goto do_command; #endif } +#endif switch (dev->key_command) { case 0xed: /* set/reset LEDs */ @@ -1928,8 +1966,10 @@ do_command: #ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set defaults\n"); #endif - dev->out_new = -1; - dev->out_delayed = -1; + dev->out_new = 0xffff; +#ifdef USE_OUT_DELAYED + dev->out_delayed = 0xffff; +#endif add_data_kbd(0xfa); keyboard_set3_all_break = 0; @@ -1976,14 +2016,16 @@ do_command: #ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: reset last scan code\n"); #endif - add_data_kbd(key_queue[key_queue_end]); + add_data_kbd_queue(kbd_last_scan_code); break; case 0xff: /* reset */ #ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: kbd reset\n"); #endif - key_queue_start = key_queue_end = 0; /*Clear key queue*/ + channel_queue_pos[1] = 0; + memset(channel_queue[1], 0x00, 16); + kbd_last_scan_code = 0x00; add_data_kbd(0xfa); /* Set scan code set to 2. */ @@ -2063,10 +2105,19 @@ do_command: kbd_log("ATkbd: self-test reinitialization\n"); #endif dev->initialized = 1; - key_ctrl_queue_start = key_ctrl_queue_end = 0; + memset(kbc_queue, 0x00, 48 * sizeof(uint16_t)); + kbc_queue_pos = 0; + for (i = 0; i < 2; i++) { + memset(channel_queue[i], 0x00, 16); + channel_queue_pos[i] = 0; + } + kbd_last_scan_code = 0x00; dev->status &= ~STAT_OFULL; dev->last_irq = 0; - dev->out_new = dev->out_delayed = -1; + dev->out_new = 0xffff; +#ifdef USE_OUT_DELAYED + dev->out_delayed = 0xffff; +#endif } dev->status |= STAT_SYSFLAG; dev->mem[0] |= 0x04; @@ -2283,17 +2334,19 @@ static void kbd_reset(void *priv) { atkbd_t *dev = (atkbd_t *)priv; + int i; dev->initialized = 0; dev->first_write = 1; dev->status = STAT_UNLOCKED | STAT_CD; dev->mem[0] = 0x01; - // if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) - dev->mem[0] |= CCB_TRANSLATE; + dev->mem[0] |= CCB_TRANSLATE; dev->wantirq = 0; write_output(dev, 0xcf); - dev->out_new = -1; - dev->out_delayed = -1; + dev->out_new = 0xffff; +#ifdef USE_OUT_DELAYED + dev->out_delayed = 0xffff; +#endif dev->last_irq = 0; dev->secr_phase = 0; dev->key_wantdata = 0; @@ -2311,6 +2364,14 @@ kbd_reset(void *priv) set_enable_kbd(dev, 1); set_enable_mouse(dev, 0); + memset(kbc_queue, 0x00, 48 * sizeof(uint16_t)); + kbc_queue_pos = 0; + for (i = 0; i < 2; i++) { + memset(channel_queue[i], 0x00, 16); + channel_queue_pos[i] = 0; + } + kbd_last_scan_code = 0; + sc_or = 0; memset(keyboard_set3_flags, 0, 512); @@ -2585,16 +2646,32 @@ keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) void keyboard_at_adddata_keyboard_raw(uint8_t val) { - key_queue[key_queue_end] = val; - key_queue_end = (key_queue_end + 1) & 0xf; + add_data_kbd_queue(val); } void keyboard_at_adddata_mouse(uint8_t val) { - mouse_queue[mouse_queue_end] = val; - mouse_queue_end = (mouse_queue_end + 1) & 0xf; + if (!mouse_scan || (channel_queue_pos[2] >= 16)) + return; + channel_queue[2][channel_queue_pos[2]] = val; + channel_queue_pos[2]++; +} + + +void +keyboard_at_mouse_reset(void) +{ + channel_queue_pos[2] = 0; + memset(channel_queue[2], 0x00, 16); +} + + +uint8_t +keyboard_at_mouse_pos(void) +{ + return channel_queue_pos[2]; } diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 70f60c568..ee4c8400d 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -190,7 +190,7 @@ ps2_write(uint8_t val, void *priv) case 0xff: /* reset */ dev->mode = MODE_STREAM; dev->flags &= 0x88; - mouse_queue_start = mouse_queue_end = 0; + keyboard_at_mouse_reset(); keyboard_at_adddata_mouse(0xfa); keyboard_at_adddata_mouse(0xaa); keyboard_at_adddata_mouse(0x00); @@ -236,7 +236,7 @@ ps2_poll(int x, int y, int z, int b, void *priv) dev->y -= y; dev->z -= z; if ((dev->mode == MODE_STREAM) && (dev->flags & FLAG_ENABLED) && - (((mouse_queue_end - mouse_queue_start) & 0x0f) < 13)) { + (keyboard_at_mouse_pos() < 13)) { dev->b = b; if (dev->x > 255) dev->x = 255; diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index f4c8f4540..90a3ab095 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -103,6 +103,8 @@ extern int keyboard_ismsexit(void); extern void keyboard_at_adddata_keyboard_raw(uint8_t val); extern void keyboard_at_adddata_mouse(uint8_t val); +extern void keyboard_at_mouse_reset(void); +extern uint8_t keyboard_at_mouse_pos(void); extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val,void *), void *); extern void keyboard_at_set_a20_key(int state); extern uint8_t keyboard_at_get_mouse_scan(void);