diff --git a/tools/plugin/README.md b/tools/plugin/README.md index 368b0f499377..5ba4d729ae97 100644 --- a/tools/plugin/README.md +++ b/tools/plugin/README.md @@ -79,7 +79,19 @@ or ``` amixer -Dsof:plugin cset numid=1 20 ``` -Right now, only volume controls are supported. Support for bytes and enum controls is pending. +Bytes control data can be set using sof-ctl as follows: + +``` +./sof-ctl -Dsof:plugin -n 4 -r -i 4 -p 2 -s ~/data.txt +``` +where -n is the numid of the kcontrol, -i is the IPC version, -p is the param ID and -s specifies +the data in csv format. + +Bytes control data can be read using sof-ctl as follows: +``` +./sof-ctl -Dsof:plugin -n 4 -i 4 -p 2 +``` +where -n is the numid of the kcontrol, -i is the IPC version and -p is the param ID. # Instructions for testing OpenVino noise suppression model with the SOF plugin: 1. Fetch the model from the Open Model zoo repository ex: noise-suppression-poconetlike-0001.xml diff --git a/tools/plugin/alsaplug/ctl.c b/tools/plugin/alsaplug/ctl.c index c235591a5f1f..f45bf4f9b0e1 100644 --- a/tools/plugin/alsaplug/ctl.c +++ b/tools/plugin/alsaplug/ctl.c @@ -145,10 +145,9 @@ static int plug_ctl_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, // TODO: ?? break; case SND_SOC_TPLG_CTL_BYTES: - printf("%s %d\n", __func__, __LINE__); bytes_ctl = (struct snd_soc_tplg_bytes_control *)hdr; *type = SND_CTL_ELEM_TYPE_BYTES; - *count = bytes_ctl->size; // Not sure if size is correct + *count = bytes_ctl->max; break; } @@ -536,36 +535,147 @@ static int plug_ctl_write_enumerated(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, /* * Bytes ops */ +static int plug_ctl_get_bytes_data(snd_sof_ctl_t *ctl, snd_ctl_ext_key_t key, + struct sof_abi_hdr *abi, unsigned int max_bytes) +{ + struct snd_soc_tplg_bytes_control *bytes_ctl = CTL_GET_TPLG_BYTES(ctl, key); + struct ipc4_module_large_config config = {{ 0 }}; + struct ipc4_module_large_config_reply *reply; + char *reply_data, *data; + void *msg; + uint32_t data_size; + int size, reply_data_size; + int err; + + /* configure the IPC message */ + plug_ctl_ipc_message(&config, abi->type, 0, + ctl->glb->ctl[key].module_id, ctl->glb->ctl[key].instance_id, + SOF_IPC4_MOD_LARGE_CONFIG_GET); + + config.extension.r.final_block = 1; + config.extension.r.init_block = 1; + + size = sizeof(config); + msg = calloc(size, 1); + if (!msg) + return -ENOMEM; + + /* + * reply contains both the requested data and the reply status. Allocate enough memory + * for max data + */ + reply_data_size = sizeof(*reply) + sizeof(*data) + bytes_ctl->max; + reply_data = calloc(reply_data_size, 1); + if (!reply_data_size) { + free(msg); + return -ENOMEM; + } + + /* send the IPC message */ + memcpy(msg, &config, sizeof(config)); + err = plug_mq_cmd_tx_rx(&ctl->ipc_tx, &ctl->ipc_rx, + msg, size, reply_data, reply_data_size); + free(msg); + if (err < 0) { + SNDERR("failed to get bytes data for control %s\n", bytes_ctl->hdr.name); + goto out; + } + + reply = (struct ipc4_module_large_config_reply *)reply_data; + if (reply->primary.r.status != IPC4_SUCCESS) { + SNDERR("bytes control %s get failed with status %d\n", + bytes_ctl->hdr.name, reply->primary.r.status); + err = -EINVAL; + goto out; + } + + /* check data sanity */ + data = (char *)(reply_data + sizeof(*reply)); + data_size = reply->extension.r.data_off_size; + if (data_size > bytes_ctl->max) { + SNDERR("received data size %d is larger than max %d for bytes control %s\n", + data_size, bytes_ctl->max, bytes_ctl->hdr.name); + err = -EINVAL; + goto out; + } + + abi->size = data_size; + + if (data_size) + memcpy(abi->data, data, MIN(data_size, max_bytes)); + + err = data_size; +out: + free(reply_data); + return err; +} + static int plug_ctl_read_bytes(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, size_t max_bytes) { + snd_sof_ctl_t *ctl = ext->private_data; + struct sof_abi_hdr *abi = (struct sof_abi_hdr *)data; + int data_size; + + data_size = plug_ctl_get_bytes_data(ctl, key, abi, max_bytes); + if (data_size < 0) + return data_size; + return 0; } static int plug_ctl_write_bytes(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, size_t max_bytes) { + snd_sof_ctl_t *ctl = ext->private_data; + struct snd_soc_tplg_bytes_control *bytes_ctl = CTL_GET_TPLG_BYTES(ctl, key); + struct sof_abi_hdr *abi = (struct sof_abi_hdr *)data; + int err; + + /* send IPC with kcontrol data */ + err = plug_send_bytes_data(&ctl->ipc_tx, &ctl->ipc_rx, + ctl->glb->ctl[key].module_id, ctl->glb->ctl[key].instance_id, + abi); + if (err < 0) { + SNDERR("failed to set bytes data for control %s\n", bytes_ctl->hdr.name); + return err; + } + return 0; } -/* - * TLV ops - * - * The format of an array of \a tlv argument is: - * tlv[0]: Type. One of SND_CTL_TLVT_XXX. - * tlv[1]: Length. The length of value in units of byte. - * tlv[2..]: Value. Depending on the type. - */ +/* TLV ops used for TLV bytes control callback */ static int plug_tlv_rw(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int op_flag, unsigned int numid, unsigned int *tlv, unsigned int tlv_size) { snd_sof_ctl_t *ctl = ext->private_data; - struct snd_soc_tplg_ctl_hdr *hdr = CTL_GET_TPLG_HDR(ctl, key); + struct snd_soc_tplg_bytes_control *bytes_ctl = CTL_GET_TPLG_BYTES(ctl, key); + struct sof_abi_hdr *abi = (struct sof_abi_hdr *)(tlv + 2); /* skip TLV header */ + int data_size; + + /* send IPC with kcontrol data if op_flag is > 0 else send IPC to get kcontrol data */ + if (op_flag) { + int err; + + err = plug_send_bytes_data(&ctl->ipc_tx, &ctl->ipc_rx, + ctl->glb->ctl[key].module_id, + ctl->glb->ctl[key].instance_id, abi); + if (err < 0) { + SNDERR("failed to set bytes data for control %s\n", bytes_ctl->hdr.name); + return err; + } + + return 0; + } + + /* read kcontrol data */ + data_size = plug_ctl_get_bytes_data(ctl, key, abi, tlv_size); + if (data_size < 0) + return data_size; - //TODO: alsamixer showing wrong dB scales - tlv[0] = hdr->tlv.type; - tlv[1] = hdr->tlv.size - sizeof(uint32_t) * 2; - memcpy(&tlv[2], hdr->tlv.data, hdr->tlv.size - sizeof(uint32_t) * 2); + /* set data size and numid */ + tlv[0] = numid; + tlv[1] = data_size + sizeof(*abi); return 0; } diff --git a/tools/plugin/alsaplug/tplg.c b/tools/plugin/alsaplug/tplg.c index 07d0bd080d11..11f8b0f0683b 100644 --- a/tools/plugin/alsaplug/tplg.c +++ b/tools/plugin/alsaplug/tplg.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -1107,7 +1108,9 @@ static int plug_set_up_route(snd_sof_plug_t *plug, struct tplg_route_info *route static int plug_set_up_widget(snd_sof_plug_t *plug, struct tplg_comp_info *comp_info) { struct tplg_pipeline_info *pipe_info = comp_info->pipe_info; - int ret; + struct plug_shm_glb_state *glb = plug->glb_ctx.addr; + struct plug_shm_ctl *ctl; + int ret, i; pipe_info->usage_count++; @@ -1125,6 +1128,33 @@ static int plug_set_up_widget(snd_sof_plug_t *plug, struct tplg_comp_info *comp_ if (ret < 0) return ret; + /* send kcontrol bytes data */ + for (i = 0; i < glb->num_ctls; i++) { + struct snd_soc_tplg_bytes_control *tplg_bytes; + struct sof_abi_hdr *abi; + int priv_size; + + ctl = &glb->ctl[i]; + + /* send the bytes data from kcontrols associated with current widget */ + if (ctl->module_id != comp_info->module_id || + ctl->instance_id != comp_info->instance_id || + ctl->type != SND_SOC_TPLG_TYPE_BYTES) + continue; + + tplg_bytes = &ctl->bytes_ctl; + priv_size = tplg_bytes->priv.size; + abi = (struct sof_abi_hdr *)ctl->data; + + /* send IPC with kcontrol data */ + ret = plug_send_bytes_data(&plug->ipc_tx, &plug->ipc_rx, + comp_info->module_id, comp_info->instance_id, abi); + if (ret < 0) { + SNDERR("failed to set bytes data for widget %s\n", comp_info->name); + return ret; + } + } + tplg_debug("widget %s set up\n", comp_info->name); return 0; diff --git a/tools/plugin/alsaplug/tplg_ctl.c b/tools/plugin/alsaplug/tplg_ctl.c index 620c730f82a1..6424b54825ba 100644 --- a/tools/plugin/alsaplug/tplg_ctl.c +++ b/tools/plugin/alsaplug/tplg_ctl.c @@ -202,7 +202,20 @@ int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, voi break; } case SND_SOC_TPLG_CTL_BYTES: + { + struct snd_soc_tplg_bytes_control *tplg_bytes = + (struct snd_soc_tplg_bytes_control *)tplg_ctl; + + glb->size += sizeof(struct plug_shm_ctl); + ctl = &glb->ctl[glb->num_ctls++]; + ctl->module_id = comp_info->module_id; + ctl->instance_id = comp_info->instance_id; + ctl->bytes_ctl = *tplg_bytes; + ctl->index = index; + ctl->type = tplg_ctl->type; + memcpy(ctl->data, tplg_bytes->priv.data, tplg_bytes->priv.size); break; + } case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_CTL_STROBE: default: diff --git a/tools/plugin/common.c b/tools/plugin/common.c index 1674dea5f787..46629f061201 100644 --- a/tools/plugin/common.c +++ b/tools/plugin/common.c @@ -264,3 +264,45 @@ void plug_ctl_ipc_message(struct ipc4_module_large_config *config, int param_id, config->extension.r.data_off_size = size; config->extension.r.large_param_id = param_id; } + +int plug_send_bytes_data(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx, + uint32_t module_id, uint32_t instance_id, struct sof_abi_hdr *abi) +{ + struct ipc4_module_large_config config = {{ 0 }}; + struct ipc4_message_reply reply; + void *msg; + int msg_size; + int err; + + /* configure the IPC message */ + plug_ctl_ipc_message(&config, abi->type, abi->size, module_id, instance_id, + SOF_IPC4_MOD_LARGE_CONFIG_SET); + + config.extension.r.final_block = 1; + config.extension.r.init_block = 1; + + /* allocate memory for IPC message */ + msg_size = sizeof(config) + abi->size; + msg = calloc(msg_size, 1); + if (!msg) + return -ENOMEM; + + /* set the IPC message data */ + memcpy(msg, &config, sizeof(config)); + memcpy(msg + sizeof(config), abi->data, abi->size); + + /* send the message and check status */ + err = plug_mq_cmd_tx_rx(ipc_tx, ipc_rx, msg, msg_size, &reply, sizeof(reply)); + free(msg); + if (err < 0) { + SNDERR("failed to send IPC to set bytes data\n"); + return err; + } + + if (reply.primary.r.status != IPC4_SUCCESS) { + SNDERR("IPC failed with status %d\n", reply.primary.r.status); + return -EINVAL; + } + + return 0; +} diff --git a/tools/plugin/common.h b/tools/plugin/common.h index f849676fbcc8..002f3843c3e7 100644 --- a/tools/plugin/common.h +++ b/tools/plugin/common.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include /* temporary - current MAXLEN is not define in UAPI header - fix pending */ #ifndef SNDRV_CTL_ELEM_ID_NAME_MAXLEN @@ -52,6 +54,7 @@ #define SOF_MAGIC "sofpipe" #define MAX_VOLUME_SIZE 120 +#define MAX_DATA_SIZE 512 enum plugin_state { SOF_PLUGIN_STATE_INIT = 0, @@ -67,6 +70,7 @@ struct plug_shm_ctl { unsigned int type; unsigned int volume_table[MAX_VOLUME_SIZE]; unsigned int index; + char data[MAX_DATA_SIZE]; union { struct snd_soc_tplg_mixer_control mixer_ctl; struct snd_soc_tplg_enum_control enum_ctl; @@ -320,5 +324,7 @@ static inline void data_dump(void *vdata, size_t bytes) void plug_ctl_ipc_message(struct ipc4_module_large_config *config, int param_id, size_t size, uint32_t module_id, uint32_t instance_id, uint32_t type); +int plug_send_bytes_data(struct plug_mq_desc *ipc_tx, struct plug_mq_desc *ipc_rx, + uint32_t module_id, uint32_t instance_id, struct sof_abi_hdr *abi); #endif