diff options
author | pandeyan <anshuman.pandey@intel.com> | 2020-01-31 12:03:17 +0530 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-17 10:59:27 +0000 |
commit | e5e676f641dec32ddf4b32d1b8f4f9636e31ff2a (patch) | |
tree | 70ff7dda81a04ab75e1f402847230d302343050c | |
parent | c0bc2333b28bfad368768292fa84808bfb9cf954 (diff) | |
download | chrome-ec-e5e676f641dec32ddf4b32d1b8f4f9636e31ff2a.tar.gz |
Button: add ectool command to simulate button press
Added a new ectool command 'ectool button' for simulating
volume up and volume down button operations along with the duration
in milli-seconds for which button needs to be pressed.
BUG=b:149659987
BRANCH=None
TEST=Tested on hatch board.
From Kernel console, entered the below commands:
$ectool button vup 500
Observed volume UP key press on EC console.
Change-Id: I6fcdf80ea45b80403f72af89ce99214226731d0f
Signed-off-by: pandeyan <anshuman.pandey@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2059929
Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r-- | common/button.c | 133 | ||||
-rw-r--r-- | include/button.h | 18 | ||||
-rw-r--r-- | include/config.h | 8 | ||||
-rw-r--r-- | include/ec_commands.h | 37 | ||||
-rw-r--r-- | util/ectool.c | 55 |
5 files changed, 188 insertions, 63 deletions
diff --git a/common/button.c b/common/button.c index 8cbdd50e5a..b800302d32 100644 --- a/common/button.c +++ b/common/button.c @@ -5,6 +5,7 @@ /* Button module for Chrome EC */ +#include "atomic.h" #include "button.h" #include "chipset.h" #include "common.h" @@ -33,8 +34,15 @@ static struct button_state_t __bss_slow state[BUTTON_COUNT]; static uint64_t __bss_slow next_deferred_time; -#ifdef CONFIG_CMD_BUTTON -static int siml_btn_presd; +#if defined(CONFIG_CMD_BUTTON) || defined(CONFIG_HOSTCMD_BUTTON) +#define CONFIG_SIMULATED_BUTTON +#endif + +#ifdef CONFIG_SIMULATED_BUTTON +/* Bitmask to keep track of simulated state of each button. + * Bit numbers are aligned to enum button. + */ +static int sim_button_state; /* * Flip state of associated button type in sim_button_state bitmask. @@ -53,18 +61,7 @@ static int siml_btn_presd; */ static int simulated_button_pressed(const struct button_config *button) { - /* bitmask to keep track of simulated state of each button */ - static int sim_button_state; - int button_mask = 1 << button->type; - int ret_val; - - /* flip the state of the button */ - sim_button_state = sim_button_state ^ button_mask; - ret_val = !!(sim_button_state & button_mask); - /* adjustment for active high/lo */ - if (!(button->flags & BUTTON_FLAG_ACTIVE_HIGH)) - ret_val = !ret_val; - return ret_val; + return !!(sim_button_state & BIT(button->type)); } #endif @@ -73,14 +70,14 @@ static int simulated_button_pressed(const struct button_config *button) */ static int raw_button_pressed(const struct button_config *button) { - int raw_value = -#ifdef CONFIG_CMD_BUTTON - siml_btn_presd ? - simulated_button_pressed(button) : + int physical_value = (!!gpio_get_level(button->gpio) == + !!(button->flags & BUTTON_FLAG_ACTIVE_HIGH)); + int simulated_value = 0; +#ifdef CONFIG_SIMULATED_BUTTON + simulated_value = simulated_button_pressed(button); #endif - gpio_get_level(button->gpio); - return button->flags & BUTTON_FLAG_ACTIVE_HIGH ? - raw_value : !raw_value; + + return (simulated_value || physical_value); } #ifdef CONFIG_BUTTON_TRIGGERED_RECOVERY @@ -324,7 +321,7 @@ void button_interrupt(enum gpio_signal signal) } } -#ifdef CONFIG_CMD_BUTTON +#ifdef CONFIG_SIMULATED_BUTTON static int button_present(enum keyboard_button_type type) { int i; @@ -339,17 +336,54 @@ static int button_present(enum keyboard_button_type type) static void button_interrupt_simulate(int button) { button_interrupt(buttons[button].gpio); - usleep(buttons[button].debounce_us >> 2); - button_interrupt(buttons[button].gpio); } +static void simulate_button_release_deferred(void) +{ + int button_idx; + + /* Release the button */ + for (button_idx = 0; button_idx < BUTTON_COUNT; button_idx++) { + /* Check state for button pressed */ + if (sim_button_state & BIT(buttons[button_idx].type)) { + /* Set state of the button as released */ + atomic_clear(&sim_button_state, + BIT(buttons[button_idx].type)); + + button_interrupt_simulate(button_idx); + } + } +} +DECLARE_DEFERRED(simulate_button_release_deferred); + +static void simulate_button(uint32_t button_mask, int press_ms) +{ + int button_idx; + + /* Press the button */ + for (button_idx = 0; button_idx < BUTTON_COUNT; button_idx++) { + if (button_mask & BIT(button_idx)) { + /* Set state of the button as pressed */ + atomic_or(&sim_button_state, + BIT(buttons[button_idx].type)); + + button_interrupt_simulate(button_idx); + } + } + + /* Defer the button release for specified duration */ + hook_call_deferred(&simulate_button_release_deferred_data, + press_ms * MSEC); +} +#endif /* #ifdef CONFIG_SIMULATED_BUTTON */ + +#ifdef CONFIG_CMD_BUTTON static int console_command_button(int argc, char **argv) { int press_ms = 50; char *e; int argv_idx; - int button; - int button_idx; + int button = BUTTON_COUNT; uint32_t button_mask = 0; if (argc < 2) @@ -382,32 +416,39 @@ static int console_command_button(int argc, char **argv) if (!button_mask) return EC_SUCCESS; - siml_btn_presd = 1; + simulate_button(button_mask, press_ms); - /* Press the button(s) */ - for (button_idx = 0; button_idx < BUTTON_COUNT; button_idx++) - if (button_mask & BIT(button_idx)) - button_interrupt_simulate(button_idx); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(button, console_command_button, + "vup|vdown|rec msec", + "Simulate button press"); +#endif /* CONFIG_CMD_BUTTON */ - /* Hold the button(s) */ - if (press_ms > 0) - msleep(press_ms); +#ifdef CONFIG_HOSTCMD_BUTTON +static enum ec_status host_command_button(struct host_cmd_handler_args *args) +{ + const struct ec_params_button *p = args->params; + int idx; + uint32_t button_mask = 0; - /* Release the button(s) */ - for (button_idx = 0; button_idx < BUTTON_COUNT; button_idx++) - if (button_mask & BIT(button_idx)) - button_interrupt_simulate(button_idx); + /* Only available on unlocked systems */ + if (system_is_locked()) + return EC_RES_ACCESS_DENIED; - /* Wait till button processing is finished */ - msleep(100); + for (idx = 0; idx < KEYBOARD_BUTTON_COUNT; idx++) { + if (p->btn_mask & BIT(idx)) + button_mask |= BIT(button_present(idx)); + } - siml_btn_presd = 0; - return EC_SUCCESS; + simulate_button(button_mask, p->press_ms); + + return EC_RES_SUCCESS; } -DECLARE_CONSOLE_COMMAND(button, console_command_button, - "vup|vdown msec", - "Simulate button press"); -#endif +DECLARE_HOST_COMMAND(EC_CMD_BUTTON, host_command_button, EC_VER_MASK(0)); + +#endif /* CONFIG_HOSTCMD_BUTTON */ + #ifdef CONFIG_EMULATED_SYSRQ diff --git a/include/button.h b/include/button.h index 5f6ffe11c6..bbe4cb44df 100644 --- a/include/button.h +++ b/include/button.h @@ -11,28 +11,12 @@ #include "common.h" #include "compile_time_macros.h" #include "gpio.h" +#include "ec_commands.h" #define BUTTON_FLAG_ACTIVE_HIGH BIT(0) #define BUTTON_DEBOUNCE_US (30 * MSEC) -enum keyboard_button_type { - KEYBOARD_BUTTON_POWER = 0, - KEYBOARD_BUTTON_VOLUME_DOWN, - KEYBOARD_BUTTON_VOLUME_UP, - KEYBOARD_BUTTON_RECOVERY, - KEYBOARD_BUTTON_CAPSENSE_1, - KEYBOARD_BUTTON_CAPSENSE_2, - KEYBOARD_BUTTON_CAPSENSE_3, - KEYBOARD_BUTTON_CAPSENSE_4, - KEYBOARD_BUTTON_CAPSENSE_5, - KEYBOARD_BUTTON_CAPSENSE_6, - KEYBOARD_BUTTON_CAPSENSE_7, - KEYBOARD_BUTTON_CAPSENSE_8, - - KEYBOARD_BUTTON_COUNT -}; - struct button_config { const char *name; enum keyboard_button_type type; diff --git a/include/config.h b/include/config.h index ad38af54d8..45ca08e6da 100644 --- a/include/config.h +++ b/include/config.h @@ -732,6 +732,14 @@ */ #undef CONFIG_BUTTONS_RUNTIME_CONFIG +/* Support simulation of a button press using EC tool command */ +#undef CONFIG_HOSTCMD_BUTTON +/* + * Configuration for button simulation i.e. dependent on + * CONFIG_HOSTCMD_BUTTON or CONFIG_CMD_BUTTON config. + */ +#undef CONFIG_SIMULATED_BUTTON + /* * Capsense chip has buttons, too. */ diff --git a/include/ec_commands.h b/include/ec_commands.h index 530b6cb2d4..5d7dd1926c 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -6013,6 +6013,43 @@ struct ec_response_get_pd_port_caps { } __ec_align1; /*****************************************************************************/ +/* + * Button press simulation + * + * This command is used to simulate a button press. + * Supported commands are vup(volume up) vdown(volume down) & rec(recovery) + * Time duration for which button needs to be pressed is an optional parameter. + * + * NOTE: This is only available on unlocked devices for testing purposes only. + */ +#define EC_CMD_BUTTON 0x0129 + +struct ec_params_button { + /* Button mask aligned to enum keyboard_button_type */ + uint32_t btn_mask; + + /* Duration in milliseconds button needs to be pressed */ + uint32_t press_ms; +} __ec_align1; + +enum keyboard_button_type { + KEYBOARD_BUTTON_POWER = 0, + KEYBOARD_BUTTON_VOLUME_DOWN = 1, + KEYBOARD_BUTTON_VOLUME_UP = 2, + KEYBOARD_BUTTON_RECOVERY = 3, + KEYBOARD_BUTTON_CAPSENSE_1 = 4, + KEYBOARD_BUTTON_CAPSENSE_2 = 5, + KEYBOARD_BUTTON_CAPSENSE_3 = 6, + KEYBOARD_BUTTON_CAPSENSE_4 = 7, + KEYBOARD_BUTTON_CAPSENSE_5 = 8, + KEYBOARD_BUTTON_CAPSENSE_6 = 9, + KEYBOARD_BUTTON_CAPSENSE_7 = 10, + KEYBOARD_BUTTON_CAPSENSE_8 = 11, + + KEYBOARD_BUTTON_COUNT +}; + +/*****************************************************************************/ /* The command range 0x200-0x2FF is reserved for Rotor. */ /*****************************************************************************/ diff --git a/util/ectool.c b/util/ectool.c index c521f94900..c04fddb4c6 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -80,6 +80,8 @@ const char help_str[] = " Read or write board-specific battery parameter\n" " boardversion\n" " Prints the board version\n" + " button [vup|vdown|rec] <Delay-ms>\n" + " Simulates button press.\n" " cbi\n" " Get/Set Cros Board Info\n" " chargecurrentlimit\n" @@ -1106,6 +1108,58 @@ int cmd_reboot_ap_on_g3(int argc, char *argv[]) return (rv < 0 ? rv : 0); } +int cmd_button(int argc, char *argv[]) +{ + struct ec_params_button p; + char *e; + int argv_idx; + int button = KEYBOARD_BUTTON_COUNT; + int rv; + + if (argc < 2) { + fprintf(stderr, "Invalid num param %d.\n", argc); + return -1; + } + + p.press_ms = 50; + p.btn_mask = 0; + + for (argv_idx = 1; argv_idx < argc; argv_idx++) { + if (!strcasecmp(argv[argv_idx], "vup")) + button = KEYBOARD_BUTTON_VOLUME_UP; + else if (!strcasecmp(argv[argv_idx], "vdown")) + button = KEYBOARD_BUTTON_VOLUME_DOWN; + else if (!strcasecmp(argv[argv_idx], "rec")) + button = KEYBOARD_BUTTON_RECOVERY; + else { + /* If last parameter check if it is an integer. */ + if (argv_idx == argc - 1) { + p.press_ms = strtol(argv[argv_idx], &e, 0); + /* If integer, break out of the loop. */ + if (!*e) + break; + } + button = KEYBOARD_BUTTON_COUNT; + } + + if (button == KEYBOARD_BUTTON_COUNT) { + fprintf(stderr, "Invalid button input.\n"); + return -1; + } + + p.btn_mask |= (1 << button); + } + if (!p.btn_mask) + return 0; + + rv = ec_command(EC_CMD_BUTTON, 0, &p, sizeof(p), NULL, 0); + if (rv < 0) + return rv; + + printf("Button(s) %d set to %d ms\n", p.btn_mask, p.press_ms); + return 0; +} + int cmd_flash_info(int argc, char *argv[]) { struct ec_response_flash_info_1 r; @@ -9428,6 +9482,7 @@ const struct command commands[] = { {"batterycutoff", cmd_battery_cut_off}, {"batteryparam", cmd_battery_vendor_param}, {"boardversion", cmd_board_version}, + {"button", cmd_button}, {"cbi", cmd_cbi}, {"chargecurrentlimit", cmd_charge_current_limit}, {"chargecontrol", cmd_charge_control}, |