aboutsummaryrefslogtreecommitdiff
path: root/src/ps2port.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2010-01-28 20:35:21 -0500
committerKevin O'Connor <kevin@koconnor.net>2010-01-28 20:35:21 -0500
commit6f702dd6987b22e9bce472fe61910392af17416a (patch)
tree14004f76f72bb1a6983f2ee5ebea8a1a1c870f40 /src/ps2port.c
parent2d3f0f5e4040a5b2dabc278bc5aa5bc3d9e71e1b (diff)
downloadseabios-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.c57
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);