[coreboot-gerrit] New patch to review for coreboot: libpayload-x86: Add common i8042 driver
Patrick Rudolph (siro@das-labor.org)
gerrit at coreboot.org
Mon Mar 6 18:51:53 CET 2017
Patrick Rudolph (siro at das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18594
-gerrit
commit 115c9a665092ed662ef046169d75fd6f6ca5f21f
Author: Patrick Rudolph <siro at das-labor.org>
Date: Wed Mar 1 19:07:37 2017 +0100
libpayload-x86: Add common i8042 driver
Add a common i8042 driver that uses multiple overflowing
fifos to seperate PS/2 port and PS/2 aux port.
Required to support PC keyboard and PC mouse at the same time.
Tested on Lenovo T500.
Change-Id: I4ca803bfa3ed45111776eef1f4dccd3fab02ea39
Signed-off-by: Patrick Rudolph <siro at das-labor.org>
---
payloads/libpayload/Kconfig | 6 +
payloads/libpayload/drivers/Makefile.inc | 1 +
payloads/libpayload/drivers/i8042/i8042.c | 351 ++++++++++++++++++++++++++++++
payloads/libpayload/include/libpayload.h | 22 ++
4 files changed, 380 insertions(+)
diff --git a/payloads/libpayload/Kconfig b/payloads/libpayload/Kconfig
index 02f5977..950295a 100644
--- a/payloads/libpayload/Kconfig
+++ b/payloads/libpayload/Kconfig
@@ -313,6 +313,12 @@ config COREBOOT_VIDEO_CONSOLE
Say Y here if coreboot switched to a graphics mode and
your payload wants to use it.
+config PC_I8042
+ bool "A common PC i8042 driver"
+ default n
+ help
+ To be used by PC_KEYBOARD and PC_MOUSE.
+
config PC_KEYBOARD
bool "Allow input from a PC keyboard"
default y if ARCH_X86 # uses IO
diff --git a/payloads/libpayload/drivers/Makefile.inc b/payloads/libpayload/drivers/Makefile.inc
index c6f6575..843921b 100644
--- a/payloads/libpayload/drivers/Makefile.inc
+++ b/payloads/libpayload/drivers/Makefile.inc
@@ -38,6 +38,7 @@ libc-$(CONFIG_LP_S5P_SERIAL_CONSOLE) += serial/s5p.c serial/serial.c
libc-$(CONFIG_LP_IPQ806X_SERIAL_CONSOLE) += serial/ipq806x.c serial/serial.c
libc-$(CONFIG_LP_IPQ40XX_SERIAL_CONSOLE) += serial/ipq40xx.c serial/serial.c
libc-$(CONFIG_LP_BG4CD_SERIAL_CONSOLE) += serial/bg4cd.c serial/serial.c
+libc-$(CONFIG_LP_PC_I8042) += i8042/i8042.c
libc-$(CONFIG_LP_PC_KEYBOARD) += keyboard.c
libc-$(CONFIG_LP_CBMEM_CONSOLE) += cbmem_console.c
diff --git a/payloads/libpayload/drivers/i8042/i8042.c b/payloads/libpayload/drivers/i8042/i8042.c
new file mode 100644
index 0000000..f554cef
--- /dev/null
+++ b/payloads/libpayload/drivers/i8042/i8042.c
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the libpayload project.
+ *
+ * Patrick Rudolph 2017 <siro at das-labor.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <libpayload-config.h>
+#include <libpayload.h>
+
+/* Overflowing FIFO implementation */
+
+struct fifo {
+ u8 *buf;
+ u32 tx;
+ u32 rx;
+ u32 len;
+};
+
+/** Initialize a new fifo queue.
+ * Initialize a new fifo with length @len.
+ * @len: Length of new fifo
+ * Returns NULL on error.
+ */
+static struct fifo *fifo_init(u32 len)
+{
+ struct fifo *ret;
+
+ ret = malloc(sizeof(*ret));
+ if (!ret)
+ return NULL;
+
+ memset(ret, 0, sizeof(*ret));
+
+ ret->buf = malloc(len);
+ if (!ret->buf) {
+ free(ret);
+ return NULL;
+ }
+
+ ret->len = len;
+
+ return ret;
+}
+
+/** Push object onto fifo queue.
+ * Pushes a new object onto the fifo. In case the fifo
+ * is full the oldest object is overwritten.
+ * @fifo: Fifo to use
+ * @c: Element to push
+ */
+static void fifo_push(struct fifo *fifo, u8 c)
+{
+ fifo->buf[fifo->tx++] = c;
+ fifo->tx = fifo->tx % fifo->len;
+ if (fifo->tx == fifo->rx)
+ fifo->rx++;
+ fifo->rx = fifo->rx % fifo->len;
+}
+
+/** Test fifo queue element count.
+ * Returns 1 if fifo is empty.
+ * @fifo: Fifo to use
+ */
+static int fifo_is_empty(struct fifo *fifo)
+{
+ return fifo->tx == fifo->rx;
+}
+
+/** Pop element from fifo queue.
+ * Returns the oldest object from queue if any.
+ * In case the queue is empty 0 is returned.
+ * @fifo: Fifo to use
+ */
+static u8 fifo_pop(struct fifo *fifo)
+{
+ u8 ret;
+
+ if (fifo_is_empty(fifo))
+ return 0;
+
+ ret = fifo->buf[fifo->rx++];
+ fifo->rx = fifo->rx % fifo->len;
+
+ return ret;
+}
+
+/* i8042 keyboard controller implementation */
+
+/* Keyboard controller methods */
+static u8 initialized;
+static struct fifo *aux_fifo;
+static struct fifo *ps2_fifo;
+
+/** Wait for command ready.
+ * Wait for the keyboard controller to accept a new command.
+ * Returns: 0 on timeout
+ */
+static u8 i8042_wait_cmd_rdy(void)
+{
+ int retries = 10000;
+ while (retries-- && (inb(0x64) & 0x02))
+ udelay(50);
+
+ return retries > 0;
+}
+
+/** Wait for data ready.
+ * Wait for the keyboard controller to accept new data.
+ * Returns: 0 on timeout
+ */
+static u8 i8042_wait_data_rdy(void)
+{
+ int retries = 10000;
+ while (retries-- && !(inb(0x64) & 0x01))
+ udelay(50);
+
+ return retries > 0;
+}
+
+/** Keyboard controller has a ps2 port.
+ * Returns if ps2 port is available.
+ */
+u8 i8042_has_ps2(void)
+{
+ return !!ps2_fifo;
+}
+
+/** Keyboard controller has an aux port.
+ * Returns if aux port is available.
+ */
+u8 i8042_has_aux(void)
+{
+ return !!aux_fifo;
+}
+
+/**
+ * Probe for keyboard controller
+ * Returns: 1 for success, 0 for failure
+ */
+u8 i8042_probe(void)
+{
+ if (initialized)
+ return 1;
+
+ /* If 0x64 returns 0xff, then we have no keyboard
+ * controller */
+ if (inb(0x64) == 0xFF)
+ return 0;
+
+ if (!i8042_wait_cmd_rdy())
+ return 0;
+
+ /* Disable first device */
+ outb(0xad, 0x64);
+
+ if (!i8042_wait_cmd_rdy())
+ return 0;
+
+ /* Disable second device */
+ outb(0xa7, 0x64);
+
+ if (!i8042_wait_cmd_rdy())
+ return 0;
+
+ /* Flush buffer */
+ while (inb(0x64) & 0x01)
+ inb(0x60);
+
+ if (!i8042_wait_cmd_rdy())
+ return 0;
+
+ /* Self test. */
+ outb(0xaa, 0x64);
+
+ if (!i8042_wait_cmd_rdy())
+ return 0;
+
+ /* Wait for answer. */
+ if (!i8042_wait_data_rdy())
+ return 0;
+
+ initialized = inb(0x60) == 0x55;
+
+ if (!i8042_wait_cmd_rdy())
+ return 0;
+
+ /* Test secondary port. Will leak aux_fifo... */
+ if (i8042_cmd(0xa9, 1) == 0)
+ aux_fifo = fifo_init(4 * 32);
+
+ /* Test first PS/2 port. Will leak ps2_fifo... */
+ if (i8042_cmd(0xab, 1) == 0)
+ ps2_fifo = fifo_init(2 * 16);
+
+ return initialized;
+}
+
+/** Send command to keyboard controller.
+ * @param cmd: The command to be send.
+ * @param response: Wait for and return response.
+ * returns: Response if any, otherwise 0 on success, -1 on failure.
+ */
+int i8042_cmd(u8 cmd, u8 response)
+{
+ if (!initialized)
+ return -1;
+
+ if (!i8042_wait_cmd_rdy())
+ return -1;
+
+ outb(cmd, 0x64);
+
+ if (!i8042_wait_cmd_rdy())
+ return -1;
+
+ if (response) {
+ if (!i8042_wait_data_rdy())
+ return -1;
+
+ return inb(0x60);
+ }
+
+ return 0;
+}
+
+/** Send additional data to keyboard controller.
+ * @param data The data to be send.
+ */
+void i8042_write_input(u8 data)
+{
+ if (!initialized)
+ return;
+
+ if (!i8042_wait_cmd_rdy())
+ return;
+
+ outb(data, 0x60);
+
+ if (!i8042_wait_cmd_rdy())
+ return;
+}
+
+/**
+ * Probe for keyboard controller data and queue it.
+ */
+static void i8042_data_poll(void)
+{
+ u8 c;
+
+ if (!initialized)
+ return;
+
+ c = inb(0x64);
+ while ((c != 0xFF) && (c & 1)) {
+ /* Assume "second PS/2 port output buffer full" flag works */
+ if ((c & 0x20) && aux_fifo)
+ fifo_push(aux_fifo, inb(0x60));
+ else if (!(c & 0x20) && ps2_fifo)
+ fifo_push(ps2_fifo, inb(0x60));
+
+ c = inb(0x64);
+ }
+}
+
+/** Keyboard controller data ready status.
+ * Signals that keyboard data is ready for reading.
+ */
+u8 i8042_data_ready_ps2(void)
+{
+ i8042_data_poll();
+ return !fifo_is_empty(ps2_fifo);
+}
+
+/** Keyboard controller data ready status.
+ * Signals that mouse data is ready for reading.
+ */
+u8 i8042_data_ready_aux(void)
+{
+ i8042_data_poll();
+ return !fifo_is_empty(aux_fifo);
+}
+
+/**
+ * Returns available keyboard data, if any.
+ */
+u8 i8042_data_get_ps2(void)
+{
+ i8042_data_poll();
+ return fifo_pop(ps2_fifo);
+}
+
+/**
+ * Returns available mouse data, if any.
+ */
+u8 i8042_data_get_aux(void)
+{
+ i8042_data_poll();
+ return fifo_pop(aux_fifo);
+}
+
+/**
+ * Waits for keyboard data.
+ * Waits for up to 500msec to receive data.
+ * Returns: -1 on timeout, data received otherwise
+ */
+int i8042_wait_read_ps2(void)
+{
+ int retries = 10000;
+
+ while (retries-- && !i8042_data_ready_ps2())
+ udelay(50);
+
+ return (retries <= 0) ? -1 : i8042_data_get_ps2();
+}
+
+/** Waits for mouse data.
+ * Waits for up to 500msec to receive data.
+ * Returns: -1 on timeout, data received otherwise
+ */
+int i8042_wait_read_aux(void)
+{
+ int retries = 10000;
+
+ while (retries-- && !i8042_data_ready_aux())
+ udelay(50);
+
+ return (retries <= 0) ? -1 : i8042_data_get_aux();
+}
diff --git a/payloads/libpayload/include/libpayload.h b/payloads/libpayload/include/libpayload.h
index 3858caa..a44eedd 100644
--- a/payloads/libpayload/include/libpayload.h
+++ b/payloads/libpayload/include/libpayload.h
@@ -178,6 +178,28 @@ u8 mouse_cursor_get_acceleration(void);
/** @} */
/**
+ * @defgroup i8042 controller functions
+ * @ingroup input
+ * @{
+ */
+u8 i8042_has_ps2(void);
+u8 i8042_has_aux(void);
+
+u8 i8042_probe(void);
+int i8042_cmd(u8 cmd, u8 response);
+void i8042_write_input(u8 data);
+
+u8 i8042_data_ready_ps2(void);
+u8 i8042_data_ready_aux(void);
+
+u8 i8042_data_get_ps2(void);
+u8 i8042_data_get_aux(void);
+
+int i8042_wait_read_ps2(void);
+int i8042_wait_read_aux(void);
+/** @} */
+
+/**
* @defgroup serial Serial functions
* @ingroup input
* @{
More information about the coreboot-gerrit
mailing list