diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2010-01-28 20:35:21 -0500 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2010-01-28 20:35:21 -0500 |
commit | 6f702dd6987b22e9bce472fe61910392af17416a (patch) | |
tree | 14004f76f72bb1a6983f2ee5ebea8a1a1c870f40 /src/ps2port.c | |
parent | 2d3f0f5e4040a5b2dabc278bc5aa5bc3d9e71e1b (diff) | |
download | seabios-hppa-6f702dd6987b22e9bce472fe61910392af17416a.zip seabios-hppa-6f702dd6987b22e9bce472fe61910392af17416a.tar.gz seabios-hppa-6f702dd6987b22e9bce472fe61910392af17416a.tar.bz2 |
Rework disabling of ps2 port irqs.
Disable the ps2 port irqs in software instead of hardware. This
prevents a race where an irq could get queued and later called when
not desired.
Diffstat (limited to 'src/ps2port.c')
-rw-r--r-- | src/ps2port.c | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/src/ps2port.c b/src/ps2port.c index fb9d24a..b52f994 100644 --- a/src/ps2port.c +++ b/src/ps2port.c @@ -151,6 +151,18 @@ process_ps2byte(u8 status, u8 data) process_key(data); } +static void +process_ps2bytes(void) +{ + for (;;) { + u8 status = inb(PORT_PS2_STATUS); + if (!(status & I8042_STR_OBF)) + return; + u8 data = inb(PORT_PS2_DATA); + process_ps2byte(status, data); + } +} + static int ps2_recvbyte(int aux, int needack, int timeout) { @@ -209,22 +221,13 @@ ps2_sendbyte(int aux, u8 command, int timeout) static int ps2_command(int aux, int command, u8 *param) { - int ret2; + int ret; int receive = (command >> 8) & 0xf; int send = (command >> 12) & 0xf; - // Disable interrupts and keyboard/mouse. - u8 ps2ctr = GET_EBDA(ps2ctr); - u8 newctr = ps2ctr; - if (aux) - newctr |= I8042_CTR_KBDDIS; - else - newctr |= I8042_CTR_AUXDIS; - newctr &= ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT); - dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr); - int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr); - if (ret) - return ret; + // Disable processing of interrupts. + u8 kbdflag = GET_BDA(kbd_flag3); + SET_BDA(kbd_flag3, kbdflag | KF3_CMD_PENDING); if (command == ATKBD_CMD_RESET_BAT) { // Reset is special wrt timeouts. @@ -270,10 +273,10 @@ ps2_command(int aux, int command, u8 *param) ret = 0; fail: - // Restore interrupts and keyboard/mouse. - ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr); - if (ret2) - return ret2; + // Restore processing of interrupts. + if (!(kbdflag & KF3_CMD_PENDING)) + process_ps2bytes(); + SET_BDA(kbd_flag3, kbdflag); return ret; } @@ -306,14 +309,10 @@ aux_command(int command, u8 *param) static void process_ps2irq(void) { - u8 status = inb(PORT_PS2_STATUS); - if (!(status & I8042_STR_OBF)) { - dprintf(1, "ps2 irq but no data.\n"); + if (GET_BDA(kbd_flag3) & KF3_CMD_PENDING) + // PS/2 command in progress - it will handle this event. return; - } - u8 data = inb(PORT_PS2_DATA); - - process_ps2byte(status, data); + process_ps2bytes(); } // INT74h : PS/2 mouse hardware interrupt @@ -402,8 +401,12 @@ keyboard_init(void *data) if (ret) return; - // Keyboard Mode: scan code convert, disable mouse, enable IRQ 1 - SET_EBDA(ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT); + // Mode: scan code convert, enable IRQ 1, enable IRQ 12 + param[0] = I8042_CTR_XLATE | I8042_CTR_KBDINT | I8042_CTR_AUXINT; + ret = i8042_command(I8042_CMD_CTL_WCTR, param); + if (ret) + return; + CLEARBITS_BDA(kbd_flag3, KF3_CMD_PENDING); /* Enable keyboard */ ret = kbd_command(ATKBD_CMD_ENABLE, NULL); @@ -420,6 +423,8 @@ ps2port_setup(void) return; dprintf(3, "init ps2port\n"); + // Setup irqs, but disable them until init complete. + SETBITS_BDA(kbd_flag3, KF3_CMD_PENDING); enable_hwirq(1, entry_09); enable_hwirq(12, entry_74); |