1 /* 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 io_interfaces 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 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 enum ec_host_cmd_log_level { 76 EC_HOST_CMD_DEBUG_OFF, /* No Host Command debug output */ 77 EC_HOST_CMD_DEBUG_NORMAL, /* Normal output mode; skips repeated commands */ 78 EC_HOST_CMD_DEBUG_EVERY, /* Print every command */ 79 EC_HOST_CMD_DEBUG_PARAMS, /* ... and print params for request/response */ 80 EC_HOST_CMD_DEBUG_MODES /* Number of host command debug modes */ 81 }; 82 83 enum ec_host_cmd_state { 84 EC_HOST_CMD_STATE_DISABLED = 0, 85 EC_HOST_CMD_STATE_RECEIVING, 86 EC_HOST_CMD_STATE_PROCESSING, 87 EC_HOST_CMD_STATE_SENDING, 88 }; 89 90 typedef void (*ec_host_cmd_user_cb_t)(const struct ec_host_cmd_rx_ctx *rx_ctx, void *user_data); 91 typedef enum ec_host_cmd_status (*ec_host_cmd_in_progress_cb_t)(void *user_data); 92 93 struct ec_host_cmd { 94 struct ec_host_cmd_rx_ctx rx_ctx; 95 struct ec_host_cmd_tx_buf tx; 96 struct ec_host_cmd_backend *backend; 97 /** 98 * The backend gives rx_ready (by calling the ec_host_cmd_send_receive function), 99 * when data in rx_ctx are ready. The handler takes rx_ready to read data in rx_ctx. 100 */ 101 struct k_sem rx_ready; 102 /** Status of the rx data checked in the ec_host_cmd_send_received function. */ 103 enum ec_host_cmd_status rx_status; 104 /** 105 * User callback after receiving a command. It is called by the ec_host_cmd_send_received 106 * function. 107 */ 108 ec_host_cmd_user_cb_t user_cb; 109 void *user_data; 110 enum ec_host_cmd_state state; 111 #ifdef CONFIG_EC_HOST_CMD_DEDICATED_THREAD 112 struct k_thread thread; 113 #endif /* CONFIG_EC_HOST_CMD_DEDICATED_THREAD */ 114 }; 115 116 /** 117 * @brief Arguments passed into every installed host command handler 118 */ 119 struct ec_host_cmd_handler_args { 120 /** Reserved for compatibility. */ 121 void *reserved; 122 /** Command identifier. */ 123 uint16_t command; 124 /** 125 * The version of the host command that is being requested. This will 126 * be a value that has been static registered as valid for the handler. 127 */ 128 uint8_t version; 129 /** The incoming data that can be cast to the handlers request type. */ 130 const void *input_buf; 131 /** The number of valid bytes that can be read from @a input_buf. */ 132 uint16_t input_buf_size; 133 /** The data written to this buffer will be send to the host. */ 134 void *output_buf; 135 /** Maximum number of bytes that can be written to the @a output_buf. */ 136 uint16_t output_buf_max; 137 /** Number of bytes of @a output_buf to send to the host. */ 138 uint16_t output_buf_size; 139 }; 140 141 typedef enum ec_host_cmd_status (*ec_host_cmd_handler_cb)(struct ec_host_cmd_handler_args *args); 142 /** 143 * @brief Structure use for statically registering host command handlers 144 */ 145 struct ec_host_cmd_handler { 146 /** Callback routine to process commands that match @a id. */ 147 ec_host_cmd_handler_cb handler; 148 /** The numerical command id used as the lookup for commands. */ 149 uint16_t id; 150 /** 151 * The bitfield of all versions that the @a handler supports, where 152 * each bit value represents that the @a handler supports that version. 153 * E.g. BIT(0) corresponds to version 0. 154 */ 155 uint16_t version_mask; 156 /** 157 * The minimum @a input_buf_size enforced by the framework before 158 * passing to the handler. 159 */ 160 uint16_t min_rqt_size; 161 /** 162 * The minimum @a output_buf_size enforced by the framework before 163 * passing to the handler. 164 */ 165 uint16_t min_rsp_size; 166 }; 167 168 /** 169 * @brief Statically define and register a host command handler. 170 * 171 * Helper macro to statically define and register a host command handler that 172 * has a compile-time-fixed sizes for its both request and response structures. 173 * 174 * @param _id Id of host command to handle request for. 175 * @param _function Name of handler function. 176 * @param _version_mask The bitfield of all versions that the @a _function 177 * supports. E.g. BIT(0) corresponds to version 0. 178 * @param _request_type The datatype of the request parameters for @a _function. 179 * @param _response_type The datatype of the response parameters for 180 * @a _function. 181 */ 182 #define EC_HOST_CMD_HANDLER(_id, _function, _version_mask, _request_type, _response_type) \ 183 const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \ 184 .handler = _function, \ 185 .id = _id, \ 186 .version_mask = _version_mask, \ 187 .min_rqt_size = sizeof(_request_type), \ 188 .min_rsp_size = sizeof(_response_type), \ 189 } 190 191 /** 192 * @brief Statically define and register a host command handler without sizes. 193 * 194 * Helper macro to statically define and register a host command handler whose 195 * request or response structure size is not known as compile time. 196 * 197 * @param _id Id of host command to handle request for. 198 * @param _function Name of handler function. 199 * @param _version_mask The bitfield of all versions that the @a _function 200 * supports. E.g. BIT(0) corresponds to version 0. 201 */ 202 #define EC_HOST_CMD_HANDLER_UNBOUND(_id, _function, _version_mask) \ 203 const STRUCT_SECTION_ITERABLE(ec_host_cmd_handler, __cmd##_id) = { \ 204 .handler = _function, \ 205 .id = _id, \ 206 .version_mask = _version_mask, \ 207 .min_rqt_size = 0, \ 208 .min_rsp_size = 0, \ 209 } 210 211 /** 212 * @brief Header for requests from host to embedded controller 213 * 214 * Represent the over-the-wire header in LE format for host command requests. 215 * This represent version 3 of the host command header. The requests are always 216 * sent from host to embedded controller. 217 */ 218 struct ec_host_cmd_request_header { 219 /** 220 * Should be 3. The EC will return EC_HOST_CMD_INVALID_HEADER if it 221 * receives a header with a version it doesn't know how to parse. 222 */ 223 uint8_t prtcl_ver; 224 /** 225 * Checksum of response and data; sum of all bytes including checksum. 226 * Should total to 0. 227 */ 228 uint8_t checksum; 229 /** Id of command that is being sent. */ 230 uint16_t cmd_id; 231 /** 232 * Version of the specific @a cmd_id being requested. Valid 233 * versions start at 0. 234 */ 235 uint8_t cmd_ver; 236 /** Unused byte in current protocol version; set to 0. */ 237 uint8_t reserved; 238 /** Length of data which follows this header. */ 239 uint16_t data_len; 240 } __packed; 241 242 /** 243 * @brief Header for responses from embedded controller to host 244 * 245 * Represent the over-the-wire header in LE format for host command responses. 246 * This represent version 3 of the host command header. Responses are always 247 * sent from embedded controller to host. 248 */ 249 struct ec_host_cmd_response_header { 250 /** Should be 3. */ 251 uint8_t prtcl_ver; 252 /** 253 * Checksum of response and data; sum of all bytes including checksum. 254 * Should total to 0. 255 */ 256 uint8_t checksum; 257 /** A @a ec_host_cmd_status response code for specific command. */ 258 uint16_t result; 259 /** Length of data which follows this header. */ 260 uint16_t data_len; 261 /** Unused bytes in current protocol version; set to 0. */ 262 uint16_t reserved; 263 } __packed; 264 265 /** 266 * @brief Initialize the host command subsystem 267 * 268 * This routine initializes the host command subsystem. It includes initialization 269 * of a backend and the handler. 270 * When the application configures the zephyr,host-cmd-espi-backend/zephyr,host-cmd-shi-backend/ 271 * zephyr,host-cmd-uart-backend chosen node and @kconfig{CONFIG_EC_HOST_CMD_INITIALIZE_AT_BOOT} is 272 * set, the chosen backend automatically calls this routine at 273 * @kconfig{CONFIG_EC_HOST_CMD_INIT_PRIORITY}. Applications that require a run-time selection of the 274 * backend must set @kconfig{CONFIG_EC_HOST_CMD_INITIALIZE_AT_BOOT} to n and must explicitly call 275 * this routine. 276 * 277 * @param[in] backend Pointer to the backend structure to initialize. 278 * 279 * @retval 0 if successful 280 */ 281 int ec_host_cmd_init(struct ec_host_cmd_backend *backend); 282 283 /** 284 * @brief Send the host command response 285 * 286 * This routine sends the host command response. It should be used to send IN_PROGRESS status or 287 * if the host command handler doesn't return e.g. reboot command. 288 * 289 * @param[in] status Host command status to be sent. 290 * @param[in] args Pointer of a structure passed to the handler. 291 * 292 * @retval 0 if successful. 293 */ 294 int ec_host_cmd_send_response(enum ec_host_cmd_status status, 295 const struct ec_host_cmd_handler_args *args); 296 297 /** 298 * @brief Signal a new host command 299 * 300 * Signal that a new host command has been received. The function should be called by a backend 301 * after copying data to the rx buffer and setting the length. 302 */ 303 void ec_host_cmd_rx_notify(void); 304 305 /** 306 * @brief Install a user callback for receiving a host command 307 * 308 * It allows installing a custom procedure needed by a user after receiving a command. 309 * 310 * @param[in] cb A callback to be installed. 311 * @param[in] user_data User data to be passed to the callback. 312 */ 313 void ec_host_cmd_set_user_cb(ec_host_cmd_user_cb_t cb, void *user_data); 314 315 /** 316 * @brief Get the main ec host command structure 317 * 318 * This routine returns a pointer to the main host command structure. 319 * It allows the application code to get inside information for any reason e.g. 320 * the host command thread id. 321 * 322 * @retval A pointer to the main host command structure 323 */ 324 const struct ec_host_cmd *ec_host_cmd_get_hc(void); 325 326 #ifndef CONFIG_EC_HOST_CMD_DEDICATED_THREAD 327 /** 328 * @brief The thread function for Host Command subsystem 329 * 330 * This routine calls the Host Command thread entry function. If 331 * @kconfig{CONFIG_EC_HOST_CMD_DEDICATED_THREAD} is not defined, a new thread is not created, 332 * and this function has to be called by application code. It doesn't return. 333 */ 334 FUNC_NORETURN void ec_host_cmd_task(void); 335 #endif 336 337 #ifdef CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS 338 /** 339 * @brief Check if a Host Command that sent EC_HOST_CMD_IN_PROGRESS status has ended. 340 * 341 * A Host Command that sends EC_HOST_CMD_IN_PROGRESS status doesn't send a final result. 342 * The final result can be get with the ec_host_cmd_send_in_progress_status function. 343 * 344 * @retval true if the Host Command endded 345 */ 346 bool ec_host_cmd_send_in_progress_ended(void); 347 348 /** 349 * @brief Get final result of a last Host Command that has sent EC_HOST_CMD_IN_PROGRESS status. 350 * 351 * A Host Command that sends EC_HOST_CMD_IN_PROGRESS status doesn't send a final result. 352 * Get the saved status with this function. The status can be get only once. Further calls return 353 * EC_HOST_CMD_UNAVAILABLE. 354 * 355 * Saving status of Host Commands that send response data is not supported. 356 * 357 * @retval The final status or EC_HOST_CMD_UNAVAILABLE if not available. 358 */ 359 enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void); 360 361 /** 362 * @brief Continue processing a handler in callback after returning EC_HOST_CMD_IN_PROGRESS. 363 * 364 * A Host Command handler may return the EC_HOST_CMD_IN_PROGRESS, but needs to continue work. 365 * This function should be called before returning EC_HOST_CMD_IN_PROGRESS with a callback that 366 * will be executed. The return status of the callback will be stored and can be get with the 367 * ec_host_cmd_send_in_progress_status function. The ec_host_cmd_send_in_progress_ended function 368 * can be used to check if the callback has ended. 369 * 370 * @param[in] cb A callback to be called after returning from a command handler. 371 * @param[in] user_data User data to be passed to the callback. 372 * 373 * @retval EC_HOST_CMD_BUSY if any command is already in progress, EC_HOST_CMD_SUCCESS otherwise 374 */ 375 enum ec_host_cmd_status ec_host_cmd_send_in_progress_continue(ec_host_cmd_in_progress_cb_t cb, 376 void *user_data); 377 #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ 378 379 /** 380 * @brief Add a suppressed command. 381 * 382 * Suppressed commands are not logged. Add a command to be suppressed. 383 * 384 * @param[in] cmd_id A command id to be suppressed. 385 * 386 * @retval 0 if successful, -EIO if exceeded max number of suppressed commands. 387 */ 388 int ec_host_cmd_add_suppressed(uint16_t cmd_id); 389 390 /** 391 * @} 392 */ 393 394 #endif /* ZEPHYR_INCLUDE_MGMT_EC_HOST_CMD_EC_HOST_CMD_H_ */ 395