xref: /openbmc/linux/sound/soc/sof/control.c (revision 09b35b41)
1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
7 //
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 //
10 
11 /* Mixer Controls */
12 
13 #include <linux/pm_runtime.h>
14 #include "sof-priv.h"
15 
16 static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
17 {
18 	if (value >= size)
19 		return volume_map[size - 1];
20 
21 	return volume_map[value];
22 }
23 
24 static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
25 {
26 	int i;
27 
28 	for (i = 0; i < size; i++) {
29 		if (volume_map[i] >= value)
30 			return i;
31 	}
32 
33 	return i - 1;
34 }
35 
36 int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
37 		       struct snd_ctl_elem_value *ucontrol)
38 {
39 	struct soc_mixer_control *sm =
40 		(struct soc_mixer_control *)kcontrol->private_value;
41 	struct snd_sof_control *scontrol = sm->dobj.private;
42 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
43 	unsigned int i, channels = scontrol->num_channels;
44 
45 	/* read back each channel */
46 	for (i = 0; i < channels; i++)
47 		ucontrol->value.integer.value[i] =
48 			ipc_to_mixer(cdata->chanv[i].value,
49 				     scontrol->volume_table, sm->max + 1);
50 
51 	return 0;
52 }
53 
54 int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
55 		       struct snd_ctl_elem_value *ucontrol)
56 {
57 	struct soc_mixer_control *sm =
58 		(struct soc_mixer_control *)kcontrol->private_value;
59 	struct snd_sof_control *scontrol = sm->dobj.private;
60 	struct snd_sof_dev *sdev = scontrol->sdev;
61 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
62 	unsigned int i, channels = scontrol->num_channels;
63 
64 	/* update each channel */
65 	for (i = 0; i < channels; i++) {
66 		cdata->chanv[i].value =
67 			mixer_to_ipc(ucontrol->value.integer.value[i],
68 				     scontrol->volume_table, sm->max + 1);
69 		cdata->chanv[i].channel = i;
70 	}
71 
72 	/* notify DSP of mixer updates */
73 	if (pm_runtime_active(sdev->dev))
74 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
75 					      SOF_IPC_COMP_SET_VALUE,
76 					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
77 					      SOF_CTRL_CMD_VOLUME,
78 					      true);
79 
80 	return 0;
81 }
82 
83 int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
84 		       struct snd_ctl_elem_value *ucontrol)
85 {
86 	struct soc_mixer_control *sm =
87 		(struct soc_mixer_control *)kcontrol->private_value;
88 	struct snd_sof_control *scontrol = sm->dobj.private;
89 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
90 	unsigned int i, channels = scontrol->num_channels;
91 
92 	/* read back each channel */
93 	for (i = 0; i < channels; i++)
94 		ucontrol->value.integer.value[i] = cdata->chanv[i].value;
95 
96 	return 0;
97 }
98 
99 int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
100 		       struct snd_ctl_elem_value *ucontrol)
101 {
102 	struct soc_mixer_control *sm =
103 		(struct soc_mixer_control *)kcontrol->private_value;
104 	struct snd_sof_control *scontrol = sm->dobj.private;
105 	struct snd_sof_dev *sdev = scontrol->sdev;
106 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
107 	unsigned int i, channels = scontrol->num_channels;
108 
109 	/* update each channel */
110 	for (i = 0; i < channels; i++) {
111 		cdata->chanv[i].value = ucontrol->value.integer.value[i];
112 		cdata->chanv[i].channel = i;
113 	}
114 
115 	/* notify DSP of mixer updates */
116 	if (pm_runtime_active(sdev->dev))
117 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
118 					      SOF_IPC_COMP_SET_VALUE,
119 					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
120 					      SOF_CTRL_CMD_SWITCH,
121 					      true);
122 
123 	return 0;
124 }
125 
126 int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
127 		     struct snd_ctl_elem_value *ucontrol)
128 {
129 	struct soc_enum *se =
130 		(struct soc_enum *)kcontrol->private_value;
131 	struct snd_sof_control *scontrol = se->dobj.private;
132 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
133 	unsigned int i, channels = scontrol->num_channels;
134 
135 	/* read back each channel */
136 	for (i = 0; i < channels; i++)
137 		ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
138 
139 	return 0;
140 }
141 
142 int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
143 		     struct snd_ctl_elem_value *ucontrol)
144 {
145 	struct soc_enum *se =
146 		(struct soc_enum *)kcontrol->private_value;
147 	struct snd_sof_control *scontrol = se->dobj.private;
148 	struct snd_sof_dev *sdev = scontrol->sdev;
149 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
150 	unsigned int i, channels = scontrol->num_channels;
151 
152 	/* update each channel */
153 	for (i = 0; i < channels; i++) {
154 		cdata->chanv[i].value = ucontrol->value.enumerated.item[i];
155 		cdata->chanv[i].channel = i;
156 	}
157 
158 	/* notify DSP of enum updates */
159 	if (pm_runtime_active(sdev->dev))
160 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
161 					      SOF_IPC_COMP_SET_VALUE,
162 					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
163 					      SOF_CTRL_CMD_ENUM,
164 					      true);
165 
166 	return 0;
167 }
168 
169 int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
170 		      struct snd_ctl_elem_value *ucontrol)
171 {
172 	struct soc_bytes_ext *be =
173 		(struct soc_bytes_ext *)kcontrol->private_value;
174 	struct snd_sof_control *scontrol = be->dobj.private;
175 	struct snd_sof_dev *sdev = scontrol->sdev;
176 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
177 	struct sof_abi_hdr *data = cdata->data;
178 	size_t size;
179 	int ret = 0;
180 
181 	if (be->max > sizeof(ucontrol->value.bytes.data)) {
182 		dev_err_ratelimited(sdev->dev,
183 				    "error: data max %d exceeds ucontrol data array size\n",
184 				    be->max);
185 		return -EINVAL;
186 	}
187 
188 	size = data->size + sizeof(*data);
189 	if (size > be->max) {
190 		dev_err_ratelimited(sdev->dev,
191 				    "error: DSP sent %zu bytes max is %d\n",
192 				    size, be->max);
193 		ret = -EINVAL;
194 		goto out;
195 	}
196 
197 	/* copy back to kcontrol */
198 	memcpy(ucontrol->value.bytes.data, data, size);
199 
200 out:
201 	return ret;
202 }
203 
204 int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
205 		      struct snd_ctl_elem_value *ucontrol)
206 {
207 	struct soc_bytes_ext *be =
208 		(struct soc_bytes_ext *)kcontrol->private_value;
209 	struct snd_sof_control *scontrol = be->dobj.private;
210 	struct snd_sof_dev *sdev = scontrol->sdev;
211 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
212 	struct sof_abi_hdr *data = cdata->data;
213 	size_t size = data->size + sizeof(*data);
214 
215 	if (be->max > sizeof(ucontrol->value.bytes.data)) {
216 		dev_err_ratelimited(sdev->dev,
217 				    "error: data max %d exceeds ucontrol data array size\n",
218 				    be->max);
219 		return -EINVAL;
220 	}
221 
222 	if (size > be->max) {
223 		dev_err_ratelimited(sdev->dev,
224 				    "error: size too big %zu bytes max is %d\n",
225 				    size, be->max);
226 		return -EINVAL;
227 	}
228 
229 	/* copy from kcontrol */
230 	memcpy(data, ucontrol->value.bytes.data, size);
231 
232 	/* notify DSP of byte control updates */
233 	if (pm_runtime_active(sdev->dev))
234 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
235 					      SOF_IPC_COMP_SET_DATA,
236 					      SOF_CTRL_TYPE_DATA_SET,
237 					      scontrol->cmd,
238 					      true);
239 
240 	return 0;
241 }
242 
243 int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
244 			  const unsigned int __user *binary_data,
245 			  unsigned int size)
246 {
247 	struct soc_bytes_ext *be =
248 		(struct soc_bytes_ext *)kcontrol->private_value;
249 	struct snd_sof_control *scontrol = be->dobj.private;
250 	struct snd_sof_dev *sdev = scontrol->sdev;
251 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
252 	struct snd_ctl_tlv header;
253 	const struct snd_ctl_tlv __user *tlvd =
254 		(const struct snd_ctl_tlv __user *)binary_data;
255 
256 	/*
257 	 * The beginning of bytes data contains a header from where
258 	 * the length (as bytes) is needed to know the correct copy
259 	 * length of data from tlvd->tlv.
260 	 */
261 	if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv)))
262 		return -EFAULT;
263 
264 	/* be->max is coming from topology */
265 	if (header.length > be->max) {
266 		dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n",
267 				    header.length, be->max);
268 		return -EINVAL;
269 	}
270 
271 	/* Check that header id matches the command */
272 	if (header.numid != scontrol->cmd) {
273 		dev_err_ratelimited(sdev->dev,
274 				    "error: incorrect numid %d\n",
275 				    header.numid);
276 		return -EINVAL;
277 	}
278 
279 	if (copy_from_user(cdata->data, tlvd->tlv, header.length))
280 		return -EFAULT;
281 
282 	if (cdata->data->magic != SOF_ABI_MAGIC) {
283 		dev_err_ratelimited(sdev->dev,
284 				    "error: Wrong ABI magic 0x%08x.\n",
285 				    cdata->data->magic);
286 		return -EINVAL;
287 	}
288 
289 	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
290 		dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n",
291 				    cdata->data->abi);
292 		return -EINVAL;
293 	}
294 
295 	if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) {
296 		dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n");
297 		return -EINVAL;
298 	}
299 
300 	/* notify DSP of byte control updates */
301 	if (pm_runtime_active(sdev->dev))
302 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
303 					      SOF_IPC_COMP_SET_DATA,
304 					      SOF_CTRL_TYPE_DATA_SET,
305 					      scontrol->cmd,
306 					      true);
307 
308 	return 0;
309 }
310 
311 int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
312 			  unsigned int __user *binary_data,
313 			  unsigned int size)
314 {
315 	struct soc_bytes_ext *be =
316 		(struct soc_bytes_ext *)kcontrol->private_value;
317 	struct snd_sof_control *scontrol = be->dobj.private;
318 	struct snd_sof_dev *sdev = scontrol->sdev;
319 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
320 	struct snd_ctl_tlv header;
321 	struct snd_ctl_tlv __user *tlvd =
322 		(struct snd_ctl_tlv __user *)binary_data;
323 	int data_size;
324 	int ret = 0;
325 
326 	/*
327 	 * Decrement the limit by ext bytes header size to
328 	 * ensure the user space buffer is not exceeded.
329 	 */
330 	size -= sizeof(const struct snd_ctl_tlv);
331 
332 	/* set the ABI header values */
333 	cdata->data->magic = SOF_ABI_MAGIC;
334 	cdata->data->abi = SOF_ABI_VERSION;
335 
336 	/* Prevent read of other kernel data or possibly corrupt response */
337 	data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
338 
339 	/* check data size doesn't exceed max coming from topology */
340 	if (data_size > be->max) {
341 		dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n",
342 				    data_size, be->max);
343 		ret = -EINVAL;
344 		goto out;
345 	}
346 
347 	header.numid = scontrol->cmd;
348 	header.length = data_size;
349 	if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) {
350 		ret = -EFAULT;
351 		goto out;
352 	}
353 
354 	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
355 		ret = -EFAULT;
356 
357 out:
358 	return ret;
359 }
360