Rewritten the AT KBC polling, PS/2 is coming soon.

This commit is contained in:
OBattler
2023-04-07 23:36:02 +02:00
parent 1c17e687e3
commit 1c8fd2c7fc

View File

@@ -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;
}