// SPDX-License-Identifier: BSD-3-Clause // // Copyright(c) 2019 Intel Corporation. All rights reserved. // // Author: Ranjani Sridharan /* Topology parser */ #include #include #include #include #include #include #include #include #include #include #include int tplg_get_single_control(struct tplg_context *ctx, struct snd_soc_tplg_ctl_hdr **ctl, struct snd_soc_tplg_private **priv_data) { struct snd_soc_tplg_ctl_hdr *ctl_hdr; struct snd_soc_tplg_mixer_control *mixer_ctl = NULL; struct snd_soc_tplg_enum_control *enum_ctl = NULL; struct snd_soc_tplg_bytes_control *bytes_ctl = NULL; /* These are set if success */ *ctl = NULL; *priv_data = NULL; ctl_hdr = tplg_get(ctx); /* load control based on type */ switch (ctl_hdr->ops.info) { case SND_SOC_TPLG_CTL_VOLSW: case SND_SOC_TPLG_CTL_STROBE: case SND_SOC_TPLG_CTL_VOLSW_SX: case SND_SOC_TPLG_CTL_VOLSW_XR_SX: case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_DAPM_CTL_VOLSW: /* load mixer type control */ mixer_ctl = (struct snd_soc_tplg_mixer_control *)ctl_hdr; if (priv_data) *priv_data = &mixer_ctl->priv; /* ctl is after private data */ *ctl = tplg_get_object_priv(ctx, mixer_ctl, mixer_ctl->priv.size); break; case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: /* load enum type control */ enum_ctl = (struct snd_soc_tplg_enum_control *)ctl_hdr; if (priv_data) *priv_data = &enum_ctl->priv; /* ctl is after private data */ *ctl = tplg_get_object_priv(ctx, enum_ctl, enum_ctl->priv.size); break; case SND_SOC_TPLG_CTL_BYTES: /* load bytes type control */ bytes_ctl = (struct snd_soc_tplg_bytes_control *)ctl_hdr; if (priv_data) *priv_data = &bytes_ctl->priv; /* ctl is after private data */ *ctl = tplg_get_object_priv(ctx, bytes_ctl, bytes_ctl->priv.size); break; default: printf("info: control type %d not supported\n", ctl_hdr->ops.info); return -EINVAL; } return 0; } /* load dapm widget kcontrols * we don't use controls in the fuzzer atm. * so just skip to the next dapm widget */ int tplg_create_controls(struct tplg_context *ctx, int num_kcontrols, struct snd_soc_tplg_ctl_hdr *rctl, size_t max_ctl_size, void *object) { struct snd_soc_tplg_ctl_hdr *ctl_hdr = NULL; 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++) { ctl_hdr = tplg_get(ctx); /* load control based on type */ switch (ctl_hdr->ops.info) { case SND_SOC_TPLG_CTL_VOLSW: case SND_SOC_TPLG_CTL_STROBE: case SND_SOC_TPLG_CTL_VOLSW_SX: 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 */ tplg_get_object_priv(ctx, mixer_ctl, mixer_ctl->priv.size); break; case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: 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 */ tplg_get_object_priv(ctx, bytes_ctl, bytes_ctl->priv.size); break; default: printf("info: control type %d not supported\n", ctl_hdr->ops.info); return -EINVAL; } if (ctx->ctl_cb && object) ctx->ctl_cb(ctl_hdr, object, ctx->ctl_arg, index); } if (rctl && ctl_hdr) { /* make sure the CTL will fit if we need to copy it for others */ if (ctl_hdr->size > max_ctl_size) { fprintf(stderr, "error: failed control control copy\n"); ret = -EINVAL; goto err; } memcpy(rctl, ctl_hdr, ctl_hdr->size); } err: return ret; }