From 7eabcb4e69aa5e19d92a8ab84806bc92377a82aa Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Sun, 17 Jun 2012 15:51:00 +0800 Subject: [PATCH] Add a test of checking power button handling This test checks power button is correctly debounced, and also check power button press of different length are handled correctly. BUG=chrome-os-partner:10273 TEST=Test passed Change-Id: I18595c60896255d36326731d28bab55e64c6bca2 Reviewed-on: https://gerrit.chromium.org/gerrit/25505 Reviewed-by: Vincent Palatin Reviewed-by: Randall Spangler Tested-by: Vic Yang Commit-Ready: Vic Yang --- chip/lm4/mock_gpio.c | 117 +++++++++++++++++++++++++ chip/lm4/mock_pwm.c | 7 ++ common/mock_i8042.c | 58 +++++++++++++ common/mock_x86_power.c | 49 +++++++++++ test/build.mk | 7 ++ test/power_button.py | 174 +++++++++++++++++++++++++++++++++++++ test/power_button.tasklist | 24 +++++ 7 files changed, 436 insertions(+) create mode 100644 chip/lm4/mock_gpio.c create mode 100644 common/mock_i8042.c create mode 100644 test/power_button.py create mode 100644 test/power_button.tasklist diff --git a/chip/lm4/mock_gpio.c b/chip/lm4/mock_gpio.c new file mode 100644 index 0000000000..600b117465 --- /dev/null +++ b/chip/lm4/mock_gpio.c @@ -0,0 +1,117 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Mock GPIO module for Chrome EC */ + +#include "board.h" +#include "console.h" +#include "gpio.h" +#include "util.h" + + +static int8_t mock_value[GPIO_COUNT] = {0}; +static int8_t mock_gpio_im[GPIO_COUNT] = {0}; + + +int gpio_pre_init(void) +{ + /* Nothing to do */ + return EC_SUCCESS; +} + + +void gpio_set_alternate_function(int port, int mask, int func) +{ + /* Not implemented */ + return; +} + + +const char *gpio_get_name(enum gpio_signal signal) +{ + return gpio_list[signal].name; +} + + +int gpio_get_level(enum gpio_signal signal) +{ + return mock_value[signal] ? 1 : 0; +} + + +int gpio_set_level(enum gpio_signal signal, int value) +{ + mock_value[signal] = value; + return EC_SUCCESS; +} + + +int gpio_set_flags(enum gpio_signal signal, int flags) +{ + /* Not implemented */ + return EC_SUCCESS; +} + + +int gpio_enable_interrupt(enum gpio_signal signal) +{ + const struct gpio_info *g = gpio_list + signal; + + /* Fail if no interrupt handler */ + if (!g->irq_handler) + return EC_ERROR_UNKNOWN; + + mock_gpio_im[signal] = 1; + return EC_SUCCESS; +} + + +/* Find a GPIO signal by name. Returns the signal index, or GPIO_COUNT if + * no match. */ +static enum gpio_signal find_signal_by_name(const char *name) +{ + const struct gpio_info *g = gpio_list; + int i; + + if (!name || !*name) + return GPIO_COUNT; + + for (i = 0; i < GPIO_COUNT; i++, g++) { + if (!strcasecmp(name, g->name)) + return i; + } + + return GPIO_COUNT; +} + + +static int command_gpio_mock(int argc, char **argv) +{ + char *e; + int v, i; + const struct gpio_info *g; + + if (argc < 3) + return EC_ERROR_PARAM_COUNT; + + i = find_signal_by_name(argv[1]); + if (i == GPIO_COUNT) + return EC_ERROR_PARAM1; + g = gpio_list + i; + + v = strtoi(argv[2], &e, 0); + if (*e) + return EC_ERROR_PARAM2; + + gpio_set_level(i, v); + + if (g->irq_handler && mock_gpio_im[i]) + g->irq_handler(i); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(gpiomock, command_gpio_mock, + "name <0 | 1>", + "Mock a GPIO input", + NULL); diff --git a/chip/lm4/mock_pwm.c b/chip/lm4/mock_pwm.c index 7bd356a6a9..6c8f4d1d8b 100644 --- a/chip/lm4/mock_pwm.c +++ b/chip/lm4/mock_pwm.c @@ -47,6 +47,13 @@ int pwm_get_keyboard_backlight_enabled(void) } +int pwm_enable_keyboard_backlight(int enable) +{ + /* Not implemented */ + return EC_SUCCESS; +} + + void pwm_task(void) { /* Do nothing */ diff --git a/common/mock_i8042.c b/common/mock_i8042.c new file mode 100644 index 0000000000..fc7b1f1e60 --- /dev/null +++ b/common/mock_i8042.c @@ -0,0 +1,58 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Mock EC i8042 interface code. + */ + +#include "i8042.h" +#include "timer.h" +#include "uart.h" + + +void i8042_receives_data(int data) +{ + /* Not implemented */ + return; +} + + +void i8042_receives_command(int cmd) +{ + /* Not implemented */ + return; +} + + +void i8042_command_task(void) +{ + /* Do nothing */ + while (1) + usleep(5000000); +} + + +enum ec_error_list i8042_send_to_host(int len, const uint8_t *bytes) +{ + uart_printf("i8042 SEND\n"); + return EC_SUCCESS; +} + + +void i8042_enable_keyboard_irq(void) { + /* Not implemented */ + return; +} + + +void i8042_disable_keyboard_irq(void) { + /* Not implemented */ + return; +} + + +void i8042_flush_buffer() +{ + /* Not implemented */ + return; +} diff --git a/common/mock_x86_power.c b/common/mock_x86_power.c index 4842044382..e108f8bd15 100644 --- a/common/mock_x86_power.c +++ b/common/mock_x86_power.c @@ -6,11 +6,15 @@ /* Mock X86 chipset power control module for Chrome EC */ #include "chipset.h" +#include "console.h" #include "lpc.h" #include "timer.h" #include "uart.h" +#include "util.h" #include "x86_power.h" +static int mock_power_on = 0; + void x86_power_cpu_overheated(int too_hot) { /* Print transitions */ @@ -31,6 +35,12 @@ void x86_power_force_shutdown(void) } +void x86_power_reset(int cold_reset) +{ + uart_printf("X86 Power %s reset\n", cold_reset ? "cold" : "warm"); +} + + void chipset_throttle_cpu(int throttle) { /* Print transitions */ @@ -45,6 +55,23 @@ void chipset_throttle_cpu(int throttle) } +void chipset_exit_hard_off(void) +{ + /* Not implemented */ + return; +} + + +int chipset_in_state(int state_mask) +{ + if (mock_power_on) + return state_mask == CHIPSET_STATE_ON; + else + return (state_mask == CHIPSET_STATE_SOFT_OFF) || + (state_mask == CHIPSET_STATE_ANY_OFF); +} + + void x86_power_interrupt(enum gpio_signal signal) { /* Not implemented */ @@ -58,3 +85,25 @@ void x86_power_task(void) while (1) usleep(5000000); } + + +static int command_mock_power(int argc, char **argv) +{ + if (argc != 2) + return EC_ERROR_PARAM_COUNT; + + if (!strcasecmp(argv[1], "on")) { + mock_power_on = 1; + } + else if (!strcasecmp(argv[1], "off")) { + mock_power_on = 0; + } + else + return EC_ERROR_PARAM1; + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(powermock, command_mock_power, + "", + "Mock power state", + NULL); diff --git a/test/build.mk b/test/build.mk index 2ad8df6c4f..e4ca8341c2 100644 --- a/test/build.mk +++ b/test/build.mk @@ -7,6 +7,7 @@ # test-list=hello pingpong timer_calib timer_dos timer_jump mutex thermal +test-list+=power_button #disable: powerdemo pingpong-y=pingpong.o @@ -20,3 +21,9 @@ chip-mock-thermal-lpc.o=mock_lpc.o chip-mock-thermal-pwm.o=mock_pwm.o common-mock-thermal-x86_power.o=mock_x86_power.o common-mock-thermal-temp_sensor.o=mock_temp_sensor.o + +# Mock modules for 'power_button' +chip-mock-power_button-gpio.o=mock_gpio.o +chip-mock-power_button-pwm.o=mock_pwm.o +common-mock-power_button-x86_power.o=mock_x86_power.o +common-mock-power_button-i8042.o=mock_i8042.o diff --git a/test/power_button.py b/test/power_button.py new file mode 100644 index 0000000000..7f5c3b9fb0 --- /dev/null +++ b/test/power_button.py @@ -0,0 +1,174 @@ +# Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Power button debounce test +# +# Refer to section 1.3 Power Button of +# https://sites.google.com/a/google.com/chromeos-partners/pages/ +# tech-docs/firmware/ec-specification-v119 +# + +import time + +SHORTER_THAN_T0 = 0.01 +LONGER_THAN_T0 = 0.05 +LONGER_THAN_T1 = 5 + +def check_no_output(helper, reg_ex): + success = False + try: + helper.wait_output(reg_ex, use_re=True, timeout=1) + except: + success = True + return success + +def consume_output(helper, reg_ex): + done = False + while not done: + try: + helper.wait_output(reg_ex, use_re=True, timeout=1) + except: + done = True + +def test(helper): + helper.wait_output("--- UART initialized") + # Release power button, set to soft off, and enable keyboard + helper.ec_command("gpiomock POWER_BUTTONn 1") + helper.ec_command("powermock off") + helper.ec_command("kbd enable") + consume_output(helper, "PB released") + + helper.trace("Press power button for shorter than T0 and check this\n" + + "event is ignored\n") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(SHORTER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + if not check_no_output(helper, "PB released"): + return False + + helper.trace("Press power button for longer than T0 and check this\n" + + "event is treated as a single press.") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(LONGER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + helper.wait_output("PB released", timeout=1) + # Expect shown only once + if not check_no_output(helper, "PB released"): + return False + + helper.trace("Press power button for two consecutive SHORTER_THAN_T0\n" + + "period and check this event is ignored\n") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(SHORTER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + time.sleep(SHORTER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(SHORTER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + if not check_no_output(helper, "PB released"): + return False + + helper.trace("Hold down power button for LONGER_THAN_T0 and check a\n" + + "single press is sent out\n") + consume_output(helper, "pwrbtn=") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(LONGER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + helper.wait_output("pwrbtn=LOW", timeout=1) + helper.wait_output("pwrbtn=HIGH", timeout=1) + if not check_no_output(helper, "pwrbtn=LOW"): + return False + + helper.trace("Press power button for SHORTER_THAN_T0, release for\n" + + "SHORTER_THAN_T0, and then press for LONGER_THAN_T0.\n" + + "Check this is treated as a single press\n") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(SHORTER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + time.sleep(SHORTER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(LONGER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + helper.wait_output("pwrbtn=LOW", timeout=1) + helper.wait_output("pwrbtn=HIGH", timeout=1) + if not check_no_output(helper, "pwrbtn=LOW"): + return False + + helper.trace("Hold down power button, wait for power button press\n" + + "sent out. Then relase for SHORTER_THAN_T0, check power\n" + + "button release is not sent out. Expect power button is\n" + + "treated as hold (ignoring the relase bounce)\n") + helper.ec_command("gpiomock POWER_BUTTONn 0") + helper.wait_output("pwrbtn=LOW", timeout=1) + helper.ec_command("gpiomock POWER_BUTTONn 1") + time.sleep(SHORTER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 0") + if not check_no_output(helper, "PB released"): + return False + helper.ec_command("gpiomock POWER_BUTTONn 1") + helper.wait_output("PB released", timeout=1) + + helper.trace("When system is off, hold down power button for\n" + + "LONGER_THAN_T0. Check the initial is stretched\n") + consume_output(helper, "pwrbtn=") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(LONGER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + t_low = helper.wait_output("\[(?P[\d\.]+) PB PCH pwrbtn=LOW\]", + use_re=True)["t"] + t_high = helper.wait_output("\[(?P[\d\.]+) PB PCH pwrbtn=HIGH\]", + use_re=True)["t"] + if not check_no_output(helper, "pwrbtn=LOW"): + return False + if float(t_high) - float(t_low) <= LONGER_THAN_T0 - 0.1: + return False + + helper.trace("When system is off, hold down power button for\n" + + "LONGER_THAN_T0. Check no scan code is send\n") + consume_output(helper, "i8042 SEND") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(LONGER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + if not check_no_output(helper, "i8042 SEND"): + return False + + helper.trace("While powered on, hold down power button for\n" + + "LONGER_THAN_T0. A single short pulse should be sent\n") + consume_output(helper, "pwrbtn=") + helper.ec_command("powermock on") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(LONGER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + t_low = helper.wait_output("\[(?P[\d\.]+) PB PCH pwrbtn=LOW\]", + use_re=True)["t"] + t_high = helper.wait_output("\[(?P[\d\.]+) PB PCH pwrbtn=HIGH\]", + use_re=True)["t"] + if not check_no_output(helper, "pwrbtn=LOW"): + return False + if float(t_high) - float(t_low) >= 0.1: + return False + + helper.trace("While powered on, hold down power button for\n" + + "LONGER_THAN_T0. Scan code should be sent\n") + consume_output(helper, "i8042 SEND") + helper.ec_command("gpiomock POWER_BUTTONn 0") + helper.wait_output("i8042 SEND", timeout=1) # Expect make code + time.sleep(LONGER_THAN_T0) + helper.ec_command("gpiomock POWER_BUTTONn 1") + helper.wait_output("i8042 SEND", timeout=1) # Expect release code + + helper.trace("While powered on, hold down power button for\n" + + "LONGER_THAN_T1 and check two presses are sent out\n") + consume_output(helper, "pwrbtn=") + helper.ec_command("gpiomock POWER_BUTTONn 0") + time.sleep(LONGER_THAN_T1) + helper.ec_command("gpiomock POWER_BUTTONn 1") + helper.wait_output("pwrbtn=LOW", timeout=1) + helper.wait_output("pwrbtn=HIGH", timeout=1) + helper.wait_output("pwrbtn=LOW", timeout=1) + helper.wait_output("pwrbtn=HIGH", timeout=1) + if not check_no_output(helper, "pwrbtn=LOW"): + return False + + return True # PASS ! diff --git a/test/power_button.tasklist b/test/power_button.tasklist new file mode 100644 index 0000000000..293d200041 --- /dev/null +++ b/test/power_button.tasklist @@ -0,0 +1,24 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** + * List of enabled tasks in the priority order + * + * The first one has the lowest priority. + * + * For each task, use the macro TASK(n, r, d) where : + * 'n' in the name of the task + * 'r' in the main routine of the task + * 'd' in an opaque parameter passed to the routine at startup + */ +#define CONFIG_TASK_LIST \ + TASK(WATCHDOG, watchdog_task, NULL) \ + TASK(PWM, pwm_task, NULL) \ + TASK(TYPEMATIC, keyboard_typematic_task, NULL) \ + TASK(X86POWER, x86_power_task, NULL) \ + TASK(I8042CMD, i8042_command_task, NULL) \ + TASK(POWERBTN, power_button_task, NULL) \ + TASK(KEYSCAN, keyboard_scan_task, NULL) \ + TASK(CONSOLE, console_task, NULL)