The PS/2 keyboard controllers now simulate the real hardware behavior of there being a slight delay between OBF and IRQ, fixes, amnong other things, PB640 Windows 95 mouse (and PB450 CMOS Setup now works without the workaround).

This commit is contained in:
OBattler
2024-05-10 00:31:58 +02:00
parent b22b2af411
commit b67c234569

View File

@@ -108,7 +108,11 @@ enum {
STATE_SEND_KBD, /* KBC is sending command to the keyboard. */
STATE_SCAN_KBD, /* KBC is waiting for the keyboard command response. */
STATE_SEND_AUX, /* KBC is sending command to the auxiliary device. */
STATE_SCAN_AUX /* KBC is waiting for the auxiliary command response. */
STATE_SCAN_AUX, /* KBC is waiting for the auxiliary command response. */
STATE_IRQ, /* KBC is raising the IRQ. */
STATE_KBC_IRQ,
STATE_AUX_IRQ,
STATE_KBC_DELAY_IRQ
};
typedef struct atkbc_t {
@@ -133,9 +137,9 @@ typedef struct atkbc_t {
uint8_t stat_hi;
uint8_t pending;
uint8_t irq_state;
uint8_t suppress_cmd_intr;
uint8_t pad;
uint8_t pad0;
uint8_t pad1;
uint8_t mem[0x100];
@@ -352,8 +356,10 @@ kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi)
uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
int temp = (channel == 1) ? kbc_translate(dev, val) : ((int) val);
if (temp == -1)
if (temp == -1) {
dev->state = STATE_MAIN_IBF;
return;
}
if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TRIGEM_AMI) ||
(dev->misc_flags & FLAG_PS2))
@@ -369,15 +375,9 @@ kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi)
if (dev->misc_flags & FLAG_PS2) {
if (channel >= 2) {
dev->status |= STAT_MFULL;
if (dev->mem[0x20] & 0x02)
picint_common(1 << 12, 0, 1, NULL);
picint_common(1 << 1, 0, 0, NULL);
} else {
if ((!dev->suppress_cmd_intr || (dev->channel == 1)) && (dev->mem[0x20] & 0x01))
picint_common(1 << 1, 0, 1, NULL);
picint_common(1 << 12, 0, 0, NULL);
}
dev->state = STATE_AUX_IRQ;
} else if (channel == 1)
dev->state = STATE_IRQ;
} else if (dev->mem[0x20] & 0x01)
picintlevel(1 << 1, &dev->irq_state); /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */
@@ -575,7 +575,6 @@ kbc_scan_kbd_ps2(atkbc_t *dev)
kbc_at_log("ATkbc: %02X coming from channel 1\n", dev->ports[0]->out_new & 0xff);
kbc_send_to_ob(dev, dev->ports[0]->out_new, 1, 0x00);
dev->ports[0]->out_new = -1;
dev->state = STATE_MAIN_IBF;
return 1;
}
@@ -589,7 +588,6 @@ kbc_scan_aux_ps2(atkbc_t *dev)
kbc_at_log("ATkbc: %02X coming from channel 2\n", dev->ports[1]->out_new & 0xff);
kbc_send_to_ob(dev, dev->ports[1]->out_new, 2, 0x00);
dev->ports[1]->out_new = -1;
dev->state = STATE_MAIN_IBF;
return 1;
}
@@ -637,22 +635,20 @@ ps2_main_ibf:
if (dev->status & STAT_IFULL)
kbc_ibf_process(dev);
else {
(void) kbc_scan_kbd_ps2(dev);
dev->state = STATE_MAIN_IBF;
if (!kbc_scan_kbd_ps2(dev))
dev->state = STATE_MAIN_IBF;
}
break;
case STATE_MAIN_AUX:
if (dev->status & STAT_IFULL)
kbc_ibf_process(dev);
else {
(void) kbc_scan_aux_ps2(dev);
dev->state = STATE_MAIN_IBF;
if (!kbc_scan_aux_ps2(dev))
dev->state = STATE_MAIN_IBF;
}
break;
case STATE_MAIN_BOTH:
if (kbc_scan_kbd_ps2(dev))
dev->state = STATE_MAIN_IBF;
else
if (!kbc_scan_kbd_ps2(dev))
dev->state = STATE_MAIN_AUX;
break;
case STATE_KBC_DELAY_OUT:
@@ -662,8 +658,29 @@ ps2_main_ibf:
#if 0
dev->state = (dev->pending == 2) ? STATE_KBC_AMI_OUT : STATE_MAIN_IBF;
#endif
dev->state = STATE_MAIN_IBF;
dev->pending = 0;
dev->state = STATE_KBC_DELAY_IRQ;
break;
case STATE_IRQ:
kbc_at_log("ATkbc: Raising IRQ 1 (keyboard)...\n");
if (dev->mem[0x20] & 0x01)
picint_common(1 << 1, 0, 1, NULL);
picint_common(1 << 12, 0, 0, NULL);
dev->state = STATE_MAIN_IBF;
break;
case STATE_AUX_IRQ:
kbc_at_log("ATkbc: Raising IRQ 12 (mouse)...\n");
if (dev->mem[0x20] & 0x02)
picint_common(1 << 12, 0, 1, NULL);
picint_common(1 << 1, 0, 0, NULL);
dev->state = STATE_MAIN_IBF;
break;
case STATE_KBC_DELAY_IRQ:
kbc_at_log("ATkbc: Raising IRQ 1 (KBC delay)...\n");
if (dev->mem[0x20] & 0x01)
picint_common(1 << 1, 0, 1, NULL);
picint_common(1 << 12, 0, 0, NULL);
dev->state = STATE_MAIN_IBF;
goto ps2_main_ibf;
case STATE_KBC_OUT:
/* Keyboard controller command want to output multiple bytes. */
@@ -676,11 +693,18 @@ ps2_main_ibf:
if (!(dev->status & STAT_OFULL)) {
kbc_at_log("ATkbc: %02X coming from channel 0\n", dev->key_ctrl_queue[dev->key_ctrl_queue_start] & 0xff);
kbc_send_to_ob(dev, dev->key_ctrl_queue[dev->key_ctrl_queue_start], 0, 0x00);
dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f;
if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end)
dev->state = STATE_MAIN_IBF;
dev->state = STATE_KBC_IRQ;
}
break;
case STATE_KBC_IRQ:
kbc_at_log("ATkbc: Raising IRQ 1 (KBC)...\n");
if (dev->mem[0x20] & 0x01)
picint_common(1 << 1, 0, 1, NULL);
picint_common(1 << 12, 0, 0, NULL);
dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f;
if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end)
dev->state = STATE_MAIN_IBF;
break;
case STATE_KBC_PARAM:
/* Keyboard controller command wants data, wait for said data. */
if (dev->status & STAT_IFULL) {
@@ -1394,8 +1418,6 @@ write60_phoenix(void *priv, uint8_t val)
kbc_at_log("ATkbc: Phoenix - Set MultiKey Variable\n");
if ((dev->mem_addr > 0) && (dev->mem_addr <= multikey_vars[0x00]))
dev->mem[multikey_vars[dev->mem_addr]] = val;
else if (dev->mem_addr == 0x29)
dev->suppress_cmd_intr = !val;
dev->command_phase = 0;
return 0;
@@ -2006,7 +2028,7 @@ kbc_at_process_cmd(void *priv)
if (dev->ib == 0xbb)
break;
if (strstr(machine_get_internal_name(), "pb") != NULL)
if (strstr(machine_get_internal_name(), "pb41") != NULL)
cpu_override_dynarec = 1;
if (dev->misc_flags & FLAG_PS2) {
@@ -2103,11 +2125,8 @@ kbc_at_read(uint16_t port, void *priv)
if (!(dev->misc_flags & FLAG_PS2))
picintclevel(1 << 1, &dev->irq_state);
/* I"m not even sure if this is correct but the PB450 absolutely requires this. */
if (dev->suppress_cmd_intr) {
picint_common(1 << 1, 0, 1, NULL);
dev->suppress_cmd_intr = 0;
}
if ((strstr(machine_get_internal_name(), "pb") != NULL) && (cpu_override_dynarec == 1))
if ((strstr(machine_get_internal_name(), "pb41") != NULL) &&
(cpu_override_dynarec == 1))
cpu_override_dynarec = 0;
break;
@@ -2149,8 +2168,6 @@ kbc_at_reset(void *priv)
kbc_at_queue_reset(dev);
dev->suppress_cmd_intr = 0;
dev->sc_or = 0;
dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) ? 0x01 : 0x00;