diff options
author | Patrick Rudolph <siro@das-labor.org> | 2017-02-06 15:26:58 +0100 |
---|---|---|
committer | Philipp Deppenwiese <zaolin.daisuki@gmail.com> | 2018-05-15 12:02:31 +0000 |
commit | 5afc2936b83c744e0a0d3ab92e7a98b2aa163df4 (patch) | |
tree | 6e46e09fd42348e0b4e84cd9cd49ca16d66ef78d /payloads/libpayload/drivers | |
parent | c622dc5e822cb849e36386a28efcb88241533a54 (diff) | |
download | coreboot-5afc2936b83c744e0a0d3ab92e7a98b2aa163df4.tar.xz |
libpayload-x86: Add PS2 mouse driver
Make use of i8042 driver to add PS2 mouse driver support.
Tested on Lenovot T500.
The touchpad can be used to drive the mouse cursor.
Change-Id: I4be9c74467596b94d64dfa510824d8722108fe9c
Signed-off-by: Patrick Rudolph <siro@das-labor.org>
Reviewed-on: https://review.coreboot.org/18597
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
Diffstat (limited to 'payloads/libpayload/drivers')
-rw-r--r-- | payloads/libpayload/drivers/Makefile.inc | 1 | ||||
-rw-r--r-- | payloads/libpayload/drivers/i8042/mouse.c | 292 | ||||
-rw-r--r-- | payloads/libpayload/drivers/mouse_cursor.c | 4 |
3 files changed, 296 insertions, 1 deletions
diff --git a/payloads/libpayload/drivers/Makefile.inc b/payloads/libpayload/drivers/Makefile.inc index 6eb9f0c4fc..2d70856f0a 100644 --- a/payloads/libpayload/drivers/Makefile.inc +++ b/payloads/libpayload/drivers/Makefile.inc @@ -39,6 +39,7 @@ 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_KEYBOARD) += i8042/keyboard.c +libc-$(CONFIG_LP_PC_MOUSE) += i8042/mouse.c libc-$(CONFIG_LP_PC_I8042) += i8042/i8042.c libc-$(CONFIG_LP_CBMEM_CONSOLE) += cbmem_console.c diff --git a/payloads/libpayload/drivers/i8042/mouse.c b/payloads/libpayload/drivers/i8042/mouse.c new file mode 100644 index 0000000000..21096d18c6 --- /dev/null +++ b/payloads/libpayload/drivers/i8042/mouse.c @@ -0,0 +1,292 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2017 Patrick Rudolph <siro@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> + +static int x_axis; +static int y_axis; +static int z_axis; +static u32 buttons; +static u8 is_intellimouse; +static u8 is_explorer_intellimouse; +static u8 initialized; +static unsigned char mouse_buf[4]; +static unsigned char mouse_buf_idx; + +static u8 mouse_cmd(unsigned char cmd) +{ + i8042_cmd(0xd4); + + i8042_write_data(cmd); + + return i8042_wait_read_aux() == 0xfa; +} + +static u8 mouse_cmd_data(u8 cmd, u8 val) +{ + if (!mouse_cmd(cmd)) + return 0; + + return mouse_cmd(val); +} + +/** Try to detect Microsoft Intelli mouse */ +static u8 mouse_is_intellimouse(void) +{ + /* Silence mouse. */ + if (!mouse_cmd(0xf5)) + return 0; + + /* Set standard. */ + if (!mouse_cmd(0xf6)) + return 0; + + /* Magic sequence. */ + if (!mouse_cmd_data(0xf3, 0xc8)) + return 0; + if (!mouse_cmd_data(0xf3, 0x64)) + return 0; + if (!mouse_cmd_data(0xf3, 0x50)) + return 0; + + /* Get mouse id */ + if (!mouse_cmd(0xf2)) + return 0; + + if (i8042_wait_read_aux() != 0x03) + return 0; + + return 1; +} + +/** Try to detect Microsoft Explorer mouse */ +static u8 mouse_is_intellimouse_explorer(void) +{ + /* Silence mouse. */ + if (!mouse_cmd(0xf5)) + return 0; + + /* Set standard. */ + if (!mouse_cmd(0xf6)) + return 0; + + /* Magic sequence. */ + if (!mouse_cmd_data(0xf3, 0xc8)) + return 0; + if (!mouse_cmd_data(0xf3, 0xc8)) + return 0; + if (!mouse_cmd_data(0xf3, 0x50)) + return 0; + + /* Get mouse id */ + if (!mouse_cmd(0xf2)) + return 0; + + if (i8042_wait_read_aux() != 4) + return 0; + + return 1; +} + +/** Decode temporary buffer + * Sanity check to prevent out of order decode. + * Decode PS/2 data. + * Supported devices: + * Generic 3 button mouse + * Microsoft Intelli mouse + * Microsoft Explorer mouse + */ +static void mouse_decode(void) +{ + /* Buffer full check and sanity check */ + if (is_intellimouse) { + if (mouse_buf_idx < 4) + return; + if ((mouse_buf[3] & 0x10) != (mouse_buf[3] & 0x08)) { + mouse_buf_idx = 0; + return; + } + } else if (is_explorer_intellimouse) { + if (mouse_buf_idx < 4) + return; + if (mouse_buf[3] & 0xc0) { + mouse_buf_idx = 0; + return; + } + } else { + if (mouse_buf_idx < 3) + return; + } + + /* Common protocol */ + x_axis += mouse_buf[1] ? mouse_buf[1] - ((mouse_buf[0] << 4) & 0x100) : 0; + y_axis += mouse_buf[2] ? ((mouse_buf[0] << 3) & 0x100) - mouse_buf[2] : 0; + buttons = mouse_buf[0] & 0x7; + + /* Extended protocol */ + if (is_intellimouse) { + z_axis += (mouse_buf[3] & 0x7) - (mouse_buf[3] & 0x08) ? 8 : 0; + } else if (is_explorer_intellimouse) { + z_axis += (mouse_buf[3] & 0x7) - (mouse_buf[3] & 0x08) ? 8 : 0; + buttons = (mouse_buf[0] & 0x7) | (mouse_buf[3] & 0x30) >> 1; + } + + mouse_buf_idx = 0; +} + +/** Insert data into internal temporary buffer. */ +static void insert_buf(unsigned char c) +{ + /* Validate input: + * First byte shall have bit 3 set ! */ + if (!mouse_buf_idx && !(c & 8)) + return; + + mouse_buf[mouse_buf_idx++] = c; +} + +/** Probe i8042 for new aux data and try to decode it. */ +static void mouse_sample(void) +{ + if (!initialized) + return; + + while (i8042_data_ready_aux()) { + insert_buf(i8042_read_data_aux()); + mouse_decode(); + } +} + +/** Mouse cursor interface method + * Return and reset internal state. + */ +static void mouse_state(int *x, int *y, int *z, u32 *b) +{ + if (!initialized) + return; + + mouse_sample(); + + if (x) { + *x = x_axis; + x_axis = 0; + } + if (y) { + *y = y_axis; + y_axis = 0; + } + if (z) { + *z = z_axis; + z_axis = 0; + } + if (b) + *b = buttons; +} + +static struct mouse_cursor_input_driver curs = { + .get_state = mouse_state, + .input_type = CURSOR_INPUT_TYPE_PS2, +}; + +/** Probe for PS/2 mouse */ +void i8042_mouse_init(void) +{ + int ret; + + /** + * Initialize keyboard controller. + * Might fail in case no AUX port or firmware disabled the AUX port. + */ + if (!i8042_probe() || !i8042_has_aux()) + return; + + /* Empty mouse buffer. */ + while (i8042_data_ready_aux()) + i8042_read_data_aux(); + + /* Enable mouse. + * Documentation is unclear at this point. + * Some recommend to wait for response, some claim there's none. + * No response on Lenovo H8 EC. + * Ignore it ... */ + ret = i8042_cmd(0xa8); + if (ret == -1) + return; + + /* Silence mouse. */ + if (!mouse_cmd(0xf5)) + return; + + /* Read mouse id. */ + if (!mouse_cmd(0xf2)) + return; + + ret = i8042_wait_read_aux(); + if (ret) + return; + + /* Get and enable features (scroll wheel and 5 buttons) */ + is_intellimouse = mouse_is_intellimouse(); + is_explorer_intellimouse = mouse_is_intellimouse_explorer(); + + /* Set defaults. */ + if (!mouse_cmd(0xf6)) + return; + + /* Enable data transmission. */ + if (!mouse_cmd(0xf4)) + return; + + initialized = 1; + + /* Register mouse cursor driver */ + mouse_cursor_add_input_driver(&curs); +} + +/* Disable PS/2 mouse. */ +void i8042_mouse_disconnect(void) +{ + /* If 0x64 returns 0xff, then we have no keyboard + * controller */ + if (inb(0x64) == 0xFF || !initialized) + return; + + /* Empty keyboard buffer */ + while (i8042_data_ready_aux()) + i8042_read_data_aux(); + + /* Disable mouse. */ + i8042_cmd(0xa7); + + initialized = 0; + + /* Release keyboard controller driver */ + i8042_close(); +} diff --git a/payloads/libpayload/drivers/mouse_cursor.c b/payloads/libpayload/drivers/mouse_cursor.c index 781845caaf..40c8934889 100644 --- a/payloads/libpayload/drivers/mouse_cursor.c +++ b/payloads/libpayload/drivers/mouse_cursor.c @@ -60,7 +60,9 @@ void mouse_cursor_add_input_driver(struct mouse_cursor_input_driver *const in) /** Init enabled mouse cursor drivers */ void mouse_cursor_init(void) { -/* FIXME */ +#if IS_ENABLED(CONFIG_LP_PC_MOUSE) + i8042_mouse_init(); +#endif } static u32 mouse_buttons; |