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