summaryrefslogtreecommitdiff
path: root/common/host_command.c
diff options
context:
space:
mode:
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 */