1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2019 Intel Corporation. All rights reserved.
4 //
5 // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
6 
7 /* Topology parser */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <stddef.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <ipc/topology.h>
16 #include <sof/lib/uuid.h>
17 #include <sof/ipc/topology.h>
18 #include <tplg_parser/topology.h>
19 #include <tplg_parser/tokens.h>
20 
tplg_get_single_control(struct tplg_context * ctx,struct snd_soc_tplg_ctl_hdr ** ctl,struct snd_soc_tplg_private ** priv_data)21 int tplg_get_single_control(struct tplg_context *ctx,
22 			    struct snd_soc_tplg_ctl_hdr **ctl,
23 			    struct snd_soc_tplg_private **priv_data)
24 {
25 	struct snd_soc_tplg_ctl_hdr *ctl_hdr;
26 	struct snd_soc_tplg_mixer_control *mixer_ctl = NULL;
27 	struct snd_soc_tplg_enum_control *enum_ctl = NULL;
28 	struct snd_soc_tplg_bytes_control *bytes_ctl = NULL;
29 
30 	/* These are set if success */
31 	*ctl = NULL;
32 	*priv_data = NULL;
33 
34 	ctl_hdr = tplg_get(ctx);
35 
36 	/* load control based on type */
37 	switch (ctl_hdr->ops.info) {
38 	case SND_SOC_TPLG_CTL_VOLSW:
39 	case SND_SOC_TPLG_CTL_STROBE:
40 	case SND_SOC_TPLG_CTL_VOLSW_SX:
41 	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
42 	case SND_SOC_TPLG_CTL_RANGE:
43 	case SND_SOC_TPLG_DAPM_CTL_VOLSW:
44 		/* load mixer type control */
45 		mixer_ctl = (struct snd_soc_tplg_mixer_control *)ctl_hdr;
46 		if (priv_data)
47 			*priv_data = &mixer_ctl->priv;
48 		/* ctl is after private data */
49 		*ctl = tplg_get_object_priv(ctx, mixer_ctl, mixer_ctl->priv.size);
50 		break;
51 
52 	case SND_SOC_TPLG_CTL_ENUM:
53 	case SND_SOC_TPLG_CTL_ENUM_VALUE:
54 	case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
55 	case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
56 	case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
57 		/* load enum type control */
58 		enum_ctl = (struct snd_soc_tplg_enum_control *)ctl_hdr;
59 		if (priv_data)
60 			*priv_data = &enum_ctl->priv;
61 		/* ctl is after private data */
62 		*ctl = tplg_get_object_priv(ctx, enum_ctl, enum_ctl->priv.size);
63 		break;
64 	case SND_SOC_TPLG_CTL_BYTES:
65 		/* load bytes type control */
66 		bytes_ctl = (struct snd_soc_tplg_bytes_control *)ctl_hdr;
67 		if (priv_data)
68 			*priv_data = &bytes_ctl->priv;
69 		/* ctl is after private data */
70 		*ctl = tplg_get_object_priv(ctx, bytes_ctl, bytes_ctl->priv.size);
71 		break;
72 
73 	default:
74 		printf("info: control type %d not supported\n",
75 		       ctl_hdr->ops.info);
76 		return -EINVAL;
77 	}
78 
79 	return 0;
80 }
81 
82 /* load dapm widget kcontrols
83  * we don't use controls in the fuzzer atm.
84  * so just skip to the next dapm widget
85  */
tplg_create_controls(struct tplg_context * ctx,int num_kcontrols,struct snd_soc_tplg_ctl_hdr * rctl,size_t max_ctl_size,void * object)86 int tplg_create_controls(struct tplg_context *ctx, int num_kcontrols,
87 			 struct snd_soc_tplg_ctl_hdr *rctl,
88 			 size_t max_ctl_size, void *object)
89 {
90 	struct snd_soc_tplg_ctl_hdr *ctl_hdr = NULL;
91 	struct snd_soc_tplg_mixer_control *mixer_ctl;
92 	struct snd_soc_tplg_enum_control *enum_ctl;
93 	struct snd_soc_tplg_bytes_control *bytes_ctl;
94 	int j, ret = 0;
95 
96 	for (j = 0; j < num_kcontrols; j++) {
97 
98 		ctl_hdr = tplg_get(ctx);
99 
100 		/* load control based on type */
101 		switch (ctl_hdr->ops.info) {
102 		case SND_SOC_TPLG_CTL_VOLSW:
103 		case SND_SOC_TPLG_CTL_STROBE:
104 		case SND_SOC_TPLG_CTL_VOLSW_SX:
105 		case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
106 		case SND_SOC_TPLG_CTL_RANGE:
107 		case SND_SOC_TPLG_DAPM_CTL_VOLSW:
108 			/* load mixer type control */
109 			mixer_ctl = (struct snd_soc_tplg_mixer_control *)ctl_hdr;
110 			/* ctl is after private data */
111 			tplg_get_object_priv(ctx, mixer_ctl, mixer_ctl->priv.size);
112 			break;
113 
114 		case SND_SOC_TPLG_CTL_ENUM:
115 		case SND_SOC_TPLG_CTL_ENUM_VALUE:
116 		case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
117 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
118 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
119 			/* load enum_ctl type control */
120 			enum_ctl = (struct snd_soc_tplg_enum_control *)ctl_hdr;
121 			/* ctl is after private data */
122 			tplg_get_object_priv(ctx, enum_ctl, enum_ctl->priv.size);
123 			break;
124 
125 		case SND_SOC_TPLG_CTL_BYTES:
126 			/* load bytes_ctl type control */
127 			bytes_ctl = (struct snd_soc_tplg_bytes_control *)ctl_hdr;
128 			/* ctl is after private data */
129 			tplg_get_object_priv(ctx, bytes_ctl, bytes_ctl->priv.size);
130 			break;
131 		default:
132 			printf("info: control type %d not supported\n",
133 			       ctl_hdr->ops.info);
134 			return -EINVAL;
135 		}
136 
137 		if (ctx->ctl_cb && object)
138 			ctx->ctl_cb(ctl_hdr, object, ctx->ctl_arg);
139 	}
140 
141 	if (rctl && ctl_hdr) {
142 		/* make sure the CTL will fit if we need to copy it for others */
143 		if (ctl_hdr->size > max_ctl_size) {
144 			fprintf(stderr, "error: failed control control copy\n");
145 			ret = -EINVAL;
146 			goto err;
147 		}
148 		memcpy(rctl, ctl_hdr, ctl_hdr->size);
149 	}
150 err:
151 	return ret;
152 }
153