PS/2 KBC: Added a 2-cycle wait before clearing the IRQ's, fixes keyboard during NTLDR.
This commit is contained in:
@@ -99,7 +99,7 @@
|
||||
enum {
|
||||
STATE_RESET = 0, /* KBC reset state, only accepts command AA. */
|
||||
STATE_KBC_DELAY_OUT, /* KBC is sending one single byte. */
|
||||
STATE_KBC_AMI_OUT, /* KBC waiting for OBF - needed for AMIKey commands that require clearing of the output byte. */
|
||||
STATE_IRQC_MAIN_IBF, /* KBC checking if the input buffer is full, clear IRQ's first. */
|
||||
STATE_MAIN_IBF, /* KBC checking if the input buffer is full. */
|
||||
STATE_MAIN_KBD, /* KBC checking if the keyboard has anything to send. */
|
||||
STATE_MAIN_AUX, /* KBC checking if the auxiliary has anything to send. */
|
||||
@@ -113,7 +113,8 @@ enum {
|
||||
STATE_IRQ, /* KBC is raising the IRQ. */
|
||||
STATE_KBC_IRQ,
|
||||
STATE_AUX_IRQ,
|
||||
STATE_KBC_DELAY_IRQ
|
||||
STATE_KBC_DELAY_IRQ,
|
||||
STATE_IRQC_WAIT,
|
||||
};
|
||||
|
||||
typedef struct atkbc_t {
|
||||
@@ -371,25 +372,29 @@ kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi)
|
||||
kbc_at_log("ATkbc: Sending %02X to the output buffer on channel %i...\n", temp, channel);
|
||||
dev->status = (dev->status & ~0xf0) | STAT_OFULL | stat_hi;
|
||||
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
|
||||
/* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly
|
||||
written to pulse its P2 IRQ bits, so they should be kept as as edge-triggered here. */
|
||||
if (dev->misc_flags & FLAG_PS2) {
|
||||
if (channel >= 2) {
|
||||
dev->status |= STAT_MFULL;
|
||||
if ((kbc_ven == KBC_VEN_IBM_PS1) || (kbc_ven == KBC_VEN_IBM)) {
|
||||
if (dev->mem[0x20] & 0x02)
|
||||
if (dev->mem[0x20] & 0x02) {
|
||||
picint_common(1 << 12, 0, 1, NULL);
|
||||
picint_common(1 << 1, 0, 0, NULL);
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
} else
|
||||
dev->state = STATE_IRQC_WAIT;
|
||||
}
|
||||
// picint_common(1 << 1, 0, 0, NULL);
|
||||
} else if (dev->mem[0x20] & 0x02)
|
||||
dev->state = STATE_AUX_IRQ;
|
||||
} else if (channel == 1) {
|
||||
if ((kbc_ven == KBC_VEN_IBM_PS1) || (kbc_ven == KBC_VEN_IBM)) {
|
||||
if (dev->mem[0x20] & 0x01)
|
||||
if (dev->mem[0x20] & 0x01) {
|
||||
picint_common(1 << 1, 0, 1, NULL);
|
||||
picint_common(1 << 12, 0, 0, NULL);
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
} else
|
||||
dev->state = STATE_IRQC_WAIT;
|
||||
}
|
||||
// picint_common(1 << 12, 0, 0, NULL);
|
||||
} else if (dev->mem[0x20] & 0x01)
|
||||
dev->state = STATE_IRQ;
|
||||
}
|
||||
} else if (dev->mem[0x20] & 0x01)
|
||||
@@ -499,10 +504,6 @@ kbc_at_poll_at(atkbc_t *dev)
|
||||
kbc_at_process_cmd(dev);
|
||||
}
|
||||
break;
|
||||
case STATE_KBC_AMI_OUT:
|
||||
if (dev->status & STAT_OFULL)
|
||||
break;
|
||||
fallthrough;
|
||||
case STATE_MAIN_IBF:
|
||||
default:
|
||||
at_main_ibf:
|
||||
@@ -530,9 +531,6 @@ at_main_ibf:
|
||||
/* Keyboard controller command want to output a single byte. */
|
||||
kbc_at_log("ATkbc: %02X coming from channel %i with high status %02X\n", dev->val, dev->channel, dev->stat_hi);
|
||||
kbc_send_to_ob(dev, dev->val, dev->channel, dev->stat_hi);
|
||||
#if 0
|
||||
dev->state = (dev->pending == 2) ? STATE_KBC_AMI_OUT : STATE_MAIN_IBF;
|
||||
#endif
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
dev->pending = 0;
|
||||
goto at_main_ibf;
|
||||
@@ -611,6 +609,8 @@ kbc_scan_aux_ps2(atkbc_t *dev)
|
||||
static void
|
||||
kbc_at_poll_ps2(atkbc_t *dev)
|
||||
{
|
||||
static uint8_t phase = 0;
|
||||
|
||||
switch (dev->state) {
|
||||
case STATE_RESET:
|
||||
if (dev->status & STAT_IFULL) {
|
||||
@@ -619,14 +619,19 @@ kbc_at_poll_ps2(atkbc_t *dev)
|
||||
kbc_at_process_cmd(dev);
|
||||
}
|
||||
break;
|
||||
case STATE_KBC_AMI_OUT:
|
||||
if (dev->status & STAT_OFULL)
|
||||
break;
|
||||
case STATE_IRQC_WAIT:
|
||||
kbc_at_log("ATkbc: IRQ clear wait...\n");
|
||||
phase = (phase + 1) & 1;
|
||||
if (phase)
|
||||
dev->state = STATE_IRQC_MAIN_IBF;
|
||||
break;
|
||||
case STATE_IRQC_MAIN_IBF:
|
||||
kbc_at_log("ATkbc: Clearing IRQ 1 and 12 (Main/IBF)...\n");
|
||||
picint_common(1 << 1, 0, 0, NULL);
|
||||
picint_common(1 << 12, 0, 0, NULL);
|
||||
fallthrough;
|
||||
case STATE_MAIN_IBF:
|
||||
default:
|
||||
picint_common(1 << 1, 0, 0, NULL);
|
||||
picint_common(1 << 12, 0, 0, NULL);
|
||||
ps2_main_ibf:
|
||||
if (dev->status & STAT_IFULL)
|
||||
kbc_ibf_process(dev);
|
||||
@@ -671,34 +676,41 @@ ps2_main_ibf:
|
||||
/* Keyboard controller command want to output a single byte. */
|
||||
kbc_at_log("ATkbc: %02X coming from channel %i with high status %02X\n", dev->val, dev->channel, dev->stat_hi);
|
||||
kbc_send_to_ob(dev, dev->val, dev->channel, dev->stat_hi);
|
||||
#if 0
|
||||
dev->state = (dev->pending == 2) ? STATE_KBC_AMI_OUT : STATE_MAIN_IBF;
|
||||
#endif
|
||||
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)
|
||||
if (dev->mem[0x20] & 0x01) {
|
||||
kbc_at_log("ATkbc: Raising IRQ 1 (keyboard)...\n");
|
||||
picint_common(1 << 1, 0, 1, NULL);
|
||||
picint_common(1 << 12, 0, 0, NULL);
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
dev->state = STATE_IRQC_WAIT;
|
||||
} else {
|
||||
kbc_at_log("ATkbc: Noping IRQ 1 (keyboard)...\n");
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
}
|
||||
break;
|
||||
case STATE_AUX_IRQ:
|
||||
kbc_at_log("ATkbc: Raising IRQ 12 (mouse)...\n");
|
||||
if (dev->mem[0x20] & 0x02)
|
||||
if (dev->mem[0x20] & 0x02) {
|
||||
picint_common(1 << 12, 0, 1, NULL);
|
||||
picint_common(1 << 1, 0, 0, NULL);
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
dev->state = STATE_IRQC_WAIT;
|
||||
} else
|
||||
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)
|
||||
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;
|
||||
dev->state = STATE_IRQC_WAIT;
|
||||
break;
|
||||
} else {
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
goto ps2_main_ibf;
|
||||
}
|
||||
case STATE_KBC_OUT:
|
||||
kbc_at_log("ATkbc: Clearing IRQ 1 and 12 (KBC out)...\n");
|
||||
picint_common(1 << 1, 0, 0, NULL);
|
||||
picint_common(1 << 12, 0, 0, NULL);
|
||||
/* Keyboard controller command want to output multiple bytes. */
|
||||
if (dev->status & STAT_IFULL) {
|
||||
/* Data from host aborts dumping. */
|
||||
@@ -716,10 +728,11 @@ ps2_main_ibf:
|
||||
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;
|
||||
dev->state = STATE_IRQC_WAIT;
|
||||
else
|
||||
dev->state = STATE_KBC_OUT;
|
||||
break;
|
||||
case STATE_KBC_PARAM:
|
||||
/* Keyboard controller command wants data, wait for said data. */
|
||||
|
Reference in New Issue
Block a user