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