1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2023 Linaro Ltd.
4 *   Author: Caleb Connolly <caleb.connolly@linaro.org>
5 */
6
7#include <button.h>
8#include <command.h>
9#include <env.h>
10#include <log.h>
11#include <vsprintf.h>
12
13/* Some sane limit "just in case" */
14#define MAX_BTN_CMDS 32
15
16struct button_cmd {
17	bool pressed;
18	const char *btn_name;
19	const char *cmd;
20};
21
22/*
23 * Button commands are set via environment variables, e.g.:
24 * button_cmd_N_name=Volume Up
25 * button_cmd_N=fastboot usb 0
26 *
27 * This function will retrieve the command for the given button N
28 * and populate the cmd struct with the command string and pressed
29 * state of the button.
30 *
31 * Returns 1 if a command was found, 0 otherwise.
32 */
33static int get_button_cmd(int n, struct button_cmd *cmd)
34{
35	const char *cmd_str;
36	struct udevice *btn = NULL;
37	char buf[24];
38
39	snprintf(buf, sizeof(buf), "button_cmd_%d_name", n);
40	cmd->btn_name = env_get(buf);
41	if (!cmd->btn_name)
42		return 0;
43
44	button_get_by_label(cmd->btn_name, &btn);
45	if (!btn) {
46		log_err("No button labelled '%s'\n", cmd->btn_name);
47		return 0;
48	}
49
50	cmd->pressed = button_get_state(btn) == BUTTON_ON;
51	/* If the button isn't pressed then cmd->cmd will be unused so don't waste
52	 * cycles reading it
53	 */
54	if (!cmd->pressed)
55		return 1;
56
57	snprintf(buf, sizeof(buf), "button_cmd_%d", n);
58	cmd_str = env_get(buf);
59	if (!cmd_str) {
60		log_err("No command set for button '%s'\n", cmd->btn_name);
61		return 0;
62	}
63
64	cmd->cmd = cmd_str;
65
66	return 1;
67}
68
69void process_button_cmds(void)
70{
71	struct button_cmd cmd = {0};
72	int i = 0;
73
74	while (get_button_cmd(i++, &cmd) && i < MAX_BTN_CMDS) {
75		if (!cmd.pressed)
76			continue;
77
78		log_info("BTN '%s'> %s\n", cmd.btn_name, cmd.cmd);
79		run_command(cmd.cmd, CMD_FLAG_ENV);
80		/* Don't run commands for multiple buttons */
81		return;
82	}
83}
84