Line data Source code
1 0 : /*
2 : * Copyright (c) 2020 Google LLC
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : #ifndef ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_H_
8 : #define ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_H_
9 :
10 : /**
11 : * @brief EC Host Command Interface
12 : * @defgroup ec_host_cmd_interface EC Host Command Interface
13 : * @since 2.4
14 : * @version 0.1.0
15 : * @ingroup device_mgmt
16 : * @{
17 : */
18 :
19 : #include <stdint.h>
20 : #include <zephyr/kernel.h>
21 : #include <zephyr/mgmt/ec_host_cmd/backend.h>
22 : #include <zephyr/sys/__assert.h>
23 : #include <zephyr/sys/iterable_sections.h>
24 :
25 : /**
26 : * @brief Host command response codes (16-bit).
27 : */
28 0 : enum ec_host_cmd_status {
29 : /** Host command was successful. */
30 : EC_HOST_CMD_SUCCESS = 0,
31 : /** The specified command id is not recognized or supported. */
32 : EC_HOST_CMD_INVALID_COMMAND = 1,
33 : /** Generic Error. */
34 : EC_HOST_CMD_ERROR = 2,
35 : /** One of more of the input request parameters is invalid. */
36 : EC_HOST_CMD_INVALID_PARAM = 3,
37 : /** Host command is not permitted. */
38 : EC_HOST_CMD_ACCESS_DENIED = 4,
39 : /** Response was invalid (e.g. not version 3 of header). */
40 : EC_HOST_CMD_INVALID_RESPONSE = 5,
41 : /** Host command id version unsupported. */
42 : EC_HOST_CMD_INVALID_VERSION = 6,
43 : /** Checksum did not match. */
44 : EC_HOST_CMD_INVALID_CHECKSUM = 7,
45 : /** A host command is currently being processed. */
46 : EC_HOST_CMD_IN_PROGRESS = 8,
47 : /** Requested information is currently unavailable. */
48 : EC_HOST_CMD_UNAVAILABLE = 9,
49 : /** Timeout during processing. */
50 : EC_HOST_CMD_TIMEOUT = 10,
51 : /** Data or table overflow. */
52 : EC_HOST_CMD_OVERFLOW = 11,
53 : /** Header is invalid or unsupported (e.g. not version 3 of header). */
54 : EC_HOST_CMD_INVALID_HEADER = 12,
55 : /** Did not receive all expected request data. */
56 : EC_HOST_CMD_REQUEST_TRUNCATED = 13,
57 : /** Response was too big to send within one response packet. */
58 : EC_HOST_CMD_RESPONSE_TOO_BIG = 14,
59 : /** Error on underlying communication bus. */
60 : EC_HOST_CMD_BUS_ERROR = 15,
61 : /** System busy. Should retry later. */
62 : EC_HOST_CMD_BUSY = 16,
63 : /** Header version invalid. */
64 : EC_HOST_CMD_INVALID_HEADER_VERSION = 17,
65 : /** Header CRC invalid. */
66 : EC_HOST_CMD_INVALID_HEADER_CRC = 18,
67 : /** Data CRC invalid. */
68 : EC_HOST_CMD_INVALID_DATA_CRC = 19,
69 : /** Can't resend response. */
70 : EC_HOST_CMD_DUP_UNAVAILABLE = 20,
71 :
72 : EC_HOST_CMD_MAX = UINT16_MAX /* Force enum to be 16 bits. */
73 : } __packed;
74 :
75 : /**
76 : * @brief Host command log levels
77 : */
78 1 : enum ec_host_cmd_log_level {
79 : EC_HOST_CMD_DEBUG_OFF, /**< No Host Command debug output */
80 : EC_HOST_CMD_DEBUG_NORMAL, /**< Normal output mode; skips repeated commands */
81 : EC_HOST_CMD_DEBUG_EVERY, /**< Print every command */
82 : EC_HOST_CMD_DEBUG_PARAMS, /**< ... and print params for request/response */
83 : EC_HOST_CMD_DEBUG_MODES /**< Number of host command debug modes */
84 : };
85 :
86 : /**
87 : * @brief Host command state
88 : */
89 1 : enum ec_host_cmd_state {
90 : EC_HOST_CMD_STATE_DISABLED = 0, /**< Host command subsystem is disabled */
91 : EC_HOST_CMD_STATE_RECEIVING, /**< Receiving command data from host */
92 : EC_HOST_CMD_STATE_PROCESSING, /**< Processing received command */
93 : EC_HOST_CMD_STATE_SENDING, /**< Sending response to host */
94 : };
95 :
96 : /**
97 : * @brief User callback function type for host command reception
98 : *
99 : * This callback is invoked after a host command is received and validated
100 : * but before command processing begins. It allows user code to perform
101 : * custom actions based on the received command.
102 : *
103 : * @param rx_ctx Pointer to the receive context containing command data
104 : * @param user_data User-defined data pointer passed during callback registration
105 : */
106 1 : typedef void (*ec_host_cmd_user_cb_t)(const struct ec_host_cmd_rx_ctx *rx_ctx, void *user_data);
107 :
108 : /**
109 : * @brief In-progress callback function type
110 : *
111 : * This callback is executed asynchronously for commands that return
112 : * EC_HOST_CMD_IN_PROGRESS status. It allows long-running operations
113 : * to complete in the background.
114 : *
115 : * @param user_data User-provided data passed to the callback
116 : * @return Final status code for the command
117 : */
118 : typedef enum ec_host_cmd_status (*ec_host_cmd_in_progress_cb_t)(void *user_data);
119 :
120 : /**
121 : * Host command context structure
122 : */
123 1 : struct ec_host_cmd {
124 0 : struct ec_host_cmd_rx_ctx rx_ctx;
125 0 : struct ec_host_cmd_tx_buf tx;
126 0 : struct ec_host_cmd_backend *backend;
127 : /**
128 : * The backend gives rx_ready (by calling the ec_host_cmd_send_receive function),
129 : * when data in rx_ctx are ready. The handler takes rx_ready to read data in rx_ctx.
130 : */
131 1 : struct k_sem rx_ready;
132 : /** Status of the rx data checked in the ec_host_cmd_send_received function. */
133 1 : enum ec_host_cmd_status rx_status;
134 : /**
135 : * User callback after receiving a command. It is called by the ec_host_cmd_send_received
136 : * function.
137 : */
138 1 : ec_host_cmd_user_cb_t user_cb;
139 0 : void *user_data;
140 0 : enum ec_host_cmd_state state;
141 : #ifdef CONFIG_EC_HOST_CMD_DEDICATED_THREAD
142 : struct k_thread thread;
143 : #endif /* CONFIG_EC_HOST_CMD_DEDICATED_THREAD */
144 : };
145 :
146 : /**
147 : * @brief Arguments passed into every installed host command handler
148 : */
149 1 : struct ec_host_cmd_handler_args {
150 : /** Reserved for compatibility. */
151 1 : void *reserved;
152 : /** Command identifier. */
153 1 : uint16_t command;
154 : /**
155 : * The version of the host command that is being requested. This will
156 : * be a value that has been static registered as valid for the handler.
157 : */
158 1 : uint8_t version;
159 : /** The incoming data that can be cast to the handlers request type. */
160 1 : const void *input_buf;
161 : /** The number of valid bytes that can be read from @a input_buf. */
162 1 : uint16_t input_buf_size;
163 : /** The data written to this buffer will be send to the host. */
164 1 : void *output_buf;
165 : /** Maximum number of bytes that can be written to the @a output_buf. */
166 1 : uint16_t output_buf_max;
167 : /** Number of bytes of @a output_buf to send to the host. */
168 1 : uint16_t output_buf_size;
169 : };
170 :
171 : /**
172 : * @brief Host command handler callback function type
173 : *
174 : * This callback is invoked to process a host command that matches the handler's
175 : * command ID and version. The handler processes the incoming command data and
176 : * generates a response.
177 : *
178 : * @param args Pointer to an @ref ec_host_cmd_handler_args structure containing command data and
179 : * buffers
180 : * @return Status code indicating the result of command processing
181 : */
182 : typedef enum ec_host_cmd_status (*ec_host_cmd_handler_cb)(struct ec_host_cmd_handler_args *args);
183 :
184 : /**
185 : * @brief Structure use for statically registering host command handlers
186 : */
187 1 : struct ec_host_cmd_handler {
188 : /** Callback routine to process commands that match @a id. */
189 1 : ec_host_cmd_handler_cb handler;
190 : /** The numerical command id used as the lookup for commands. */
191 1 : uint16_t id;
192 : /**
193 : * The bitfield of all versions that the @a handler supports, where
194 : * each bit value represents that the @a handler supports that version.
195 : * E.g. BIT(0) corresponds to version 0.
196 : */
197 1 : uint16_t version_mask;
198 : /**
199 : * The minimum @a input_buf_size enforced by the framework before
200 : * passing to the handler.
201 : */
202 1 : uint16_t min_rqt_size;
203 : /**
204 : * The minimum @a output_buf_size enforced by the framework before
205 : * passing to the handler.
206 : */
207 1 : uint16_t min_rsp_size;
208 : };
209 :
210 : /**
211 : * @brief Statically define and register a host command handler.
212 : *
213 : * Helper macro to statically define and register a host command handler that
214 : * has a compile-time-fixed sizes for its both request and response structures.
215 : *
216 : * @param _id Id of host command to handle request for.
217 : * @param _function Name of handler function.
218 : * @param _version_mask The bitfield of all versions that the @a _function
219 : * supports. E.g. BIT(0) corresponds to version 0.
220 : * @param _request_type The datatype of the request parameters for @a _function.
221 : * @param _response_type The datatype of the response parameters for
222 : * @a _function.
223 : */
224 1 : #define EC_HOST_CMD_HANDLER(_id, _function, _version_mask, _request_type, _response_type) \
225 : const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \
226 : .handler = _function, \
227 : .id = _id, \
228 : .version_mask = _version_mask, \
229 : .min_rqt_size = sizeof(_request_type), \
230 : .min_rsp_size = sizeof(_response_type), \
231 : }
232 :
233 : /**
234 : * @brief Statically define and register a host command handler without sizes.
235 : *
236 : * Helper macro to statically define and register a host command handler whose
237 : * request or response structure size is not known as compile time.
238 : *
239 : * @param _id Id of host command to handle request for.
240 : * @param _function Name of handler function.
241 : * @param _version_mask The bitfield of all versions that the @a _function
242 : * supports. E.g. BIT(0) corresponds to version 0.
243 : */
244 1 : #define EC_HOST_CMD_HANDLER_UNBOUND(_id, _function, _version_mask) \
245 : const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \
246 : .handler = _function, \
247 : .id = _id, \
248 : .version_mask = _version_mask, \
249 : .min_rqt_size = 0, \
250 : .min_rsp_size = 0, \
251 : }
252 :
253 : /**
254 : * @brief Header for requests from host to embedded controller
255 : *
256 : * Represent the over-the-wire header in LE format for host command requests.
257 : * This represent version 3 of the host command header. The requests are always
258 : * sent from host to embedded controller.
259 : */
260 1 : struct ec_host_cmd_request_header {
261 : /**
262 : * Should be 3. The EC will return EC_HOST_CMD_INVALID_HEADER if it
263 : * receives a header with a version it doesn't know how to parse.
264 : */
265 1 : uint8_t prtcl_ver;
266 : /**
267 : * Checksum of response and data; sum of all bytes including checksum.
268 : * Should total to 0.
269 : */
270 1 : uint8_t checksum;
271 : /** Id of command that is being sent. */
272 1 : uint16_t cmd_id;
273 : /**
274 : * Version of the specific @a cmd_id being requested. Valid
275 : * versions start at 0.
276 : */
277 1 : uint8_t cmd_ver;
278 : /** Unused byte in current protocol version; set to 0. */
279 1 : uint8_t reserved;
280 : /** Length of data which follows this header. */
281 1 : uint16_t data_len;
282 : } __packed;
283 :
284 : /**
285 : * @brief Header for responses from embedded controller to host
286 : *
287 : * Represent the over-the-wire header in LE format for host command responses.
288 : * This represent version 3 of the host command header. Responses are always
289 : * sent from embedded controller to host.
290 : */
291 1 : struct ec_host_cmd_response_header {
292 : /** Should be 3. */
293 1 : uint8_t prtcl_ver;
294 : /**
295 : * Checksum of response and data; sum of all bytes including checksum.
296 : * Should total to 0.
297 : */
298 1 : uint8_t checksum;
299 : /** A @a ec_host_cmd_status response code for specific command. */
300 1 : uint16_t result;
301 : /** Length of data which follows this header. */
302 1 : uint16_t data_len;
303 : /** Unused bytes in current protocol version; set to 0. */
304 1 : uint16_t reserved;
305 : } __packed;
306 :
307 : /**
308 : * @brief Initialize the host command subsystem
309 : *
310 : * This routine initializes the host command subsystem. It includes initialization
311 : * of a backend and the handler.
312 : * When the application configures the zephyr,host-cmd-espi-backend/zephyr,host-cmd-shi-backend/
313 : * zephyr,host-cmd-uart-backend chosen node and @kconfig{CONFIG_EC_HOST_CMD_INITIALIZE_AT_BOOT} is
314 : * set, the chosen backend automatically calls this routine at
315 : * @kconfig{CONFIG_EC_HOST_CMD_INIT_PRIORITY}. Applications that require a run-time selection of the
316 : * backend must set @kconfig{CONFIG_EC_HOST_CMD_INITIALIZE_AT_BOOT} to n and must explicitly call
317 : * this routine.
318 : *
319 : * @param[in] backend Pointer to the backend structure to initialize.
320 : *
321 : * @retval 0 if successful
322 : */
323 1 : int ec_host_cmd_init(struct ec_host_cmd_backend *backend);
324 :
325 : /**
326 : * @brief Send the host command response
327 : *
328 : * This routine sends the host command response. It should be used to send IN_PROGRESS status or
329 : * if the host command handler doesn't return e.g. reboot command.
330 : *
331 : * @param[in] status Host command status to be sent.
332 : * @param[in] args Pointer of a structure passed to the handler.
333 : *
334 : * @retval 0 if successful.
335 : */
336 1 : int ec_host_cmd_send_response(enum ec_host_cmd_status status,
337 : const struct ec_host_cmd_handler_args *args);
338 :
339 : /**
340 : * @brief Signal a new host command
341 : *
342 : * Signal that a new host command has been received. The function should be called by a backend
343 : * after copying data to the rx buffer and setting the length.
344 : */
345 1 : void ec_host_cmd_rx_notify(void);
346 :
347 : /**
348 : * @brief Install a user callback for receiving a host command
349 : *
350 : * It allows installing a custom procedure needed by a user after receiving a command.
351 : *
352 : * @param[in] cb A callback to be installed.
353 : * @param[in] user_data User data to be passed to the callback.
354 : */
355 1 : void ec_host_cmd_set_user_cb(ec_host_cmd_user_cb_t cb, void *user_data);
356 :
357 : /**
358 : * @brief Get the main ec host command structure
359 : *
360 : * This routine returns a pointer to the main host command structure.
361 : * It allows the application code to get inside information for any reason e.g.
362 : * the host command thread id.
363 : *
364 : * @retval A pointer to the main host command structure
365 : */
366 1 : const struct ec_host_cmd *ec_host_cmd_get_hc(void);
367 :
368 : #ifndef CONFIG_EC_HOST_CMD_DEDICATED_THREAD
369 : /**
370 : * @brief The thread function for Host Command subsystem
371 : *
372 : * This routine calls the Host Command thread entry function. If
373 : * @kconfig{CONFIG_EC_HOST_CMD_DEDICATED_THREAD} is not defined, a new thread is not created,
374 : * and this function has to be called by application code. It doesn't return.
375 : */
376 1 : FUNC_NORETURN void ec_host_cmd_task(void);
377 : #endif
378 :
379 : #if defined(CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS) || defined(__DOXYGEN__)
380 : /**
381 : * @brief Check if a Host Command that sent @ref EC_HOST_CMD_IN_PROGRESS status has ended.
382 : *
383 : * A Host Command that sends @ref EC_HOST_CMD_IN_PROGRESS status doesn't send a final result.
384 : * The final result can be obtained with the @ref ec_host_cmd_send_in_progress_status function.
385 : *
386 : * @kconfig_dep{CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS}
387 : *
388 : * @retval true if the Host Command endded
389 : */
390 1 : bool ec_host_cmd_send_in_progress_ended(void);
391 :
392 : /**
393 : * @brief Get final result of a last Host Command that has sent @ref EC_HOST_CMD_IN_PROGRESS status.
394 : *
395 : * A Host Command that sends @ref EC_HOST_CMD_IN_PROGRESS status doesn't send a final result.
396 : * Get the saved status with this function. The status can be obtained only once. Further calls
397 : * return @ref EC_HOST_CMD_UNAVAILABLE.
398 : *
399 : * Saving status of Host Commands that send response data is not supported.
400 : *
401 : * @kconfig_dep{CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS}
402 : *
403 : * @retval The final status or EC_HOST_CMD_UNAVAILABLE if not available.
404 : */
405 1 : enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void);
406 :
407 : /**
408 : * @brief Continue processing a handler in callback after returning @ref EC_HOST_CMD_IN_PROGRESS.
409 : *
410 : * A Host Command handler may return the @ref EC_HOST_CMD_IN_PROGRESS, but needs to continue work.
411 : * This function should be called before returning @ref EC_HOST_CMD_IN_PROGRESS with a callback that
412 : * will be executed. The return status of the callback will be stored and can be obtained with the
413 : * @ref ec_host_cmd_send_in_progress_status function. The @ref ec_host_cmd_send_in_progress_ended
414 : * function can be used to check if the callback has ended.
415 : *
416 : * @kconfig_dep{CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS}
417 : *
418 : * @param[in] cb A callback to be called after returning from a command handler.
419 : * @param[in] user_data User data to be passed to the callback.
420 : *
421 : * @retval EC_HOST_CMD_BUSY if any command is already in progress, EC_HOST_CMD_SUCCESS otherwise
422 : */
423 1 : enum ec_host_cmd_status ec_host_cmd_send_in_progress_continue(ec_host_cmd_in_progress_cb_t cb,
424 : void *user_data);
425 : #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */
426 :
427 : /**
428 : * @brief Add a suppressed command.
429 : *
430 : * Suppressed commands are not logged. Add a command to be suppressed.
431 : *
432 : * @param[in] cmd_id A command id to be suppressed.
433 : *
434 : * @retval 0 if successful, -EIO if exceeded max number of suppressed commands.
435 : */
436 1 : int ec_host_cmd_add_suppressed(uint16_t cmd_id);
437 :
438 : /**
439 : * @}
440 : */
441 :
442 : #endif /* ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_H_ */
|