diff --git a/boot/Kconfig b/boot/Kconfig index 71ee41645f..3d7aabd27d 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -20,6 +20,21 @@ config TIMESTAMP loaded that does not, the message 'Wrong FIT format: no timestamp' is shown. +config BUTTON_CMD + bool "Support for running a command if a button is held during boot" + depends on CMDLINE + depends on BUTTON + help + For many embedded devices it's useful to enter a special flashing mode + such as fastboot mode when a button is held during boot. This option + allows arbitrary commands to be assigned to specific buttons. These will + be run after "preboot" if the button is held. Configuration is done via + the environment variables "button_cmd_N_name" and "button_cmd_N" where n is + the button number (starting from 0). e.g: + + "button_cmd_0_name=vol_down" + "button_cmd_0=fastboot usb 0" + menuconfig FIT bool "Flattened Image Tree (FIT)" select HASH diff --git a/common/Makefile b/common/Makefile index f010c2a1b9..e983547342 100644 --- a/common/Makefile +++ b/common/Makefile @@ -12,6 +12,7 @@ obj-y += cli_getch.o cli_simple.o cli_readline.o obj-$(CONFIG_HUSH_OLD_PARSER) += cli_hush.o obj-$(CONFIG_HUSH_MODERN_PARSER) += cli_hush_modern.o obj-$(CONFIG_AUTOBOOT) += autoboot.o +obj-$(CONFIG_BUTTON_CMD) += button_cmd.o obj-y += version.o # # boards diff --git a/common/button_cmd.c b/common/button_cmd.c new file mode 100644 index 0000000000..b6a8434d6f --- /dev/null +++ b/common/button_cmd.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 Linaro Ltd. + * Author: Caleb Connolly + */ + +#include +#include +#include +#include +#include + +/* Some sane limit "just in case" */ +#define MAX_BTN_CMDS 32 + +struct button_cmd { + bool pressed; + const char *btn_name; + const char *cmd; +}; + +/* + * Button commands are set via environment variables, e.g.: + * button_cmd_N_name=Volume Up + * button_cmd_N=fastboot usb 0 + * + * This function will retrieve the command for the given button N + * and populate the cmd struct with the command string and pressed + * state of the button. + * + * Returns 1 if a command was found, 0 otherwise. + */ +static int get_button_cmd(int n, struct button_cmd *cmd) +{ + const char *cmd_str; + struct udevice *btn; + char buf[24]; + + snprintf(buf, sizeof(buf), "button_cmd_%d_name", n); + cmd->btn_name = env_get(buf); + if (!cmd->btn_name) + return 0; + + button_get_by_label(cmd->btn_name, &btn); + if (!btn) { + log_err("No button labelled '%s'\n", cmd->btn_name); + return 0; + } + + cmd->pressed = button_get_state(btn) == BUTTON_ON; + /* If the button isn't pressed then cmd->cmd will be unused so don't waste + * cycles reading it + */ + if (!cmd->pressed) + return 1; + + snprintf(buf, sizeof(buf), "button_cmd_%d", n); + cmd_str = env_get(buf); + if (!cmd_str) { + log_err("No command set for button '%s'\n", cmd->btn_name); + return 0; + } + + cmd->cmd = cmd_str; + + return 1; +} + +void process_button_cmds(void) +{ + struct button_cmd cmd = {0}; + int i = 0; + + while (get_button_cmd(i++, &cmd) && i < MAX_BTN_CMDS) { + if (!cmd.pressed) + continue; + + log_info("BTN '%s'> %s\n", cmd.btn_name, cmd.cmd); + run_command(cmd.cmd, CMD_FLAG_ENV); + /* Don't run commands for multiple buttons */ + return; + } +} diff --git a/common/main.c b/common/main.c index 6dba6cba14..82d3aafa53 100644 --- a/common/main.c +++ b/common/main.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -62,6 +63,8 @@ void main_loop(void) efi_launch_capsules(); } + process_button_cmds(); + s = bootdelay_process(); if (cli_process_fdt(&s)) cli_secure_boot_cmd(s); diff --git a/doc/usage/environment.rst b/doc/usage/environment.rst index 82b6ea7b6e..ebf75fa948 100644 --- a/doc/usage/environment.rst +++ b/doc/usage/environment.rst @@ -190,6 +190,10 @@ bootm_size bootstopkeysha256, bootdelaykey, bootstopkey See README.autoboot +button_cmd_0, button_cmd_0_name ... button_cmd_N, button_cmd_N_name + Used to map commands to run when a button is held during boot. + See CONFIG_BUTTON_CMD. + updatefile Location of the software update file on a TFTP server, used by the automatic software update feature. Please refer to diff --git a/include/button.h b/include/button.h index 207f4a0f4d..8d38e52132 100644 --- a/include/button.h +++ b/include/button.h @@ -74,4 +74,13 @@ enum button_state_t button_get_state(struct udevice *dev); */ int button_get_code(struct udevice *dev); +#if IS_ENABLED(CONFIG_BUTTON_CMD) +/* Process button command mappings specified in the environment, + * running the commands for buttons which are pressed + */ +void process_button_cmds(void); +#else +static inline void process_button_cmds(void) {} +#endif /* CONFIG_BUTTON_CMD */ + #endif