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. */
15static 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
120unlock:
121	if (lock)
122		mutex_unlock(&swidget->setup_mutex);
123
124	return ret;
125}
126
127static 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
154static 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
172static 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
205static 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
221static 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
253static 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
269static 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
301static 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
333static 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
366static 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
443err_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
453static 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
509static 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
515static 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
522static 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
550static 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
662static 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
699static int
700sof_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
716const 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