summaryrefslogtreecommitdiff
path: root/common/host_command.c
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2012-08-22 14:46:37 +0100
committerGerrit <chrome-bot@google.com>2012-09-10 16:17:13 -0700
commitd392ed7266e239758440830f04dbd0200461ce45 (patch)
tree12ceb9489c5573657726ae9d6637ee6d7b3c9542 /common/host_command.c
parentf4ff90502735102f1fbb68071d430229cb02b5af (diff)
downloadchrome-ec-d392ed7266e239758440830f04dbd0200461ce45.tar.gz
Move pending command logic into host_command
This logic doesn't really belong in drivers, since to enable another driver (like SPI) we must repeat it all. This is tricky if we enable both I2C and SPI. Move the logic into host_command. BUG=chrome-os-partner:10533 BRANCH=none TEST=manual Use U-Boot to test comms status functionality on snow: SMDK5250 # mkbp write rw 40000000 SMDK5250 # mkbp erase rw SMDK5250 # mkbp erase rw Change-Id: I3f90aada80208cd0540be14525f73f980ad33292 Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/32075 Reviewed-by: David Hendricks <dhendrix@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'common/host_command.c')
-rw-r--r--common/host_command.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/common/host_command.c b/common/host_command.c
index 389bb537de..6a872de508 100644
--- a/common/host_command.c
+++ b/common/host_command.c
@@ -31,6 +31,17 @@ static uint8_t host_memmap[EC_MEMMAP_SIZE];
static int hcdebug; /* Enable extra host command debug output */
+#ifdef CONFIG_HOST_COMMAND_STATUS
+/*
+ * Indicates that a 'slow' command has sent EC_RES_IN_PROGRESS but hasn't
+ * sent a final status (i.e. it is in progress)
+ */
+static uint8_t command_pending;
+
+/* The result of the last 'slow' operation */
+static uint8_t saved_result = EC_RES_UNAVAILABLE;
+#endif
+
uint8_t *host_get_memmap(int offset)
{
#ifdef CONFIG_LPC
@@ -42,6 +53,49 @@ uint8_t *host_get_memmap(int offset)
void host_send_response(struct host_cmd_handler_args *args)
{
+#ifdef CONFIG_HOST_COMMAND_STATUS
+ /*
+ * TODO(sjg@chromium.org):
+ * If we got an 'in progress' previously, then this
+ * must be the completion of that command, so stash the result
+ * code. We can't send it back to the host now since we already sent
+ * the in-progress response and the host is on to other things now.
+ *
+ * If we are in interrupt context, then we are handling a
+ * get_status response or an immediate error which prevented us
+ * from processing the command. Note we can't check for the
+ * GET_COMMS_STATUS command in args->command because the original
+ * command value has now been overwritten.
+ *
+ * When a EC_CMD_RESEND_RESPONSE arrives we will supply this response
+ * to that command.
+ *
+ * We don't support stashing response data, so mark the response as
+ * unavailable in that case.
+ *
+ * TODO(sjg@chromium.org): If we stashed the command in host_command
+ * before processing it, then it would not get overwritten by a
+ * subsequent command and we could simplify the logic here by adding
+ * a flag to host_cmd_handler_args to indicate that the command had
+ * an interim response. We would have to make this stashing dependent
+ * on CONFIG_HOST_COMMAND_STATUS also.
+ */
+ if (!in_interrupt_context()) {
+ if (command_pending) {
+ CPRINTF("pending complete, size=%d, result=%d\n",
+ args->response_size, args->result);
+ if (args->response_size != 0)
+ saved_result = EC_RES_UNAVAILABLE;
+ else
+ saved_result = args->result;
+ command_pending = 0;
+ return;
+ } else if (args->result == EC_RES_IN_PROGRESS) {
+ command_pending = 1;
+ CPRINTF("Command pending\n");
+ }
+ }
+#endif
args->send_response(args);
}
@@ -60,16 +114,23 @@ void host_command_received(struct host_cmd_handler_args *args)
args->result = EC_RES_ERROR;
}
- /* If the driver has signalled an error, send the response now */
if (args->result) {
- host_send_response(args);
+ ; /* driver has signalled an error, respond now */
+#ifdef CONFIG_HOST_COMMAND_STATUS
+ } else if (args->command == EC_CMD_GET_COMMS_STATUS) {
+ args->result = host_command_process(args);
+#endif
} else {
/* Save the command */
pending_args = args;
/* Wake up the task to handle the command */
task_set_event(TASK_ID_HOSTCMD, TASK_EVENT_CMD_PENDING, 0);
+ return;
}
+
+ /* Send the response now */
+ host_send_response(args);
}
/*
@@ -214,6 +275,39 @@ enum ec_status host_command_process(struct host_cmd_handler_args *args)
return rv;
}
+#ifdef CONFIG_HOST_COMMAND_STATUS
+/* Returns current command status (busy or not) */
+static int host_command_get_comms_status(struct host_cmd_handler_args *args)
+{
+ struct ec_response_get_comms_status *r = args->response;
+
+ r->flags = command_pending ? EC_COMMS_STATUS_PROCESSING : 0;
+ args->response_size = sizeof(*r);
+
+ return EC_SUCCESS;
+}
+
+DECLARE_HOST_COMMAND(EC_CMD_GET_COMMS_STATUS,
+ host_command_get_comms_status,
+ EC_VER_MASK(0));
+
+/* Resend the last saved response */
+static int host_command_resend_response(struct host_cmd_handler_args *args)
+{
+ /* Handle resending response */
+ args->result = saved_result;
+ args->response_size = 0;
+
+ saved_result = EC_RES_UNAVAILABLE;
+
+ return EC_SUCCESS;
+}
+
+DECLARE_HOST_COMMAND(EC_CMD_RESEND_RESPONSE,
+ host_command_resend_response,
+ EC_VER_MASK(0));
+#endif /* CONFIG_HOST_COMMAND_STATUS */
+
/*****************************************************************************/
/* Initialization / task */