From 9e87daa2bde5e2ad75383515aaa64a57df7e4d71 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 6 Apr 2023 20:54:18 -0300 Subject: [PATCH 1/8] Jenkins: Fix AppImage icon searching, closes #2904 --- .ci/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/build.sh b/.ci/build.sh index 9b4494c46..ea49fa825 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -1014,7 +1014,7 @@ else mkdir -p "$icon_dir" cp -rp "$icon_size" "$icon_dir/apps" done - project_icon=$(ls "$icon_base/"[0-9]*x[0-9]*/* | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)') + project_icon=$(find "$icon_base/"[0-9]*x[0-9]*/* -type f -name '*.png' | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)') # Archive executable, while also stripping it if requested. mkdir -p archive_tmp/usr/local/bin From 9ea3014c591e5057cb00e95cdd40c35e60276a66 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 7 Apr 2023 15:23:09 +0200 Subject: [PATCH 2/8] The keyboard controller now correctly processes IBF even if OBF is set, fixes AMIBIOS 6.x machines such as the Supermicro P6SBA. --- src/device/keyboard_at.c | 51 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 4035a8fc6..7ab2d111f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -823,33 +823,32 @@ kbd_poll(void *priv) break; /* Process commands and/or monitor the attached devices. */ case KBC_STATE_NORMAL: - if (!(dev->status & STAT_OFULL)) { - if (dev->status & STAT_IFULL) { + /* Always process IBF, even if OBF is set. */ + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + if ((dev->status & STAT_CD) || dev->want60) + kbc_process_cmd(dev); + else if (!(dev->status & STAT_CD) && !dev->want60) { dev->status &= ~STAT_IFULL; - if ((dev->status & STAT_CD) || dev->want60) - kbc_process_cmd(dev); - else if (!(dev->status & STAT_CD) && !dev->want60) { - dev->status &= ~STAT_IFULL; - set_enable_kbd(dev, 1); - kbc_queue_reset(4); - dev->key_wantcmd = 1; - dev->key_dat = dev->ib; - dev->kbc_state = KBC_STATE_KBD; - } - } else { - if (key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); - add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; - } else if (mouse_enabled && (dev->out_new_mouse != -1)) { - kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); - add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); - dev->out_new_mouse = -1; - } else if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { - kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); - add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); - dev->out_new = -1; - } + set_enable_kbd(dev, 1); + kbc_queue_reset(4); + dev->key_wantcmd = 1; + dev->key_dat = dev->ib; + dev->kbc_state = KBC_STATE_KBD; + } + } else if (!(dev->status & STAT_OFULL)) { + if (key_ctrl_queue_start != key_ctrl_queue_end) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; + } else if (mouse_enabled && (dev->out_new_mouse != -1)) { + kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); + add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); + dev->out_new_mouse = -1; + } else if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { + kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; } } break; From 1c8fd2c7fcd317c1d4ea553bb72e431cf5b05a1d Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 7 Apr 2023 23:36:02 +0200 Subject: [PATCH 3/8] Rewritten the AT KBC polling, PS/2 is coming soon. --- src/device/keyboard_at.c | 148 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 7ab2d111f..4179f5fd3 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -95,9 +95,13 @@ enum { KBC_STATE_RESET = 0, KBC_STATE_NORMAL, + KBC_STATE_KBC_OUT, + KBC_STATE_KBC_PARAM, KBC_STATE_KBD, KBC_STATE_MOUSE }; +#define KBC_STATE_SCAN_KBD KBC_STATE_KBD +#define KBC_STATE_SCAN_MOUSE KBC_STATE_MOUSE typedef struct { uint8_t command, status, ib, out, @@ -584,6 +588,7 @@ static const scancode scancode_set3[512] = { static void add_data_kbd(uint16_t val); +// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -804,6 +809,117 @@ set_enable_mouse(atkbd_t *dev, uint8_t enable) dev->mem[0x20] |= (enable ? 0x00 : 0x20); } +static void +kbc_ibf_process(atkbd_t *dev) +{ + /* IBF set, process both commands and data. */ + dev->status &= ~STAT_IFULL; + dev->kbc_state = KBC_STATE_NORMAL; + if (dev->status & STAT_CD) + 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; + } +} + +static void +kbc_scan_kbd_at(atkbd_t *dev) +{ + if (!(dev->mem[0x20] & 0x10)) { + /* Both OBF and IBF clear and keyboard is enabled. */ + /* XT mode. */ + if (dev->mem[0x20] & 0x20) { + if (dev->out_new != -1) { + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_NORMAL; + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + /* AT mode. */ + } else { + // dev->t = dev->mem[0x28]; + if (dev->mem[0x2e] != 0x00) { + // if (!(dev->t & 0x02)) + // return; + dev->mem[0x2e] = 0x00; + } + dev->output_port &= 0xbf; + if (dev->out_new != -1) { + /* In our case, we never have noise on the line, so we can simplify this. */ + /* Read data from the keyboard. */ + if (dev->mem[0x20] & 0x40) { + if ((dev->mem[0x20] & 0x08) || (dev->input_port & 0x80)) + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->mem[0x2d] = (dev->out_new == 0xf0) ? 0x80 : 0x00; + } else + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_NORMAL; + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } +} + +static void +kbc_poll_at(atkbd_t *dev) +{ + switch (dev->kbc_state) { + case KBC_STATE_RESET: + if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + break; + case KBC_STATE_NORMAL: + if (dev->status & STAT_OFULL) { + /* OBF set, wait until it is cleared but still process commands. */ + if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD)) { + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else + kbc_scan_kbd_at(dev); + break; + case KBC_STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ + if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->kbc_state = KBC_STATE_NORMAL; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; + if (key_ctrl_queue_start == key_ctrl_queue_end) + dev->kbc_state = KBC_STATE_NORMAL; + } + break; + case KBC_STATE_KBC_PARAM: + /* Keyboard controller command wants data, wait for said data. */ + if (dev->status & STAT_IFULL) { + /* Command written, abort current command. */ + if (dev->status & STAT_CD) + dev->kbc_state = KBC_STATE_NORMAL; + + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + break; + case KBC_STATE_SCAN_KBD: + kbc_scan_kbd_at(dev); + break; + } +} + /* TODO: State machines for controller, keyboard, and mouse. */ static void kbd_poll(void *priv) @@ -815,14 +931,19 @@ kbd_poll(void *priv) mouse_enabled = !(dev->mem[0x20] & 0x20) && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF); - switch (dev->kbc_state) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) + kbc_poll_at(dev); + else switch (dev->kbc_state) { /* Reset state. */ case KBC_STATE_RESET: - if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) + if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->status &= ~STAT_IFULL; kbc_process_cmd(dev); + } break; /* Process commands and/or monitor the attached devices. */ case KBC_STATE_NORMAL: + case KBC_STATE_KBC_PARAM: /* Always process IBF, even if OBF is set. */ if (dev->status & STAT_IFULL) { dev->status &= ~STAT_IFULL; @@ -1408,6 +1529,7 @@ write64_generic(void *priv, uint8_t val) if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: write mouse output buffer\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; } break; @@ -1417,6 +1539,7 @@ write64_generic(void *priv, uint8_t val) set_enable_mouse(dev, 1); kbc_queue_reset(3); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xf0 ... 0xff: @@ -1453,6 +1576,7 @@ write60_ami(void *priv, uint8_t val) if (dev->secr_phase == 1) { dev->mem_addr = val; dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; dev->secr_phase = 2; } else if (dev->secr_phase == 2) { dev->mem[dev->mem_addr] = val; @@ -1489,11 +1613,13 @@ write64_ami(void *priv, uint8_t val) case 0x40 ... 0x5f: kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xa0: /* copyright message */ kbc_queue_add(dev, 0x28, 0); kbc_queue_add(dev, 0x00, 0); + dev->kbc_state = KBC_STATE_KBC_OUT; break; case 0xa1: /* get controller version */ @@ -1548,6 +1674,7 @@ write64_ami(void *priv, uint8_t val) } else { kbd_log("ATkbc: get extended controller RAM\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; } return 0; @@ -1590,6 +1717,7 @@ write64_ami(void *priv, uint8_t val) } else { kbd_log("ATkbc: set extended controller RAM\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; dev->secr_phase = 1; } return 0; @@ -1630,6 +1758,7 @@ write64_ami(void *priv, uint8_t val) case 0xc1: /* write input port */ kbd_log("ATkbc: AMI MegaKey - write input port\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xc4: @@ -1764,6 +1893,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; } @@ -1828,6 +1958,7 @@ write64_toshiba(void *priv, uint8_t val) case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ @@ -2072,6 +2203,10 @@ kbc_process_cmd(void *priv) if (dev->status & STAT_CD) { /* Controller command. */ dev->want60 = 0; + dev->kbc_state = KBC_STATE_NORMAL; + + /* Clear the keyboard controller queue. */ + kbc_queue_reset(0); switch (dev->ib) { /* Read data from KBC memory. */ @@ -2082,6 +2217,7 @@ kbc_process_cmd(void *priv) /* Write data to KBC memory. */ case 0x60 ... 0x7f: dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xaa: /* self-test */ @@ -2167,6 +2303,7 @@ kbc_process_cmd(void *priv) kbc_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] & 0x0f], 0); kbc_queue_add(dev, 0x39, 0); } + dev->kbc_state = KBC_STATE_KBC_OUT; } break; @@ -2183,6 +2320,7 @@ kbc_process_cmd(void *priv) case 0xc7: /* set port1 bits */ kbd_log("ATkbc: Phoenix - set port1 bits\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xca: /* read keyboard mode */ @@ -2193,6 +2331,7 @@ kbc_process_cmd(void *priv) case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xd0: /* read output port */ @@ -2206,11 +2345,13 @@ kbc_process_cmd(void *priv) case 0xd1: /* write output port */ kbd_log("ATkbc: write output port\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xd2: /* write keyboard output buffer */ kbd_log("ATkbc: write keyboard output buffer\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xdd: /* disable A20 address line */ @@ -2244,6 +2385,7 @@ kbc_process_cmd(void *priv) } else if (dev->want60) { /* Write data to controller. */ dev->want60 = 0; + dev->kbc_state = KBC_STATE_NORMAL; switch (dev->command) { case 0x60 ... 0x7f: @@ -2339,6 +2481,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } write_output(dev, val | 0x01); dev->want60 = 0; + dev->kbc_state = KBC_STATE_NORMAL; return; } break; @@ -2348,6 +2491,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) if (val == 0xd1) { kbd_log("ATkbc: write output port\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; dev->command = 0xd1; return; } From 289962319ff3d030f3e2186936dca8d129729e20 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 00:40:57 +0200 Subject: [PATCH 4/8] Rewritten the PS/2 poll (without the password security state, that is yet to be done) and enabled the PS/2 KBC IRQ latch on all PCI machines as well (it is present at the very least on Intel SIO and PIIX), fixes Windows for Workgroups 3.11 input, and reduced mouse polling to 255 Hz (the maximums supported by PS/2 mice). --- src/device/keyboard_at.c | 157 +++++++++++++++++++++++++-------------- src/device/mouse.c | 8 +- src/include/86box/pic.h | 1 + src/pic.c | 6 ++ 4 files changed, 113 insertions(+), 59 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 4179f5fd3..31bd91c53 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -920,78 +920,125 @@ kbc_poll_at(atkbd_t *dev) } } -/* TODO: State machines for controller, keyboard, and mouse. */ -static void -kbd_poll(void *priv) +static int +kbc_scan_kbd_ps2(atkbd_t *dev) { - atkbd_t *dev = (atkbd_t *) priv; - int mouse_enabled; + if (dev->out_new != -1) { + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_NORMAL; + return 1; + } - timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); + return 0; +} - mouse_enabled = !(dev->mem[0x20] & 0x20) && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF); +static int +kbc_scan_aux_ps2(atkbd_t *dev) +{ + if (dev->out_new_mouse != -1) { + add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); + dev->out_new_mouse = -1; + dev->kbc_state = KBC_STATE_NORMAL; + return 1; + } - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) - kbc_poll_at(dev); - else switch (dev->kbc_state) { - /* Reset state. */ + return 0; +} + +static void +kbc_poll_ps2(atkbd_t *dev) +{ + switch (dev->kbc_state) { case KBC_STATE_RESET: if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { dev->status &= ~STAT_IFULL; kbc_process_cmd(dev); } break; - /* Process commands and/or monitor the attached devices. */ case KBC_STATE_NORMAL: - case KBC_STATE_KBC_PARAM: - /* Always process IBF, even if OBF is set. */ + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else if (!(dev->status & STAT_OFULL)) { + if (dev->mem[0x20] & 0x20) { + if (!(dev->mem[0x20] & 0x10)) { + dev->output_port &= 0xbf; + + if (kbc_scan_kbd_ps2(dev) == 0) { + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } + } else { + dev->output_port &= 0xf7; + if (dev->mem[0x20] & 0x10) { + if (kbc_scan_aux_ps2(dev) == 0) { + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } else { + dev->output_port &= 0xbf; + + if (kbc_scan_kbd_ps2(dev) == 0) { + if (kbc_scan_aux_ps2(dev) == 0) { + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } + } + } + } + break; + case KBC_STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->kbc_state = KBC_STATE_NORMAL; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; + if (key_ctrl_queue_start == key_ctrl_queue_end) + dev->kbc_state = KBC_STATE_NORMAL; + } + break; + case KBC_STATE_KBC_PARAM: + /* Keyboard controller command wants data, wait for said data. */ + if (dev->status & STAT_IFULL) { + /* Command written, abort current command. */ + if (dev->status & STAT_CD) + dev->kbc_state = KBC_STATE_NORMAL; + dev->status &= ~STAT_IFULL; - if ((dev->status & STAT_CD) || dev->want60) - kbc_process_cmd(dev); - else if (!(dev->status & STAT_CD) && !dev->want60) { - dev->status &= ~STAT_IFULL; - set_enable_kbd(dev, 1); - kbc_queue_reset(4); - dev->key_wantcmd = 1; - dev->key_dat = dev->ib; - dev->kbc_state = KBC_STATE_KBD; - } - } else if (!(dev->status & STAT_OFULL)) { - if (key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); - add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; - } else if (mouse_enabled && (dev->out_new_mouse != -1)) { - kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); - add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); - dev->out_new_mouse = -1; - } else if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { - kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); - add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); - dev->out_new = -1; - } + kbc_process_cmd(dev); } break; - /* Wait for keyboard command response. */ - case KBC_STATE_KBD: - if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { - kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); - add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); - dev->out_new = -1; - dev->kbc_state = KBC_STATE_NORMAL; - } + case KBC_STATE_SCAN_KBD: + (void) kbc_scan_kbd_ps2(dev); break; - /* Wait for keyboard mouse response. */ - case KBC_STATE_MOUSE: - if (mouse_enabled && (dev->out_new_mouse != -1)) { - kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); - add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); - dev->out_new_mouse = -1; - dev->kbc_state = KBC_STATE_NORMAL; - } + case KBC_STATE_SCAN_MOUSE: + (void) kbc_scan_aux_ps2(dev); break; } +} + +/* TODO: State machines for controller, keyboard, and mouse. */ +static void +kbd_poll(void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + + timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); + + /* 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 + kbc_poll_ps2(dev); if (dev->reset_delay) { dev->reset_delay--; @@ -2520,7 +2567,7 @@ kbd_read(uint16_t port, void *priv) This also means that in AT mode, the IRQ is level-triggered. */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) picintc(1 << 1); - else if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { + else if (pic_get_pci_flag() || ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF)) { /* PS/2 MCA: Latched as level-sensitive until port 0x60 is read (and with it, OBF is cleared), in accordance with the IBM PS/2 Model 80 Technical Reference Manual. */ kbc_irq(dev, dev->irq_levels, 0); diff --git a/src/device/mouse.c b/src/device/mouse.c index 46bbc4ac2..13d9999c7 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -152,8 +152,8 @@ mouse_close(void) static void mouse_timer_poll(void *priv) { - /* Poll at 3600 Hz. */ - timer_on_auto(&mouse_timer, 277.0 + (7.0 / 9.0)); + /* Poll at 255 Hz, maximum supported by PS/2 mic. */ + timer_on_auto(&mouse_timer, 1000000.0 / 255.0); #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ if (gdbstub_step == GDBSTUB_EXEC) @@ -186,8 +186,8 @@ mouse_reset(void) timer_add(&mouse_timer, mouse_timer_poll, NULL, 0); - /* Poll at 3600 Hz. */ - timer_on_auto(&mouse_timer, 277.0 + (7.0 / 9.0)); + /* Poll at 255 Hz, maximum supported by PS/2 mic. */ + timer_on_auto(&mouse_timer, 1000000.0 / 255.0); } /* Callback from the hardware driver. */ diff --git a/src/include/86box/pic.h b/src/include/86box/pic.h index 318ce2fad..52bc920e4 100644 --- a/src/include/86box/pic.h +++ b/src/include/86box/pic.h @@ -43,6 +43,7 @@ extern void pic_elcr_write(uint16_t port, uint8_t val, void *priv); extern uint8_t pic_elcr_read(uint16_t port, void *priv); extern void pic_set_shadow(int sh); +extern int pic_get_pci_flag(void); extern void pic_set_pci_flag(int pci); extern void pic_set_pci(void); extern void pic_init(void); diff --git a/src/pic.c b/src/pic.c index bdff7f59c..9920a23e9 100644 --- a/src/pic.c +++ b/src/pic.c @@ -284,6 +284,12 @@ pic_set_shadow(int sh) shadow = sh; } +int +pic_get_pci_flag(void) +{ + return pic_pci; +} + void pic_set_pci_flag(int pci) { From c786eb0924da4fda5f755f300dfe17c743826bc0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 01:42:09 +0200 Subject: [PATCH 5/8] Fixed input port intialization, fixes the logo on the Epson Action PC. --- src/device/keyboard_at.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 31bd91c53..0d433188e 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2287,7 +2287,9 @@ kbc_process_cmd(void *priv) } else { if (dev->kbc_state != KBC_STATE_RESET) { kbd_log("ATkbc: self-test reinitialization\n"); - dev->input_port |= 0xff; + /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */ + /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ + dev->input_port = dev->input_port & 0xff; write_output(dev, 0xcf); } @@ -2309,27 +2311,6 @@ kbc_process_cmd(void *priv) dev->kbc_state = KBC_STATE_NORMAL; add_to_kbc_queue_front(dev, 0x55, 0, 0x00); - -#if 0 - write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->out_new = dev->out_new_mouse = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - keyboard_scan = 0; - mouse_scan = 0; - kbd_last_scan_code = 0x00; - dev->status &= ~STAT_OFULL; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - add_to_kbc_queue_front(dev, 0x55, 0, 0x00); -#endif break; case 0xab: /* interface test */ From cdf413c985b165c8e3446255406f8727321ced37 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 02:09:47 +0200 Subject: [PATCH 6/8] Gave the Epson Action PC 2600 a PS/2 mouse port, per the manual. --- src/machine/m_at_386dx_486.c | 2 +- src/machine/machine_table.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 0ee7b51a2..8b743af2f 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1657,7 +1657,7 @@ machine_at_actionpc2600_init(const machine_t *model) device_add(&umc_8886af_device); device_add(&um8669f_device); device_add(&intel_flash_bxt_device); - device_add(&keyboard_at_ami_device); + device_add(&keyboard_ps2_ami_device); return ret; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9047342e8..3a11769f8 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -7036,7 +7036,7 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_PCI, + .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { .min = 1024, From c0be988ec4f3fbbb2f33a5aab971d1a25537909e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 02:44:12 +0200 Subject: [PATCH 7/8] Added the TriGem AMI keyboard controllers. --- src/machine/m_at_386dx_486.c | 8 ++++---- src/machine/m_at_socket5.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 8b743af2f..ee54758e2 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -220,7 +220,7 @@ machine_at_spc6000a_init(const machine_t *model) if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); - device_add(&keyboard_at_samsung_device); + device_add(&keyboard_at_ami_device); return ret; } @@ -1657,7 +1657,7 @@ machine_at_actionpc2600_init(const machine_t *model) device_add(&umc_8886af_device); device_add(&um8669f_device); device_add(&intel_flash_bxt_device); - device_add(&keyboard_ps2_ami_device); + device_add(&keyboard_ps2_tg_ami_device); return ret; } @@ -1782,7 +1782,7 @@ machine_at_tg486gp_init(const machine_t *model) device_add(&ali1435_device); device_add(&sst_flash_29ee010_device); - device_add(&keyboard_ps2_ami_device); + device_add(&keyboard_ps2_tg_ami_device); return ret; } @@ -1806,7 +1806,7 @@ machine_at_tg486g_init(const machine_t *model) device_add(&sis_85c471_device); device_add(&ide_isa_device); device_add(&fdc37c651_ide_device); - device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&keyboard_ps2_tg_ami_pci_device); return ret; } diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 842554713..9a45e71bf 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -237,7 +237,7 @@ machine_at_hawk_init(const machine_t *model) pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_tg_ami_pci_device); device_add(&i430fx_device); device_add(&piix_device); device_add(&fdc37c665_device); From d4b57298ad8d6503d7c679d7e0fc8a4e849d7bf8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 03:11:53 +0200 Subject: [PATCH 8/8] Fixed the keyboard controller reset state, fixes Xi8088. --- src/device/keyboard_at.c | 119 ++++++++++++++++++++++++----------- src/include/86box/keyboard.h | 5 +- 2 files changed, 88 insertions(+), 36 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 0d433188e..e440b3b07 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -37,7 +37,6 @@ #include <86box/mem.h> #include <86box/device.h> #include <86box/machine.h> -#include <86box/m_xt_xi8088.h> #include <86box/m_at_t3100e.h> #include <86box/fdd.h> #include <86box/fdc.h> @@ -81,15 +80,15 @@ #define KBC_VEN_IBM_MCA 0x08 #define KBC_VEN_QUADTEL 0x0c #define KBC_VEN_TOSHIBA 0x10 -#define KBC_VEN_XI8088 0x14 -#define KBC_VEN_IBM_PS1 0x18 -#define KBC_VEN_ACER 0x1c -#define KBC_VEN_INTEL_AMI 0x20 -#define KBC_VEN_OLIVETTI 0x24 -#define KBC_VEN_NCR 0x28 -#define KBC_VEN_SAMSUNG 0x2c -#define KBC_VEN_ALI 0x30 -#define KBC_VEN_PHOENIX 0x3c +#define KBC_VEN_IBM_PS1 0x14 +#define KBC_VEN_ACER 0x18 +#define KBC_VEN_INTEL_AMI 0x1c +#define KBC_VEN_OLIVETTI 0x20 +#define KBC_VEN_NCR 0x24 +#define KBC_VEN_PHOENIX 0x28 +#define KBC_VEN_ALI 0x2c +#define KBC_VEN_TG 0x30 +#define KBC_VEN_TG_GREEN 0x34 #define KBC_VEN_MASK 0x3c enum { @@ -109,9 +108,9 @@ typedef struct { output_port, old_output_port, key_command, output_locked, ami_stat, want60, key_wantdata, ami_flags, key_wantcmd, key_dat, mouse_wantcmd, mouse_dat, - kbc_state, kbd_state, mouse_state, pad; + kbc_state, kbd_state, mouse_state, pci; - uint16_t irq_levels, pad0; + uint16_t irq_levels, pad; uint8_t mem[0x100]; @@ -713,7 +712,8 @@ add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_ { uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + 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)) stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); else stat_hi |= 0x10; @@ -870,9 +870,10 @@ kbc_poll_at(atkbd_t *dev) { switch (dev->kbc_state) { case KBC_STATE_RESET: - if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { - dev->status &= ~STAT_IFULL; - kbc_process_cmd(dev); + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_process_cmd(dev); } break; case KBC_STATE_NORMAL: @@ -951,9 +952,10 @@ kbc_poll_ps2(atkbd_t *dev) { switch (dev->kbc_state) { case KBC_STATE_RESET: - if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { - dev->status &= ~STAT_IFULL; - kbc_process_cmd(dev); + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_process_cmd(dev); } break; case KBC_STATE_NORMAL: @@ -1451,13 +1453,15 @@ write_cmd(atkbd_t *dev, uint8_t val) /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { + 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)) { keyboard_mode &= ~CCB_PCMODE; kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); } - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { + 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)) { /* 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)); } @@ -1559,7 +1563,16 @@ write64_generic(void *priv, uint8_t val) 0, 0x00); dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc); } else { - if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) { + /* Bit 3, 2: + 1, 1: TriGem logo; + 1, 0: Garbled logo; + 0, 1: Epson logo; + 0, 0: Generic AMI logo. */ + if (dev->pci) + fixed_bits |= 8; + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); + } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) #if 0 add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); @@ -1671,18 +1684,25 @@ write64_ami(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) + add_to_kbc_queue_front(dev, 'Z', 0, 0x00); + else if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { if (kbc_ven == KBC_VEN_ALI) add_to_kbc_queue_front(dev, 'F', 0, 0x00); else if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI) add_to_kbc_queue_front(dev, '5', 0, 0x00); - else if (is_pentium) + else if (cpu_64bitbus) add_to_kbc_queue_front(dev, 'R', 0, 0x00); + else if (is486) + add_to_kbc_queue_front(dev, 'P', 0, 0x00); else add_to_kbc_queue_front(dev, 'H', 0, 0x00); - } else if (is386 && !is486) - add_to_kbc_queue_front(dev, 'B', 0, 0x00); - else if (!is386) + } else if (is386 && !is486) { + if (cpu_16bitbus) + add_to_kbc_queue_front(dev, 'D', 0, 0x00); + else + add_to_kbc_queue_front(dev, 'B', 0, 0x00); + } else if (!is386) add_to_kbc_queue_front(dev, '8', 0, 0x00); else add_to_kbc_queue_front(dev, 'F', 0, 0x00); @@ -2583,7 +2603,7 @@ kbd_reset(void *priv) dev->key_wantdata = 0; /* Set up the correct Video Type bits. */ - if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) + if (!is286 || (kbc_ven == KBC_VEN_ACER)) dev->input_port = video_is_mda() ? 0xb0 : 0xf0; else dev->input_port = video_is_mda() ? 0xf0 : 0xb0; @@ -2664,6 +2684,7 @@ kbd_init(const device_t *info) memset(dev, 0x00, sizeof(atkbd_t)); dev->flags = info->local; + dev->pci = !!(info->flags & DEVICE_PCI); video_reset(gfxcard[0]); kbd_reset(dev); @@ -2683,7 +2704,6 @@ kbd_init(const device_t *info) case KBC_VEN_GENERIC: case KBC_VEN_NCR: case KBC_VEN_IBM_PS1: - case KBC_VEN_XI8088: dev->write64_ven = write64_generic; break; @@ -2693,8 +2713,9 @@ kbd_init(const device_t *info) case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: - case KBC_VEN_SAMSUNG: case KBC_VEN_ALI: + case KBC_VEN_TG: + case KBC_VEN_TG_GREEN: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -2748,11 +2769,11 @@ const device_t keyboard_at_ami_device = { .config = NULL }; -const device_t keyboard_at_samsung_device = { - .name = "PC/AT Keyboard (Samsung)", - .internal_name = "keyboard_at_samsung", +const device_t keyboard_at_tg_ami_device = { + .name = "PC/AT Keyboard (TriGem AMI)", + .internal_name = "keyboard_at_tg_ami", .flags = 0, - .local = KBC_TYPE_ISA | KBC_VEN_SAMSUNG, + .local = KBC_TYPE_ISA | KBC_VEN_TG, .init = kbd_init, .close = kbd_close, .reset = kbd_reset, @@ -2850,7 +2871,7 @@ const device_t keyboard_ps2_xi8088_device = { .name = "PS/2 Keyboard (Xi8088)", .internal_name = "keyboard_ps2_xi8088", .flags = 0, - .local = KBC_TYPE_PS2_1 | KBC_VEN_XI8088, + .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, .init = kbd_init, .close = kbd_close, .reset = kbd_reset, @@ -2874,6 +2895,20 @@ const device_t keyboard_ps2_ami_device = { .config = NULL }; +const device_t keyboard_ps2_tg_ami_device = { + .name = "PS/2 Keyboard (TriGem AMI)", + .internal_name = "keyboard_ps2_tg_ami", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_ps2_mca_device = { .name = "PS/2 Keyboard", .internal_name = "keyboard_ps2_mca", @@ -2972,6 +3007,20 @@ const device_t keyboard_ps2_intel_ami_pci_device = { .config = NULL }; +const device_t keyboard_ps2_tg_ami_pci_device = { + .name = "PS/2 Keyboard (TriGem AMI)", + .internal_name = "keyboard_ps2_tg_ami_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_ps2_acer_pci_device = { .name = "PS/2 Keyboard (Acer 90M002A)", .internal_name = "keyboard_ps2_acer_pci", diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 2ff0325cb..767ffdca7 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -159,7 +159,7 @@ extern const device_t keyboard_xt_zenith_device; extern const device_t keyboard_xtclone_device; extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; -extern const device_t keyboard_at_samsung_device; +extern const device_t keyboard_at_tg_ami_device; extern const device_t keyboard_at_toshiba_device; extern const device_t keyboard_at_olivetti_device; extern const device_t keyboard_at_ncr_device; @@ -168,6 +168,8 @@ extern const device_t keyboard_ps2_ps1_device; extern const device_t keyboard_ps2_ps1_pci_device; extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; +extern const device_t keyboard_ps2_tg_ami_device; +extern const device_t keyboard_ps2_tg_ami_green_device; extern const device_t keyboard_ps2_olivetti_device; extern const device_t keyboard_ps2_mca_device; extern const device_t keyboard_ps2_mca_2_device; @@ -177,6 +179,7 @@ extern const device_t keyboard_ps2_ami_pci_device; extern const device_t keyboard_ps2_intel_ami_pci_device; extern const device_t keyboard_ps2_acer_pci_device; extern const device_t keyboard_ps2_ali_pci_device; +extern const device_t keyboard_ps2_tg_ami_pci_device; #endif /*EMU_DEVICE_H*/ extern void keyboard_init(void);