386 lines
9.8 KiB
C
386 lines
9.8 KiB
C
/*
|
|
* 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);
|