Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 157 additions & 24 deletions tools/plugin/alsaplug/ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static int plug_ctl_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
struct snd_soc_tplg_bytes_control *bytes_ctl;
int err = 0;

switch (hdr->type) {
switch (hdr->ops.info) {
case SND_SOC_TPLG_CTL_VOLSW:
case SND_SOC_TPLG_CTL_VOLSW_SX:
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
Expand All @@ -138,7 +138,7 @@ static int plug_ctl_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
case SND_SOC_TPLG_CTL_ENUM_VALUE:
enum_ctl = (struct snd_soc_tplg_enum_control *)hdr;
*type = SND_CTL_ELEM_TYPE_ENUMERATED;
*count = enum_ctl->num_channels;
*count = enum_ctl->items;
break;
case SND_SOC_TPLG_CTL_RANGE:
case SND_SOC_TPLG_CTL_STROBE:
Expand Down Expand Up @@ -198,6 +198,20 @@ static int plug_ctl_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
return err;
}

static 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)
{
config->primary.r.type = type;
config->primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_MODULE_MSG;
config->primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST;
config->primary.r.module_id = module_id;
config->primary.r.instance_id = instance_id;

config->extension.r.data_off_size = size;
config->extension.r.large_param_id = param_id;
}

static int plug_ctl_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value)
{
snd_sof_ctl_t *ctl = ext->private_data;
Expand All @@ -212,14 +226,9 @@ static int plug_ctl_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long
int i, err;

/* configure the IPC message */
config.primary.r.type = SOF_IPC4_MOD_LARGE_CONFIG_GET;
config.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_MODULE_MSG;
config.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST;
config.primary.r.module_id = ctl->glb->ctl[key].module_id;
config.primary.r.instance_id = ctl->glb->ctl[key].instance_id;

config.extension.r.data_off_size = sizeof(volume);
config.extension.r.large_param_id = IPC4_VOLUME;
plug_ctl_ipc_message(&config, IPC4_VOLUME, sizeof(volume), 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;

Expand All @@ -229,7 +238,7 @@ static int plug_ctl_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long
return -ENOMEM;

/* reply contains both the requested data and the reply status */
reply_data_size = sizeof(reply) + mixer_ctl->num_channels * sizeof(*volume);
reply_data_size = sizeof(*reply) + mixer_ctl->num_channels * sizeof(*volume);
reply_data = calloc(reply_data_size, 1);
if (!reply_data_size) {
free(msg);
Expand Down Expand Up @@ -316,14 +325,9 @@ static int plug_ctl_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, lon
volume.curve_duration = 200000;

/* configure the IPC message */
config.primary.r.type = SOF_IPC4_MOD_LARGE_CONFIG_SET;
config.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_MODULE_MSG;
config.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST;
config.primary.r.module_id = ctl->glb->ctl[key].module_id;
config.primary.r.instance_id = ctl->glb->ctl[key].instance_id;

config.extension.r.data_off_size = sizeof(volume);
config.extension.r.large_param_id = IPC4_VOLUME;
plug_ctl_ipc_message(&config, IPC4_VOLUME, sizeof(volume),
ctl->glb->ctl[key].module_id, ctl->glb->ctl[key].instance_id,
SOF_IPC4_MOD_LARGE_CONFIG_SET);
config.extension.r.final_block = 1;
config.extension.r.init_block = 1;

Expand Down Expand Up @@ -369,7 +373,7 @@ static int plug_ctl_get_enumerated_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t ke
(struct snd_soc_tplg_enum_control *)hdr;
int err = 0;

switch (hdr->type) {
switch (hdr->ops.info) {
case SND_SOC_TPLG_CTL_ENUM:
case SND_SOC_TPLG_CTL_ENUM_VALUE:
*items = enum_ctl->items;
Expand All @@ -391,10 +395,8 @@ static int plug_ctl_get_enumerated_name(snd_ctl_ext_t *ext, snd_ctl_ext_key_t ke
struct snd_soc_tplg_enum_control *enum_ctl =
(struct snd_soc_tplg_enum_control *)hdr;

printf("%s %d\n", __func__, __LINE__);

if (item >= enum_ctl->count) {
SNDERR("invalid item %d for enum using key %d", item, key);
if (item >= enum_ctl->items) {
SNDERR("invalid item %d for enum using key %d\n", item, key);
return -EINVAL;
}

Expand All @@ -405,12 +407,143 @@ static int plug_ctl_get_enumerated_name(snd_ctl_ext_t *ext, snd_ctl_ext_key_t ke
static int plug_ctl_read_enumerated(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
unsigned int *items)
{
snd_sof_ctl_t *ctl = ext->private_data;
struct snd_soc_tplg_enum_control *enum_ctl = CTL_GET_TPLG_ENUM(ctl, key);
struct ipc4_module_large_config config = {{ 0 }};
struct ipc4_module_large_config_reply *reply;
struct sof_ipc4_control_msg_payload *data;
char *reply_data;
void *msg;
int size, reply_data_size;
int i, err;

/* configure the IPC message */
plug_ctl_ipc_message(&config, SOF_IPC4_ENUM_CONTROL_PARAM_ID, 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 */
reply_data_size = sizeof(*reply) + sizeof(*data) +
enum_ctl->num_channels * sizeof(data->chanv[0]);
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 enum items for control %s\n", enum_ctl->hdr.name);
goto out;
}

reply = (struct ipc4_module_large_config_reply *)reply_data;
if (reply->primary.r.status != IPC4_SUCCESS) {
SNDERR("enum control %s get failed with status %d\n",
enum_ctl->hdr.name, reply->primary.r.status);
err = -EINVAL;
goto out;
}

/* check data sanity */
data = (struct sof_ipc4_control_msg_payload *)(reply_data + sizeof(*reply));
if (data->num_elems != enum_ctl->num_channels) {
SNDERR("Channel count %d doesn't match the expected value %d for enum ctl %s\n",
data->num_elems, enum_ctl->num_channels, enum_ctl->hdr.name);
err = -EINVAL;
goto out;
}

/* set the enum items based on the received data */
for (i = 0; i < enum_ctl->num_channels; i++)
items[i] = data->chanv[i].value;
out:
free(reply_data);
return 0;
}

static int plug_ctl_write_enumerated(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
unsigned int *items)
{
snd_sof_ctl_t *ctl = ext->private_data;
struct snd_soc_tplg_enum_control *enum_ctl = CTL_GET_TPLG_ENUM(ctl, key);
struct ipc4_module_large_config config = {{ 0 }};
struct sof_ipc4_control_msg_payload *data;
struct ipc4_message_reply reply;
void *msg;
int data_size, msg_size;
int err, i;

/* size of control data */
data_size = enum_ctl->num_channels * sizeof(struct sof_ipc4_ctrl_value_chan) +
sizeof(*data);

/* allocate memory for control data */
data = calloc(data_size, 1);
if (!data)
return -ENOMEM;

/* set param ID and number of channels */
data->id = ctl->glb->ctl[key].index;
data->num_elems = enum_ctl->num_channels;

/* set the enum values */
for (i = 0; i < data->num_elems; i++) {
data->chanv[i].channel = i;
data->chanv[i].value = items[i];
}

/* configure the IPC message */
plug_ctl_ipc_message(&config, SOF_IPC4_ENUM_CONTROL_PARAM_ID, data_size,
ctl->glb->ctl[key].module_id, ctl->glb->ctl[key].instance_id,
SOF_IPC4_MOD_LARGE_CONFIG_SET);

/*
* enum controls can have a maximum of 16 texts/values. So the entire data can be sent
* in a single IPC message
*/
config.extension.r.final_block = 1;
config.extension.r.init_block = 1;

/* allocate memory for IPC message */
msg_size = sizeof(config) + data_size;
msg = calloc(msg_size, 1);
if (!msg) {
free(data);
return -ENOMEM;
}

/* set the IPC message data */
memcpy(msg, &config, sizeof(config));
memcpy(msg + sizeof(config), data, data_size);
free(data);

/* send the message and check status */
err = plug_mq_cmd_tx_rx(&ctl->ipc_tx, &ctl->ipc_rx, msg, msg_size, &reply, sizeof(reply));
free(msg);
if (err < 0) {
SNDERR("failed to set enum control %s\n", enum_ctl->hdr.name);
return err;
}

if (reply.primary.r.status != IPC4_SUCCESS) {
SNDERR("enum control %s set failed with status %d\n",
enum_ctl->hdr.name, reply.primary.r.status);
return -EINVAL;
}

return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion tools/plugin/alsaplug/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,6 @@ int plug_parse_topology(snd_sof_plug_t *plug);
int plug_set_up_pipelines(snd_sof_plug_t *plug, int dir);
int plug_free_pipelines(snd_sof_plug_t *plug, struct tplg_pipeline_list *pipeline_list, int dir);
void plug_free_topology(snd_sof_plug_t *plug);
int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, void *arg);
int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, void *arg, int index);

#endif
19 changes: 16 additions & 3 deletions tools/plugin/alsaplug/tplg_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,9 @@ static uint32_t vol_compute_gain(uint32_t value, struct snd_soc_tplg_tlv_dbscale
}

/* helper function to add new kcontrols to the list of kcontrols in the global context */
int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, void *arg)
int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, void *arg, int index)
{
struct tplg_comp_info *comp_info = _comp;
snd_sof_plug_t *plug = arg;
struct plug_shm_glb_state *glb = plug->glb_ctx.addr;
struct plug_shm_ctl *ctl;
Expand All @@ -152,14 +153,13 @@ int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, voi
return -EINVAL;
}

switch (tplg_ctl->type) {
switch (tplg_ctl->ops.info) {
case SND_SOC_TPLG_CTL_VOLSW:
case SND_SOC_TPLG_CTL_VOLSW_SX:
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
{
struct snd_soc_tplg_mixer_control *tplg_mixer =
(struct snd_soc_tplg_mixer_control *)tplg_ctl;
struct tplg_comp_info *comp_info = _comp;
struct snd_soc_tplg_ctl_tlv *tlv;
struct snd_soc_tplg_tlv_dbscale *scale;
int i;
Expand All @@ -169,6 +169,7 @@ int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, voi
ctl->module_id = comp_info->module_id;
ctl->instance_id = comp_info->instance_id;
ctl->mixer_ctl = *tplg_mixer;
ctl->index = index;
tlv = &tplg_ctl->tlv;
scale = &tlv->scale;

Expand All @@ -186,6 +187,18 @@ int plug_kcontrol_cb_new(struct snd_soc_tplg_ctl_hdr *tplg_ctl, void *_comp, voi
}
case SND_SOC_TPLG_CTL_ENUM:
case SND_SOC_TPLG_CTL_ENUM_VALUE:
{
struct snd_soc_tplg_enum_control *tplg_enum =
(struct snd_soc_tplg_enum_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->enum_ctl = *tplg_enum;
ctl->index = index;
break;
}
case SND_SOC_TPLG_CTL_BYTES:
break;
case SND_SOC_TPLG_CTL_RANGE:
Expand Down
1 change: 1 addition & 0 deletions tools/plugin/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct plug_shm_ctl {
unsigned int instance_id;
unsigned int type;
unsigned int volume_table[MAX_VOLUME_SIZE];
unsigned int index;
union {
struct snd_soc_tplg_mixer_control mixer_ctl;
struct snd_soc_tplg_enum_control enum_ctl;
Expand Down
9 changes: 8 additions & 1 deletion tools/tplg_parser/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ int tplg_create_controls(struct tplg_context *ctx, int num_kcontrols,
struct snd_soc_tplg_mixer_control *mixer_ctl;
struct snd_soc_tplg_enum_control *enum_ctl;
struct snd_soc_tplg_bytes_control *bytes_ctl;
int num_mixers = 0;
int num_enums = 0;
int num_byte_controls = 0;
int index;
int j, ret = 0;

for (j = 0; j < num_kcontrols; j++) {
Expand All @@ -105,6 +109,7 @@ int tplg_create_controls(struct tplg_context *ctx, int num_kcontrols,
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
case SND_SOC_TPLG_CTL_RANGE:
case SND_SOC_TPLG_DAPM_CTL_VOLSW:
index = num_mixers++;
/* load mixer type control */
mixer_ctl = (struct snd_soc_tplg_mixer_control *)ctl_hdr;
/* ctl is after private data */
Expand All @@ -116,13 +121,15 @@ int tplg_create_controls(struct tplg_context *ctx, int num_kcontrols,
case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
index = num_enums++;
/* load enum_ctl type control */
enum_ctl = (struct snd_soc_tplg_enum_control *)ctl_hdr;
/* ctl is after private data */
tplg_get_object_priv(ctx, enum_ctl, enum_ctl->priv.size);
break;

case SND_SOC_TPLG_CTL_BYTES:
index = num_byte_controls++;
/* load bytes_ctl type control */
bytes_ctl = (struct snd_soc_tplg_bytes_control *)ctl_hdr;
/* ctl is after private data */
Expand All @@ -135,7 +142,7 @@ int tplg_create_controls(struct tplg_context *ctx, int num_kcontrols,
}

if (ctx->ctl_cb && object)
ctx->ctl_cb(ctl_hdr, object, ctx->ctl_arg);
ctx->ctl_cb(ctl_hdr, object, ctx->ctl_arg, index);
}

if (rctl && ctl_hdr) {
Expand Down
2 changes: 1 addition & 1 deletion tools/tplg_parser/include/tplg_parser/topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ struct tplg_context {
/* kcontrol creation */
void *ctl_arg;
int (*ctl_cb)(struct snd_soc_tplg_ctl_hdr *tplg_ctl,
void *comp, void *arg);
void *comp, void *arg, int index);
};

#define tplg_get(ctx) ((void *)(ctx->tplg_base + ctx->tplg_offset))
Expand Down
2 changes: 1 addition & 1 deletion tools/tplg_parser/pga.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static int pga_ipc3_build(struct tplg_context *ctx, void *_pga)

/* call ctl creation callback if needed */
if (ctx->ctl_cb)
ctx->ctl_cb(ctl, volume, ctx->ctl_arg);
ctx->ctl_cb(ctl, volume, ctx->ctl_arg, 0);

/* we only care about the volume ctl - ignore others atm */
if (ctl->ops.get != 256)
Expand Down
2 changes: 1 addition & 1 deletion tools/tplg_parser/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ int tplg_new_process(struct tplg_context *ctx, void *process, size_t process_siz

/* call ctl creation callback if needed */
if (ctx->ctl_cb)
ctx->ctl_cb(ctl, process, ctx->ctl_arg);
ctx->ctl_cb(ctl, process, ctx->ctl_arg, 0);

/* Merge process and priv_data into process_ipc */
if (!priv_data)
Expand Down