xref: /openbmc/linux/sound/soc/sof/ipc3-control.c (revision 8056dc04)
1 // SPDX-License-Identifier: (GPL-2.0-only 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) 2021 Intel Corporation. All rights reserved.
7 //
8 //
9 
10 #include "sof-priv.h"
11 #include "sof-audio.h"
12 #include "ipc3-priv.h"
13 
14 /* IPC set()/get() for kcontrols. */
15 static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol,
16 					  bool set, bool lock)
17 {
18 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp);
19 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
20 	const struct sof_ipc_ops *iops = sdev->ipc->ops;
21 	enum sof_ipc_ctrl_type ctrl_type;
22 	struct snd_sof_widget *swidget;
23 	bool widget_found = false;
24 	u32 ipc_cmd, msg_bytes;
25 	int ret = 0;
26 
27 	list_for_each_entry(swidget, &sdev->widget_list, list) {
28 		if (swidget->comp_id == scontrol->comp_id) {
29 			widget_found = true;
30 			break;
31 		}
32 	}
33 
34 	if (!widget_found) {
35 		dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__,
36 			scontrol->comp_id);
37 		return -EINVAL;
38 	}
39 
40 	if (lock)
41 		mutex_lock(&swidget->setup_mutex);
42 	else
43 		lockdep_assert_held(&swidget->setup_mutex);
44 
45 	/*
46 	 * Volatile controls should always be part of static pipelines and the
47 	 * widget use_count would always be > 0 in this case. For the others,
48 	 * just return the cached value if the widget is not set up.
49 	 */
50 	if (!swidget->use_count)
51 		goto unlock;
52 
53 	/*
54 	 * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the
55 	 * direction
56 	 * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently
57 	 *	 for ctrl_type
58 	 */
59 	if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
60 		ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA;
61 		ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET;
62 	} else {
63 		ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE;
64 		ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET;
65 	}
66 
67 	cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
68 	cdata->type = ctrl_type;
69 	cdata->comp_id = scontrol->comp_id;
70 	cdata->msg_index = 0;
71 
72 	/* calculate header and data size */
73 	switch (cdata->type) {
74 	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
75 	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
76 		cdata->num_elems = scontrol->num_channels;
77 
78 		msg_bytes = scontrol->num_channels *
79 			    sizeof(struct sof_ipc_ctrl_value_chan);
80 		msg_bytes += sizeof(struct sof_ipc_ctrl_data);
81 		break;
82 	case SOF_CTRL_TYPE_DATA_GET:
83 	case SOF_CTRL_TYPE_DATA_SET:
84 		cdata->num_elems = cdata->data->size;
85 
86 		msg_bytes = cdata->data->size;
87 		msg_bytes += sizeof(struct sof_ipc_ctrl_data) +
88 			     sizeof(struct sof_abi_hdr);
89 		break;
90 	default:
91 		ret = -EINVAL;
92 		goto unlock;
93 	}
94 
95 	cdata->rhdr.hdr.size = msg_bytes;
96 	cdata->elems_remaining = 0;
97 
98 	ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set);
99 
100 unlock:
101 	if (lock)
102 		mutex_unlock(&swidget->setup_mutex);
103 
104 	return ret;
105 }
106 
107 static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
108 {
109 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
110 	struct snd_soc_component *scomp = scontrol->scomp;
111 	int ret;
112 
113 	if (!scontrol->comp_data_dirty)
114 		return;
115 
116 	if (!pm_runtime_active(scomp->dev))
117 		return;
118 
119 	/* set the ABI header values */
120 	cdata->data->magic = SOF_ABI_MAGIC;
121 	cdata->data->abi = SOF_ABI_VERSION;
122 
123 	/* refresh the component data from DSP */
124 	scontrol->comp_data_dirty = false;
125 	ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, true);
126 	if (ret < 0) {
127 		dev_err(scomp->dev, "Failed to get control data: %d\n", ret);
128 
129 		/* Set the flag to re-try next time to get the data */
130 		scontrol->comp_data_dirty = true;
131 	}
132 }
133 
134 static int sof_ipc3_volume_get(struct snd_sof_control *scontrol,
135 			       struct snd_ctl_elem_value *ucontrol)
136 {
137 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
138 	unsigned int channels = scontrol->num_channels;
139 	unsigned int i;
140 
141 	snd_sof_refresh_control(scontrol);
142 
143 	/* read back each channel */
144 	for (i = 0; i < channels; i++)
145 		ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
146 								scontrol->volume_table,
147 								scontrol->max + 1);
148 
149 	return 0;
150 }
151 
152 static bool sof_ipc3_volume_put(struct snd_sof_control *scontrol,
153 				struct snd_ctl_elem_value *ucontrol)
154 {
155 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
156 	struct snd_soc_component *scomp = scontrol->scomp;
157 	unsigned int channels = scontrol->num_channels;
158 	unsigned int i;
159 	bool change = false;
160 
161 	/* update each channel */
162 	for (i = 0; i < channels; i++) {
163 		u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
164 					 scontrol->volume_table, scontrol->max + 1);
165 
166 		change = change || (value != cdata->chanv[i].value);
167 		cdata->chanv[i].channel = i;
168 		cdata->chanv[i].value = value;
169 	}
170 
171 	/* notify DSP of mixer updates */
172 	if (pm_runtime_active(scomp->dev)) {
173 		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
174 
175 		if (ret < 0) {
176 			dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
177 				scontrol->name);
178 			return false;
179 		}
180 	}
181 
182 	return change;
183 }
184 
185 static int sof_ipc3_switch_get(struct snd_sof_control *scontrol,
186 			       struct snd_ctl_elem_value *ucontrol)
187 {
188 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
189 	unsigned int channels = scontrol->num_channels;
190 	unsigned int i;
191 
192 	snd_sof_refresh_control(scontrol);
193 
194 	/* read back each channel */
195 	for (i = 0; i < channels; i++)
196 		ucontrol->value.integer.value[i] = cdata->chanv[i].value;
197 
198 	return 0;
199 }
200 
201 static bool sof_ipc3_switch_put(struct snd_sof_control *scontrol,
202 				struct snd_ctl_elem_value *ucontrol)
203 {
204 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
205 	struct snd_soc_component *scomp = scontrol->scomp;
206 	unsigned int channels = scontrol->num_channels;
207 	unsigned int i;
208 	bool change = false;
209 	u32 value;
210 
211 	/* update each channel */
212 	for (i = 0; i < channels; i++) {
213 		value = ucontrol->value.integer.value[i];
214 		change = change || (value != cdata->chanv[i].value);
215 		cdata->chanv[i].channel = i;
216 		cdata->chanv[i].value = value;
217 	}
218 
219 	/* notify DSP of mixer updates */
220 	if (pm_runtime_active(scomp->dev)) {
221 		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
222 
223 		if (ret < 0) {
224 			dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
225 				scontrol->name);
226 			return false;
227 		}
228 	}
229 
230 	return change;
231 }
232 
233 static int sof_ipc3_enum_get(struct snd_sof_control *scontrol,
234 			     struct snd_ctl_elem_value *ucontrol)
235 {
236 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
237 	unsigned int channels = scontrol->num_channels;
238 	unsigned int i;
239 
240 	snd_sof_refresh_control(scontrol);
241 
242 	/* read back each channel */
243 	for (i = 0; i < channels; i++)
244 		ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
245 
246 	return 0;
247 }
248 
249 static bool sof_ipc3_enum_put(struct snd_sof_control *scontrol,
250 			      struct snd_ctl_elem_value *ucontrol)
251 {
252 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
253 	struct snd_soc_component *scomp = scontrol->scomp;
254 	unsigned int channels = scontrol->num_channels;
255 	unsigned int i;
256 	bool change = false;
257 	u32 value;
258 
259 	/* update each channel */
260 	for (i = 0; i < channels; i++) {
261 		value = ucontrol->value.enumerated.item[i];
262 		change = change || (value != cdata->chanv[i].value);
263 		cdata->chanv[i].channel = i;
264 		cdata->chanv[i].value = value;
265 	}
266 
267 	/* notify DSP of enum updates */
268 	if (pm_runtime_active(scomp->dev)) {
269 		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
270 
271 		if (ret < 0) {
272 			dev_err(scomp->dev, "Failed to set enum updates for %s\n",
273 				scontrol->name);
274 			return false;
275 		}
276 	}
277 
278 	return change;
279 }
280 
281 static int sof_ipc3_bytes_get(struct snd_sof_control *scontrol,
282 			      struct snd_ctl_elem_value *ucontrol)
283 {
284 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
285 	struct snd_soc_component *scomp = scontrol->scomp;
286 	struct sof_abi_hdr *data = cdata->data;
287 	size_t size;
288 
289 	snd_sof_refresh_control(scontrol);
290 
291 	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
292 		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
293 				    scontrol->max_size);
294 		return -EINVAL;
295 	}
296 
297 	/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
298 	if (data->size > scontrol->max_size - sizeof(*data)) {
299 		dev_err_ratelimited(scomp->dev,
300 				    "%u bytes of control data is invalid, max is %zu\n",
301 				    data->size, scontrol->max_size - sizeof(*data));
302 		return -EINVAL;
303 	}
304 
305 	size = data->size + sizeof(*data);
306 
307 	/* copy back to kcontrol */
308 	memcpy(ucontrol->value.bytes.data, data, size);
309 
310 	return 0;
311 }
312 
313 static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol,
314 			      struct snd_ctl_elem_value *ucontrol)
315 {
316 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
317 	struct snd_soc_component *scomp = scontrol->scomp;
318 	struct sof_abi_hdr *data = cdata->data;
319 	size_t size;
320 
321 	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
322 		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
323 				    scontrol->max_size);
324 		return -EINVAL;
325 	}
326 
327 	/* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
328 	if (data->size > scontrol->max_size - sizeof(*data)) {
329 		dev_err_ratelimited(scomp->dev, "data size too big %u bytes max is %zu\n",
330 				    data->size, scontrol->max_size - sizeof(*data));
331 		return -EINVAL;
332 	}
333 
334 	size = data->size + sizeof(*data);
335 
336 	/* copy from kcontrol */
337 	memcpy(data, ucontrol->value.bytes.data, size);
338 
339 	/* notify DSP of byte control updates */
340 	if (pm_runtime_active(scomp->dev))
341 		return sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
342 
343 	return 0;
344 }
345 
346 static int sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
347 				  const unsigned int __user *binary_data, unsigned int size)
348 {
349 	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
350 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
351 	struct snd_soc_component *scomp = scontrol->scomp;
352 	struct snd_ctl_tlv header;
353 	size_t data_size;
354 
355 	snd_sof_refresh_control(scontrol);
356 
357 	/*
358 	 * Decrement the limit by ext bytes header size to
359 	 * ensure the user space buffer is not exceeded.
360 	 */
361 	if (size < sizeof(struct snd_ctl_tlv))
362 		return -ENOSPC;
363 
364 	size -= sizeof(struct snd_ctl_tlv);
365 
366 	/* set the ABI header values */
367 	cdata->data->magic = SOF_ABI_MAGIC;
368 	cdata->data->abi = SOF_ABI_VERSION;
369 
370 	/* check data size doesn't exceed max coming from topology */
371 	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
372 		dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
373 				    cdata->data->size,
374 				    scontrol->max_size - sizeof(struct sof_abi_hdr));
375 		return -EINVAL;
376 	}
377 
378 	data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
379 
380 	/* make sure we don't exceed size provided by user space for data */
381 	if (data_size > size)
382 		return -ENOSPC;
383 
384 	header.numid = cdata->cmd;
385 	header.length = data_size;
386 	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
387 		return -EFAULT;
388 
389 	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
390 		return -EFAULT;
391 
392 	return 0;
393 }
394 
395 static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
396 				  const unsigned int __user *binary_data,
397 				  unsigned int size)
398 {
399 	const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data;
400 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
401 	struct snd_soc_component *scomp = scontrol->scomp;
402 	struct snd_ctl_tlv header;
403 
404 	/*
405 	 * The beginning of bytes data contains a header from where
406 	 * the length (as bytes) is needed to know the correct copy
407 	 * length of data from tlvd->tlv.
408 	 */
409 	if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
410 		return -EFAULT;
411 
412 	/* make sure TLV info is consistent */
413 	if (header.length + sizeof(struct snd_ctl_tlv) > size) {
414 		dev_err_ratelimited(scomp->dev, "Inconsistent TLV, data %d + header %zu > %d\n",
415 				    header.length, sizeof(struct snd_ctl_tlv), size);
416 		return -EINVAL;
417 	}
418 
419 	/* be->max is coming from topology */
420 	if (header.length > scontrol->max_size) {
421 		dev_err_ratelimited(scomp->dev, "Bytes data size %d exceeds max %zu\n",
422 				    header.length, scontrol->max_size);
423 		return -EINVAL;
424 	}
425 
426 	/* Check that header id matches the command */
427 	if (header.numid != cdata->cmd) {
428 		dev_err_ratelimited(scomp->dev, "Incorrect command for bytes put %d\n",
429 				    header.numid);
430 		return -EINVAL;
431 	}
432 
433 	if (copy_from_user(cdata->data, tlvd->tlv, header.length))
434 		return -EFAULT;
435 
436 	if (cdata->data->magic != SOF_ABI_MAGIC) {
437 		dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic);
438 		return -EINVAL;
439 	}
440 
441 	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
442 		dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n",
443 				    cdata->data->abi);
444 		return -EINVAL;
445 	}
446 
447 	/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
448 	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
449 		dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
450 		return -EINVAL;
451 	}
452 
453 	/* notify DSP of byte control updates */
454 	if (pm_runtime_active(scomp->dev))
455 		return sof_ipc3_set_get_kcontrol_data(scontrol, true, true);
456 
457 	return 0;
458 }
459 
460 static int sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
461 					   const unsigned int __user *binary_data,
462 					   unsigned int size)
463 {
464 	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
465 	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
466 	struct snd_soc_component *scomp = scontrol->scomp;
467 	struct snd_ctl_tlv header;
468 	size_t data_size;
469 	int ret;
470 
471 	/*
472 	 * Decrement the limit by ext bytes header size to
473 	 * ensure the user space buffer is not exceeded.
474 	 */
475 	if (size < sizeof(struct snd_ctl_tlv))
476 		return -ENOSPC;
477 
478 	size -= sizeof(struct snd_ctl_tlv);
479 
480 	/* set the ABI header values */
481 	cdata->data->magic = SOF_ABI_MAGIC;
482 	cdata->data->abi = SOF_ABI_VERSION;
483 
484 	/* get all the component data from DSP */
485 	ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, true);
486 	if (ret < 0)
487 		return ret;
488 
489 	/* check data size doesn't exceed max coming from topology */
490 	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
491 		dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
492 				    cdata->data->size,
493 				    scontrol->max_size - sizeof(struct sof_abi_hdr));
494 		return -EINVAL;
495 	}
496 
497 	data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
498 
499 	/* make sure we don't exceed size provided by user space for data */
500 	if (data_size > size)
501 		return -ENOSPC;
502 
503 	header.numid = cdata->cmd;
504 	header.length = data_size;
505 	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
506 		return -EFAULT;
507 
508 	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
509 		return -EFAULT;
510 
511 	return ret;
512 }
513 
514 static void snd_sof_update_control(struct snd_sof_control *scontrol,
515 				   struct sof_ipc_ctrl_data *cdata)
516 {
517 	struct snd_soc_component *scomp = scontrol->scomp;
518 	struct sof_ipc_ctrl_data *local_cdata;
519 	int i;
520 
521 	local_cdata = scontrol->ipc_control_data;
522 
523 	if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
524 		if (cdata->num_elems != local_cdata->data->size) {
525 			dev_err(scomp->dev, "cdata binary size mismatch %u - %u\n",
526 				cdata->num_elems, local_cdata->data->size);
527 			return;
528 		}
529 
530 		/* copy the new binary data */
531 		memcpy(local_cdata->data, cdata->data, cdata->num_elems);
532 	} else if (cdata->num_elems != scontrol->num_channels) {
533 		dev_err(scomp->dev, "cdata channel count mismatch %u - %d\n",
534 			cdata->num_elems, scontrol->num_channels);
535 	} else {
536 		/* copy the new values */
537 		for (i = 0; i < cdata->num_elems; i++)
538 			local_cdata->chanv[i].value = cdata->chanv[i].value;
539 	}
540 }
541 
542 static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_message)
543 {
544 	struct sof_ipc_ctrl_data *cdata = ipc_control_message;
545 	struct snd_soc_dapm_widget *widget;
546 	struct snd_sof_control *scontrol;
547 	struct snd_sof_widget *swidget;
548 	struct snd_kcontrol *kc = NULL;
549 	struct soc_mixer_control *sm;
550 	struct soc_bytes_ext *be;
551 	size_t expected_size;
552 	struct soc_enum *se;
553 	bool found = false;
554 	int i, type;
555 
556 	if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET ||
557 	    cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) {
558 		dev_err(sdev->dev, "Component data is not supported in control notification\n");
559 		return;
560 	}
561 
562 	/* Find the swidget first */
563 	list_for_each_entry(swidget, &sdev->widget_list, list) {
564 		if (swidget->comp_id == cdata->comp_id) {
565 			found = true;
566 			break;
567 		}
568 	}
569 
570 	if (!found)
571 		return;
572 
573 	/* Translate SOF cmd to TPLG type */
574 	switch (cdata->cmd) {
575 	case SOF_CTRL_CMD_VOLUME:
576 	case SOF_CTRL_CMD_SWITCH:
577 		type = SND_SOC_TPLG_TYPE_MIXER;
578 		break;
579 	case SOF_CTRL_CMD_BINARY:
580 		type = SND_SOC_TPLG_TYPE_BYTES;
581 		break;
582 	case SOF_CTRL_CMD_ENUM:
583 		type = SND_SOC_TPLG_TYPE_ENUM;
584 		break;
585 	default:
586 		dev_err(sdev->dev, "Unknown cmd %u in %s\n", cdata->cmd, __func__);
587 		return;
588 	}
589 
590 	widget = swidget->widget;
591 	for (i = 0; i < widget->num_kcontrols; i++) {
592 		/* skip non matching types or non matching indexes within type */
593 		if (widget->dobj.widget.kcontrol_type[i] == type &&
594 		    widget->kcontrol_news[i].index == cdata->index) {
595 			kc = widget->kcontrols[i];
596 			break;
597 		}
598 	}
599 
600 	if (!kc)
601 		return;
602 
603 	switch (cdata->cmd) {
604 	case SOF_CTRL_CMD_VOLUME:
605 	case SOF_CTRL_CMD_SWITCH:
606 		sm = (struct soc_mixer_control *)kc->private_value;
607 		scontrol = sm->dobj.private;
608 		break;
609 	case SOF_CTRL_CMD_BINARY:
610 		be = (struct soc_bytes_ext *)kc->private_value;
611 		scontrol = be->dobj.private;
612 		break;
613 	case SOF_CTRL_CMD_ENUM:
614 		se = (struct soc_enum *)kc->private_value;
615 		scontrol = se->dobj.private;
616 		break;
617 	default:
618 		return;
619 	}
620 
621 	expected_size = sizeof(struct sof_ipc_ctrl_data);
622 	switch (cdata->type) {
623 	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
624 	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
625 		expected_size += cdata->num_elems *
626 				 sizeof(struct sof_ipc_ctrl_value_chan);
627 		break;
628 	case SOF_CTRL_TYPE_DATA_GET:
629 	case SOF_CTRL_TYPE_DATA_SET:
630 		expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr);
631 		break;
632 	default:
633 		return;
634 	}
635 
636 	if (cdata->rhdr.hdr.size != expected_size) {
637 		dev_err(sdev->dev, "Component notification size mismatch\n");
638 		return;
639 	}
640 
641 	if (cdata->num_elems)
642 		/*
643 		 * The message includes the updated value/data, update the
644 		 * control's local cache using the received notification
645 		 */
646 		snd_sof_update_control(scontrol, cdata);
647 	else
648 		/* Mark the scontrol that the value/data is changed in SOF */
649 		scontrol->comp_data_dirty = true;
650 
651 	snd_ctl_notify_one(swidget->scomp->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
652 }
653 
654 static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev,
655 					  struct snd_sof_widget *swidget)
656 {
657 	struct snd_sof_control *scontrol;
658 	int ret;
659 
660 	/* set up all controls for the widget */
661 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
662 		if (scontrol->comp_id == swidget->comp_id) {
663 			/* set kcontrol data in DSP */
664 			ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, false);
665 			if (ret < 0) {
666 				dev_err(sdev->dev,
667 					"kcontrol %d set up failed for widget %s\n",
668 					scontrol->comp_id, swidget->widget->name);
669 				return ret;
670 			}
671 
672 			/*
673 			 * Read back the data from the DSP for static widgets.
674 			 * This is particularly useful for binary kcontrols
675 			 * associated with static pipeline widgets to initialize
676 			 * the data size to match that in the DSP.
677 			 */
678 			if (swidget->dynamic_pipeline_widget)
679 				continue;
680 
681 			ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, false);
682 			if (ret < 0)
683 				dev_warn(sdev->dev,
684 					 "kcontrol %d read failed for widget %s\n",
685 					 scontrol->comp_id, swidget->widget->name);
686 		}
687 
688 	return 0;
689 }
690 
691 static int
692 sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
693 {
694 	int i;
695 
696 	/* init the volume table */
697 	scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
698 	if (!scontrol->volume_table)
699 		return -ENOMEM;
700 
701 	/* populate the volume table */
702 	for (i = 0; i < size ; i++)
703 		scontrol->volume_table[i] = vol_compute_gain(i, tlv);
704 
705 	return 0;
706 }
707 
708 const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
709 	.volume_put = sof_ipc3_volume_put,
710 	.volume_get = sof_ipc3_volume_get,
711 	.switch_put = sof_ipc3_switch_put,
712 	.switch_get = sof_ipc3_switch_get,
713 	.enum_put = sof_ipc3_enum_put,
714 	.enum_get = sof_ipc3_enum_get,
715 	.bytes_put = sof_ipc3_bytes_put,
716 	.bytes_get = sof_ipc3_bytes_get,
717 	.bytes_ext_put = sof_ipc3_bytes_ext_put,
718 	.bytes_ext_get = sof_ipc3_bytes_ext_get,
719 	.bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get,
720 	.update = sof_ipc3_control_update,
721 	.widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup,
722 	.set_up_volume_table = sof_ipc3_set_up_volume_table,
723 };
724