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).
This commit is contained in:
@@ -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) {
|
||||
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;
|
||||
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 if (!(dev->status & STAT_OFULL)) {
|
||||
if (key_ctrl_queue_start != key_ctrl_queue_end) {
|
||||
}
|
||||
} 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;
|
||||
} 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;
|
||||
/* 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;
|
||||
if (key_ctrl_queue_start == key_ctrl_queue_end)
|
||||
dev->kbc_state = KBC_STATE_NORMAL;
|
||||
}
|
||||
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;
|
||||
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:
|
||||
(void) kbc_scan_kbd_ps2(dev);
|
||||
break;
|
||||
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);
|
||||
|
@@ -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. */
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user