[SeaBIOS] [PATCH] ps2: Support mode for polling the PS2 port instead of using irqs

Kevin O'Connor kevin at koconnor.net
Mon Jul 6 23:20:01 CEST 2015


Some recent hardware has trouble with routing PS2 port interrupts
while the interrupt controller is in legacy routing mode.  This patch
adds a config mechanism (via "etc/ps2-poll-only") to force the PS2
code into a polling only mode so that interrupts are not required.

It is not recommended to use this polling mode on hardware that does
properly support PS2 irqs, because some very old (DOS-era) programs
depend on the BIOS PS2 irq behavior.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---

It has been reported that some chromebooks can't use PS2 interrupts.
The google seabios repo has a patch (implemented differently) to
address this (eg, 2bc098e85).

I don't actually have the impacted hardware, but I have tested this
patch by forcing polling mode on both QEMU and real hardware and can
verify that polling mode works.

---
 docs/Runtime_config.md |  1 +
 src/clock.c            |  2 ++
 src/hw/ps2port.c       | 46 ++++++++++++++++++++++++++++++++++++++--------
 src/hw/ps2port.h       |  1 +
 4 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/docs/Runtime_config.md b/docs/Runtime_config.md
index 4ac0eae..962a8a9 100644
--- a/docs/Runtime_config.md
+++ b/docs/Runtime_config.md
@@ -180,6 +180,7 @@ There are several additional configuration options available in the
 | boot-fail-wait      | If no boot devices are found SeaBIOS will reboot after 60 seconds. Set this to the amount of time (in milliseconds) to customize the reboot delay or set to -1 to disable rebooting when no boot devices are found
 | extra-pci-roots     | If the target machine has multiple independent root buses set this to a positive value. The SeaBIOS PCI probe will then search for the given number of extra root buses.
 | ps2-keyboard-spinup | Some laptops that emulate PS2 keyboards don't respond to keyboard commands immediately after powering on. One may specify the amount of time (in milliseconds) here to allow as additional time for the keyboard to become responsive. When this field is set, SeaBIOS will repeatedly attempt to detect the keyboard until the keyboard is found or the specified timeout is reached.
+| ps2-poll-only       | SeaBIOS normally sets up the PS2 port to generate interrupts on keyboard and mouse events. One may set this field to a non-zero value to have SeaBIOS periodically poll the PS2 port for events instead. This may be useful on machines that do not properly route PS2 port interrupts.
 | optionroms-checksum | Option ROMs are required to have correct checksums. However, some option ROMs in the wild don't correctly follow the specifications and have bad checksums. Set this to a zero value to allow SeaBIOS to execute them anyways.
 | pci-optionrom-exec  | Controls option ROM execution for roms found on PCI devices (as opposed to roms found in CBFS/fw_cfg).  Valid values are 0: Execute no ROMs, 1: Execute only VGA ROMs, 2: Execute all ROMs. The default is 2 (execute all ROMs).
 | s3-resume-vga-init  | Set this to a non-zero value to instruct SeaBIOS to run the vga rom on an S3 resume.
diff --git a/src/clock.c b/src/clock.c
index 28c168c..ee2b53f 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -8,6 +8,7 @@
 #include "biosvar.h" // SET_BDA
 #include "bregs.h" // struct bregs
 #include "hw/pic.h" // pic_eoi1
+#include "hw/ps2port.h" // ps2_check_event
 #include "hw/rtc.h" // rtc_read
 #include "hw/usb-hid.h" // usb_check_event
 #include "output.h" // debug_enter
@@ -297,6 +298,7 @@ handle_08(void)
     // Check for internal events.
     floppy_tick();
     usb_check_event();
+    ps2_check_event();
 
     // chain to user timer tick INT #0x1c
     struct bregs br;
diff --git a/src/hw/ps2port.c b/src/hw/ps2port.c
index 04995c8..4558a6e 100644
--- a/src/hw/ps2port.c
+++ b/src/hw/ps2port.c
@@ -210,7 +210,8 @@ ps2_sendbyte(int aux, u8 command, int timeout)
     return 0;
 }
 
-u8 Ps2ctr VARLOW;
+u8 Ps2ctr VARLOW = I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
+u8 Ps2poll VARFSEG;
 
 static int
 __ps2_command(int aux, int command, u8 *param)
