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