kbd: Add keyboard polling

Some devices don't have legacy interrupt support, but still use
need to use a legacy keyboard. This patch adds a KBC check and manual call
to the keyboard service if there is a key waiting in the KBC.

BUG=chrome-os-partner:30836
BRANCH=None
TEST=Build and boot Rambi SeaBIOS.

Change-Id: I11033d29ec26b5a772588a0aa1a35678ab05a462
Signed-off-by: Marc Jones <marc.jones@se-eng.com>
Reviewed-on: https://chromium-review.googlesource.com/219803
Reviewed-by: Mike Loptien <mike.loptien@se-eng.com>
Tested-by: Mike Loptien <mike.loptien@se-eng.com>
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
diff --git a/chromeos/default.config b/chromeos/default.config
index 41dd032..2717cf0 100644
--- a/chromeos/default.config
+++ b/chromeos/default.config
@@ -7,5 +7,6 @@
 # CONFIG_USB_OHCI is not set
 # CONFIG_LPT is not set
 # CONFIG_MOUSE is not set
+CONFIG_KBC_POLL=y
 CONFIG_NO_VGABIOS=y
 CONFIG_DEBUG_LEVEL=8
diff --git a/src/Kconfig b/src/Kconfig
index cce3ad8..3f57543 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -391,6 +391,11 @@
         default y
         help
             Support for int15c2 mouse calls.
+    config KBC_POLL
+        bool "Poll the keyboad controller for keys"
+        default n
+        help
+            Poll for keys when interrupts are not available.
 
     config S3_RESUME
         bool "S3 resume"
diff --git a/src/boot.c b/src/boot.c
index 183f4f3..d44605a 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -435,7 +435,10 @@
             return get_raw_keystroke();
         if (irqtimer_check(end))
             return -1;
+     if (!CONFIG_KBC_POLL)
         yield_toirq();
+     else
+        msleep(5);
     }
 }
 
diff --git a/src/kbd.c b/src/kbd.c
index 33a95a3..b387d26 100644
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -262,6 +262,18 @@
     // XXX - set_leds should be called from irq handler
     set_leds();
 
+    // If interrupts are not enabled do KBC polling.
+    // Check the KBC for a key on every keyboard service function (INT16).
+    // If interrupts are working the KBC status port should always be empty.
+    // (Yes, there is a race condition, but it is recoverable).
+    if (CONFIG_PS2PORT && CONFIG_KBC_POLL) {
+        u8 v = inb(PORT_PS2_STATUS);
+        if ((v & I8042_STR_OBF) && !(v & I8042_STR_AUXDATA)) {
+            v = inb(PORT_PS2_DATA);
+            process_key(v);
+        }
+    }
+
     switch (regs->ah) {
     case 0x00: handle_1600(regs); break;
     case 0x01: handle_1601(regs); break;