return 0;
udelay(50);
}
- dprintf(1, "i8042 timeout on wait read\n");
+ warn_timeout();
return -1;
}
return 0;
udelay(50);
}
- dprintf(1, "i8042 timeout on wait write\n");
+ warn_timeout();
return -1;
}
dprintf(7, "i8042 flushed %x (status=%x)\n", data, status);
}
- dprintf(1, "i8042 timeout on flush\n");
+ warn_timeout();
return -1;
}
#define PS2_RET_ACK 0xfa
#define PS2_RET_NAK 0xfe
+static void
+process_ps2byte(u8 status, u8 data)
+{
+ if (!MODE16) {
+ // Don't pull in all of keyboard/mouse code into 32bit code -
+ // just discard the data.
+ dprintf(1, "Discarding ps2 data %x (status=%x)\n", data, status);
+ return;
+ }
+ if (status & I8042_STR_AUXDATA)
+ process_mouse(data);
+ else
+ 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)
{
}
}
- // This data not for us - XXX - just discard it for now.
- dprintf(1, "Discarding ps2 data %x (status=%x)\n", data, status);
+ // Data not part of this command.
+ process_ps2byte(status, data);
}
if (check_time(end)) {
- dprintf(1, "ps2_recvbyte timeout\n");
+ // Don't warn on second byte of a reset
+ if (timeout > 100)
+ warn_timeout();
return -1;
}
yield();
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.
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;
}
* IRQ handlers
****************************************************************/
+static void
+process_ps2irq(void)
+{
+ if (GET_BDA(kbd_flag3) & KF3_CMD_PENDING)
+ // PS/2 command in progress - it will handle this event.
+ return;
+ process_ps2bytes();
+}
+
// INT74h : PS/2 mouse hardware interrupt
void VISIBLE16
-handle_74()
+handle_74(void)
{
if (! CONFIG_PS2PORT)
return;
debug_isr(DEBUG_ISR_74);
-
- u8 v = inb(PORT_PS2_STATUS);
- if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA))
- != (I8042_STR_OBF|I8042_STR_AUXDATA)) {
- dprintf(1, "mouse irq but no mouse data.\n");
- goto done;
- }
- v = inb(PORT_PS2_DATA);
-
- process_mouse(v);
-
-done:
+ process_ps2irq();
eoi_pic2();
}
// INT09h : Keyboard Hardware Service Entry Point
void VISIBLE16
-handle_09()
+handle_09(void)
{
if (! CONFIG_PS2PORT)
return;
debug_isr(DEBUG_ISR_09);
-
- // read key from keyboard controller
- u8 v = inb(PORT_PS2_STATUS);
- if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA)) != I8042_STR_OBF) {
- dprintf(1, "keyboard irq but no keyboard data.\n");
- goto done;
- }
- v = inb(PORT_PS2_DATA);
-
- process_key(v);
-
-done:
+ process_ps2irq();
eoi_pic1();
}
****************************************************************/
static void
-keyboard_init()
+keyboard_init(void *data)
{
/* flush incoming keys */
int ret = i8042_flush();
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);
if (ret)
return;
- dprintf(1, "keyboard initialized\n");
+ dprintf(1, "PS2 keyboard initialized\n");
}
void
-ps2port_setup()
+ps2port_setup(void)
{
+ ASSERT32FLAT();
if (! CONFIG_PS2PORT)
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);