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. */
sof_ipc3_set_get_kcontrol_data(struct snd_sof_control * scontrol,bool set,bool lock)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
snd_sof_refresh_control(struct snd_sof_control * scontrol)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
sof_ipc3_volume_get(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_volume_put(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_switch_get(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_switch_put(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_enum_get(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_enum_put(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_bytes_get(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_bytes_put(struct snd_sof_control * scontrol,struct snd_ctl_elem_value * ucontrol)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
sof_ipc3_bytes_ext_get(struct snd_sof_control * scontrol,const unsigned int __user * binary_data,unsigned int size)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
sof_ipc3_bytes_ext_put(struct snd_sof_control * scontrol,const unsigned int __user * binary_data,unsigned int size)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
sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control * scontrol,const unsigned int __user * binary_data,unsigned int size)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
snd_sof_update_control(struct snd_sof_control * scontrol,struct sof_ipc_ctrl_data * cdata)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
sof_ipc3_control_update(struct snd_sof_dev * sdev,void * ipc_control_message)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
sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget)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
sof_ipc3_set_up_volume_table(struct snd_sof_control * scontrol,int tlv[SOF_TLV_ITEMS],int size)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