summaryrefslogtreecommitdiff
path: root/common/console.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2011-12-07 18:51:09 +0000
committerVincent Palatin <vpalatin@chromium.org>2011-12-07 19:10:02 +0000
commitbdf7da5b082f6d18dd27f1e5d8cca0b12154a28c (patch)
tree6f14312a6cc70d056efc2bede8728c0868266719 /common/console.c
parentabe5786058f4b60dc6d30e7d7c964aae850caa1f (diff)
downloadchrome-ec-bdf7da5b082f6d18dd27f1e5d8cca0b12154a28c.tar.gz
Initial sources import 1/3
source files mainly done by Randall. Signed-off-by: Randall Spangler <rspangler@chromium.org> Change-Id: Iaff83a842b17f3350fb6f2a3f1597ad4c29bd12a
Diffstat (limited to 'common/console.c')
-rw-r--r--common/console.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/common/console.c b/common/console.c
new file mode 100644
index 0000000000..bc558f5cf4
--- /dev/null
+++ b/common/console.c
@@ -0,0 +1,207 @@
+/* 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.
+ */
+
+/* Console module for Chrome EC */
+
+#include "console.h"
+#include "task.h"
+#include "uart.h"
+#include "registers.h"
+#include "util.h"
+
+#define MAX_COMMAND_GROUPS 20
+#define MAX_ARGS_PER_COMMAND 10
+
+#define PROMPT "> "
+
+static const struct console_group *group_list[MAX_COMMAND_GROUPS];
+static int group_count = 0;
+
+
+void console_has_input(void)
+{
+ /* Wake up the console task */
+ task_send_msg(TASK_ID_CONSOLE, TASK_ID_CONSOLE, 0);
+}
+
+
+int console_register_commands(const struct console_group *group)
+{
+ if (group_count >= MAX_COMMAND_GROUPS)
+ return EC_ERROR_OVERFLOW;
+
+ group_list[group_count++] = group;
+ return EC_SUCCESS;
+}
+
+
+/* Splits a line of input into words. Stores the count of words in
+ * <argc>. Stores pointers to the words in <argv>, which must be at
+ * least <max_argc> long. If more than <max_argc> words are found,
+ * discards the excess and returns EC_ERROR_OVERFLOW. */
+int split_words(char *input, int max_argc, int *argc, char **argv)
+{
+ char *c;
+ int in_word = 0;
+
+ /* Parse input into words */
+ *argc = 0;
+ for (c = input; *c; c++) {
+ if (isspace(*c)) {
+ if (in_word) {
+ /* Ending a word */
+ *c = '\0';
+ ++*argc;
+ in_word = 0;
+ }
+ } else if (*c == '#') {
+ /* After the hash sign is comment, ignored.
+ * TODO: Need more logic to suuport escaping. */
+ break;
+ } else {
+ if (!in_word) {
+ /* Starting a new word */
+ if (*argc >= max_argc)
+ return EC_ERROR_OVERFLOW;
+
+ argv[*argc] = c;
+ in_word = 1;
+ }
+ }
+ }
+ return EC_SUCCESS;
+}
+
+
+/* Finds a command by name. Returns the command structure, or NULL if
+ * no match found. */
+const struct console_command *find_command(char *name)
+{
+ const struct console_command *cmd;
+ int c, g;
+
+ /* Find the command in the command groups */
+ for (g = 0; g < group_count; g++) {
+ cmd = group_list[g]->commands;
+ for (c = group_list[g]->command_count; c > 0; c--, cmd++) {
+ if (!strcasecmp(name, cmd->name))
+ return cmd;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* Handles a line of input containing a single command.
+ *
+ * Modifies the input string during parsing. */
+static int handle_command(char *input)
+{
+ const struct console_command *cmd;
+ char *argv[MAX_ARGS_PER_COMMAND];
+ int argc = 0;
+
+ /* Split input into words. Ignore words past our limit. */
+ split_words(input, MAX_ARGS_PER_COMMAND, &argc, argv);
+
+ /* If no command, nothing to do */
+ if (!argc)
+ return EC_SUCCESS;
+
+ cmd = find_command(argv[0]);
+ if (cmd)
+ return cmd->handler(argc, argv);
+
+ uart_printf("Command '%s' not found.\n", argv[0]);
+ return EC_ERROR_UNKNOWN;
+}
+
+
+static char last_input[80];
+static char input_buf[80];
+
+/* handle a console command */
+void console_process(void)
+{
+ int rv;
+
+ /* Process all the pending commands. Need to do this all at once
+ * since our interrupt may have been triggered multiple times. */
+ /* TODO: Go to sleep briefly between commands to give lower
+ * priority tasks a chance to run? */
+ while (uart_peek('\n') >= 0) {
+ uart_gets(input_buf, sizeof(input_buf));
+
+ /* "." repeats the last command, if any */
+ if (!strcasecmp(input_buf, ".\n"))
+ strzcpy(input_buf, last_input, sizeof(input_buf));
+ else if (!isspace(*input_buf))
+ strzcpy(last_input, input_buf, sizeof(last_input));
+
+ rv = handle_command(input_buf);
+ if (rv != EC_SUCCESS)
+ uart_printf("Command returned error %d\n", rv);
+ uart_puts(PROMPT);
+ }
+}
+
+void console_task(void)
+{
+ console_init();
+
+ while (1) {
+ console_process();
+ /* wait for the next command message */
+ task_wait_msg(-1);
+ }
+}
+
+/*****************************************************************************/
+/* Console commands */
+
+/* Command handler - prints help. */
+static int command_help(int argc, char **argv)
+{
+ const struct console_command *cmd;
+ int c, g;
+
+ uart_puts("Known commands:\n");
+
+ for (g = 0; g < group_count; g++) {
+ cmd = group_list[g]->commands;
+ uart_printf("Group %s:\n", group_list[g]->group_name);
+ for (c = group_list[g]->command_count; c > 0; c--, cmd++)
+ uart_printf(" %s\n", cmd->name);
+ /* Generates enough output to overflow the buffer */
+ uart_flush_output();
+ }
+
+ uart_puts("'.' repeats the last command.\n");
+
+ return EC_SUCCESS;
+}
+
+static const struct console_command console_commands[] = {
+ {"help", command_help},
+ {"?", command_help},
+};
+static const struct console_group command_group = {
+ "Console", console_commands, ARRAY_SIZE(console_commands)
+};
+
+/*****************************************************************************/
+/* Initialization */
+
+int console_init(void)
+{
+ *last_input = '\0';
+ *input_buf = '\0';
+ uart_set_console_mode(1);
+ uart_printf("Console is enabled; type HELP for help.\n");
+ uart_puts(PROMPT);
+ /* Register our internal commands */
+ return console_register_commands(&command_group);
+}