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