@@ -232,6 +233,7 @@ __ps2_command(int aux, int command, u8 *param)
     yield();
 
     // Enable port command is being sent to.
+    SET_LOW(Ps2ctr, newctr);
     if (aux)
         newctr &= ~I8042_CTR_AUXDIS;
     else
@@ -308,6 +310,7 @@ __ps2_command(int aux, int command, u8 *param)
 
 fail:
     // Restore interrupts and keyboard/mouse.
+    SET_LOW(Ps2ctr, ps2ctr);
     ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
     if (ret2)
         return ret2;
@@ -341,9 +344,11 @@ ps2_mouse_command(int command, u8 *param)
 
     // Update ps2ctr for mouse enable/disable.
     if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) {
+        u8 ps2poll = GET_GLOBAL(Ps2poll);
         u8 ps2ctr = GET_LOW(Ps2ctr);
         if (command == PSMOUSE_CMD_ENABLE)
-            ps2ctr = (ps2ctr | I8042_CTR_AUXINT) & ~I8042_CTR_AUXDIS;
+            ps2ctr = ((ps2ctr | (ps2poll ? 0 : I8042_CTR_AUXINT))
+                      & ~I8042_CTR_AUXDIS);
         else
             ps2ctr = (ps2ctr | I8042_CTR_AUXDIS) & ~I8042_CTR_AUXINT;
         SET_LOW(Ps2ctr, ps2ctr);
@@ -414,6 +419,30 @@ done:
     pic_eoi1();
 }
 
+void
+ps2_check_event(void)
+{
+    if (! CONFIG_PS2PORT || !GET_GLOBAL(Ps2poll))
+        return;
+    u8 ps2ctr = GET_LOW(Ps2ctr);
+    if ((ps2ctr & (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS))
+        == (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS))
+        return;
+    for (;;) {
+        u8 status = inb(PORT_PS2_STATUS);
+        if (!(status & I8042_STR_OBF))
+            break;
+        u8 data = inb(PORT_PS2_DATA);
+        if (status & I8042_STR_AUXDATA) {
+            if (!(ps2ctr & I8042_CTR_AUXDIS))
+                process_mouse(data);
+        } else {
+            if (!(ps2ctr & I8042_CTR_KBDDIS))
+                process_key(data);
+        }
+    }
+}
+
 
 /****************************************************************
  * Setup
@@ -446,9 +475,6 @@ ps2_keyboard_setup(void *data)
         return;
     }
 
-    // Disable keyboard and mouse events.
-    SET_LOW(Ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS);
-
 
     /* ------------------- keyboard side ------------------------*/
     /* reset keyboard and self test  (keyboard side) */
@@ -482,7 +508,8 @@ ps2_keyboard_setup(void *data)
         return;
 
     // Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ
-    SET_LOW(Ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
+    Ps2ctr = (I8042_CTR_AUXDIS | I8042_CTR_XLATE
+              | (Ps2poll ? 0 : I8042_CTR_KBDINT));
 
     /* Enable keyboard */
     ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL);
@@ -500,8 +527,11 @@ ps2port_setup(void)
         return;
     dprintf(3, "init ps2port\n");
 
-    enable_hwirq(1, FUNC16(entry_09));
-    enable_hwirq(12, FUNC16(entry_74));
+    Ps2poll = romfile_loadint("etc/ps2-poll-only", 0);
+    if (!Ps2poll) {
+        enable_hwirq(1, FUNC16(entry_09));
+        enable_hwirq(12, FUNC16(entry_74));
+    }
 
     run_thread(ps2_keyboard_setup, NULL);
 }
diff --git a/src/hw/ps2port.h b/src/hw/ps2port.h
index e5d9014..dc0e430 100644
--- a/src/hw/ps2port.h
+++ b/src/hw/ps2port.h
@@ -61,6 +61,7 @@
 void i8042_reboot(void);
 int ps2_kbd_command(int command, u8 *param);
 int ps2_mouse_command(int command, u8 *param);
+void ps2_check_event(void);
 void ps2port_setup(void);
 
 #endif // ps2port.h
-- 
1.9.3




More information about the SeaBIOS mailing list