Mention branches and keyring.
[releases.git] / sof / ipc3-control.c
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 };