Prefer passing a USB "pipe" structure over a USB endp encoding.
[seabios.git] / src / ps2port.c
index d03c049bc9aee2065f19478f6bcf375ff7b3abc6..26c55f28ee8ef6d3ae3221a9deb23680bbbee57d 100644 (file)
@@ -32,7 +32,7 @@ i8042_wait_read(void)
             return 0;
         udelay(50);
     }
-    dprintf(1, "i8042 timeout on wait read\n");
+    warn_timeout();
     return -1;
 }
 
@@ -47,7 +47,7 @@ i8042_wait_write(void)
             return 0;
         udelay(50);
     }
-    dprintf(1, "i8042 timeout on wait write\n");
+    warn_timeout();
     return -1;
 }
 
@@ -65,7 +65,7 @@ i8042_flush(void)
         dprintf(7, "i8042 flushed %x (status=%x)\n", data, status);
     }
 
-    dprintf(1, "i8042 timeout on flush\n");
+    warn_timeout();
     return -1;
 }
 
@@ -136,6 +136,33 @@ i8042_aux_write(u8 c)
 #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)
 {
@@ -157,12 +184,14 @@ 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();
@@ -194,22 +223,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.
@@ -255,10 +275,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;
 }
@@ -288,49 +308,36 @@ aux_command(int command, u8 *param)
  * 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();
 }
 
@@ -340,7 +347,7 @@ done:
  ****************************************************************/
 
 static void
-keyboard_init()
+keyboard_init(void *data)
 {
     /* flush incoming keys */
     int ret = i8042_flush();
@@ -396,24 +403,31 @@ keyboard_init()
     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);