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