| /* |
| * Copyright (c) 2022-2023, Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * ARM SiP service shell command 'sip_svc'. |
| */ |
| |
| #include <zephyr/shell/shell.h> |
| #include <zephyr/sip_svc/sip_svc.h> |
| #include <zephyr/sip_svc/sip_svc_controller.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| |
| #define MAX_TIMEOUT_MSECS (1 * 1000UL) |
| |
| struct private_data { |
| struct k_sem semaphore; |
| const struct shell *sh; |
| }; |
| |
| static int parse_common_args(const struct shell *sh, char **argv, void **ctrl) |
| { |
| *ctrl = sip_svc_get_controller(argv[1]); |
| |
| if (!*ctrl) { |
| shell_error(sh, "service %s not found", argv[1]); |
| return -ENODEV; |
| } |
| |
| struct sip_svc_controller *ct = (struct sip_svc_controller *)(*ctrl); |
| |
| if (!ct->init) { |
| shell_error(sh, "ARM SiP services method %s not initialized", argv[1]); |
| return -ENODEV; |
| } |
| return 0; |
| } |
| |
| static int cmd_reg(const struct shell *sh, size_t argc, char **argv) |
| { |
| struct sip_svc_controller *ctrl; |
| uint32_t c_token; |
| int err; |
| |
| err = parse_common_args(sh, argv, (void **)&ctrl); |
| if (err < 0) { |
| return err; |
| } |
| |
| c_token = sip_svc_register(ctrl, NULL); |
| if (c_token == SIP_SVC_ID_INVALID) { |
| shell_error(sh, "%s: register fail", ctrl->method); |
| err = -1; |
| } else { |
| shell_print(sh, "%s: register success: client token %08x\n", ctrl->method, c_token); |
| err = 0; |
| } |
| |
| return err; |
| } |
| |
| static int cmd_unreg(const struct shell *sh, size_t argc, char **argv) |
| { |
| struct sip_svc_controller *ctrl; |
| uint32_t c_token; |
| int err; |
| char *endptr; |
| |
| err = parse_common_args(sh, argv, (void **)&ctrl); |
| if (err < 0) { |
| return err; |
| } |
| |
| errno = 0; |
| c_token = strtoul(argv[2], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[2] || *endptr) { |
| shell_error(sh, "Invalid argument"); |
| return -errno; |
| } |
| |
| err = sip_svc_unregister(ctrl, (uint32_t)c_token); |
| if (err) { |
| shell_error(sh, "%s: unregister fail (%d): client token %08x", ctrl->method, err, |
| (uint32_t)c_token); |
| } else { |
| shell_print(sh, "%s: unregister success: client token %08x", ctrl->method, |
| (uint32_t)c_token); |
| } |
| |
| return err; |
| } |
| |
| static int cmd_open(const struct shell *sh, size_t argc, char **argv) |
| { |
| struct sip_svc_controller *ctrl; |
| uint32_t c_token; |
| unsigned long mseconds = 0; |
| int err; |
| char *endptr; |
| k_timeout_t timeout = K_MSEC(MAX_TIMEOUT_MSECS); |
| |
| err = parse_common_args(sh, argv, (void **)&ctrl); |
| if (err < 0) { |
| return err; |
| } |
| |
| errno = 0; |
| c_token = strtoul(argv[2], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[2] || *endptr) { |
| shell_error(sh, "Invalid argument"); |
| return -errno; |
| } |
| |
| if (argc > 3) { |
| errno = 0; |
| mseconds = strtoul(argv[3], &endptr, 10); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[3] || *endptr) { |
| shell_error(sh, "Invalid Argument"); |
| return -EINVAL; |
| } else if (mseconds <= MAX_TIMEOUT_MSECS) { |
| timeout = K_MSEC(mseconds); |
| } else { |
| timeout = K_MSEC(MAX_TIMEOUT_MSECS); |
| shell_error(sh, "Setting timeout value to %lu milliseconds", |
| MAX_TIMEOUT_MSECS); |
| } |
| } |
| |
| err = sip_svc_open(ctrl, (uint32_t)c_token, timeout); |
| if (err) { |
| shell_error(sh, "%s: open fail (%d): client token %08x", ctrl->method, err, |
| (uint32_t)c_token); |
| } else { |
| shell_print(sh, "%s: open success: client token %08x", ctrl->method, |
| (uint32_t)c_token); |
| } |
| |
| return err; |
| } |
| |
| static int cmd_close(const struct shell *sh, size_t argc, char **argv) |
| { |
| struct sip_svc_controller *ctrl; |
| uint32_t c_token; |
| int err; |
| char *endptr; |
| |
| err = parse_common_args(sh, argv, (void **)&ctrl); |
| if (err < 0) { |
| return err; |
| } |
| |
| errno = 0; |
| c_token = strtoul(argv[2], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[2] || *endptr) { |
| shell_error(sh, "Invalid argument"); |
| return -errno; |
| } |
| |
| err = sip_svc_close(ctrl, (uint32_t)c_token, NULL); |
| if (err) { |
| shell_error(sh, "%s: close fail (%d): client token %08x", ctrl->method, err, |
| (uint32_t)c_token); |
| } else { |
| shell_print(sh, "%s: close success: client token %08x", ctrl->method, |
| (uint32_t)c_token); |
| } |
| |
| return err; |
| } |
| |
| static void cmd_send_callback(uint32_t c_token, struct sip_svc_response *response) |
| { |
| if (response == NULL) { |
| return; |
| } |
| |
| struct private_data *priv = (struct private_data *)response->priv_data; |
| const struct shell *sh = priv->sh; |
| |
| shell_print(sh, "\n\rsip_svc send callback response\n"); |
| shell_print(sh, "\theader=%08x\n", response->header); |
| shell_print(sh, "\ta0=%016lx\n", response->a0); |
| shell_print(sh, "\ta1=%016lx\n", response->a1); |
| shell_print(sh, "\ta2=%016lx\n", response->a2); |
| shell_print(sh, "\ta3=%016lx\n", response->a3); |
| |
| k_sem_give(&(priv->semaphore)); |
| } |
| |
| static int cmd_send(const struct shell *sh, size_t argc, char **argv) |
| { |
| struct sip_svc_controller *ctrl; |
| uint32_t c_token; |
| int trans_id; |
| struct sip_svc_request request; |
| struct private_data priv; |
| char *endptr; |
| int err; |
| |
| err = parse_common_args(sh, argv, (void **)&ctrl); |
| if (err < 0) { |
| return err; |
| } |
| |
| errno = 0; |
| c_token = strtoul(argv[2], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[2] || *endptr) { |
| shell_error(sh, "Invalid argument"); |
| return -errno; |
| } |
| |
| request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_SYNC, 0); |
| |
| request.a0 = strtoul(argv[3], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a0"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[3] || *endptr) { |
| shell_error(sh, "Invalid argument for a0"); |
| return -errno; |
| } |
| |
| if (argc > 4) { |
| request.a1 = strtoul(argv[4], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a1"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[4] || *endptr) { |
| shell_error(sh, "Invalid argument for a1"); |
| return -errno; |
| } |
| } |
| |
| if (argc > 5) { |
| request.a2 = strtoul(argv[5], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a2"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[5] || *endptr) { |
| shell_error(sh, "Invalid argument for a2"); |
| return -errno; |
| } |
| } |
| |
| if (argc > 6) { |
| request.a3 = strtoul(argv[6], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a3"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[6] || *endptr) { |
| shell_error(sh, "Invalid argument for a3"); |
| return -errno; |
| } |
| } |
| |
| if (argc > 7) { |
| request.a4 = strtoul(argv[7], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a4"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[7] || *endptr) { |
| shell_error(sh, "Invalid argument for a4"); |
| return -errno; |
| } |
| } |
| |
| if (argc > 8) { |
| request.a5 = strtoul(argv[8], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a5"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[8] || *endptr) { |
| shell_error(sh, "Invalid argument for a5"); |
| return -errno; |
| } |
| } |
| |
| if (argc > 9) { |
| request.a6 = strtoul(argv[9], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a6"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[9] || *endptr) { |
| shell_error(sh, "Invalid argument for a6"); |
| return -errno; |
| } |
| } |
| |
| if (argc > 10) { |
| request.a7 = strtoul(argv[10], &endptr, 16); |
| if (errno == ERANGE) { |
| shell_error(sh, "Out of range value for a7"); |
| return -ERANGE; |
| } else if (errno || endptr == argv[10] || *endptr) { |
| shell_error(sh, "Invalid argument for a7"); |
| return -errno; |
| } |
| } |
| |
| k_sem_init(&(priv.semaphore), 0, 1); |
| priv.sh = sh; |
| |
| request.resp_data_addr = 0; |
| request.resp_data_size = 0; |
| request.priv_data = (void *)&priv; |
| |
| trans_id = sip_svc_send(ctrl, (uint32_t)c_token, &request, cmd_send_callback); |
| |
| if (trans_id < 0) { |
| shell_error(sh, "%s: send fail: client token %08x", ctrl->method, |
| (uint32_t)c_token); |
| err = trans_id; |
| } else { |
| /*wait for callback*/ |
| k_sem_take(&(priv.semaphore), K_FOREVER); |
| |
| shell_print(sh, "%s: send success: client token %08x, trans_id %d", ctrl->method, |
| (uint32_t)c_token, trans_id); |
| err = 0; |
| } |
| return err; |
| } |
| |
| static int cmd_info(const struct shell *sh, size_t argc, char **argv) |
| { |
| struct sip_svc_controller *ctrl; |
| int err; |
| uint32_t i; |
| static const char *const state_str_list[] = {"INVALID", "IDLE", "OPEN", "ABORT"}; |
| const char *state_str = "UNKNOWN"; |
| |
| err = parse_common_args(sh, argv, (void **)&ctrl); |
| if (err < 0) { |
| return err; |
| } |
| |
| shell_print(sh, "---------------------------------------\n"); |
| shell_print(sh, "sip_svc service information\n"); |
| shell_print(sh, "---------------------------------------\n"); |
| |
| shell_print(sh, "active job cnt %d\n", ctrl->active_job_cnt); |
| shell_print(sh, "active async job cnt %d\n", ctrl->active_async_job_cnt); |
| |
| shell_print(sh, "---------------------------------------\n"); |
| shell_print(sh, "Client Token\tState\tTrans Cnt\n"); |
| shell_print(sh, "---------------------------------------\n"); |
| for (i = 0; i < ctrl->num_clients; i++) { |
| if (ctrl->clients[i].id != SIP_SVC_ID_INVALID) { |
| if (ctrl->clients[i].state <= SIP_SVC_CLIENT_ST_ABORT) { |
| state_str = state_str_list[ctrl->clients[i].state]; |
| } |
| |
| shell_print(sh, "%08x \t%-10s\t%-9d\n", ctrl->clients[i].token, |
| state_str, ctrl->clients[i].active_trans_cnt); |
| } |
| } |
| return err; |
| } |
| |
| SHELL_STATIC_SUBCMD_SET_CREATE( |
| sub_sip_svc, SHELL_CMD_ARG(reg, NULL, "<method>", cmd_reg, 2, 0), |
| SHELL_CMD_ARG(unreg, NULL, "<method> <token>", cmd_unreg, 3, 0), |
| SHELL_CMD_ARG(open, NULL, "<method> <token> <[timeout_msec]>", cmd_open, 3, 1), |
| SHELL_CMD_ARG(close, NULL, "<method> <token>", cmd_close, 3, 0), |
| SHELL_CMD_ARG(send, NULL, "<method> <token> <a0> [<a1> <a2> ... <a7>]", cmd_send, 4, 7), |
| SHELL_CMD_ARG(info, NULL, "<method>", cmd_info, 2, 0), SHELL_SUBCMD_SET_END); |
| |
| SHELL_CMD_REGISTER(sip_svc, &sub_sip_svc, "ARM SiP services commands", NULL); |