[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