~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/sof/ipc4-control.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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) 2022 Intel Corporation
  7 //
  8 //
  9 
 10 #include "sof-priv.h"
 11 #include "sof-audio.h"
 12 #include "ipc4-priv.h"
 13 #include "ipc4-topology.h"
 14 
 15 static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
 16                                           bool set, bool lock)
 17 {
 18         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
 19         struct snd_soc_component *scomp = scontrol->scomp;
 20         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 21         const struct sof_ipc_ops *iops = sdev->ipc->ops;
 22         struct sof_ipc4_msg *msg = &cdata->msg;
 23         struct snd_sof_widget *swidget;
 24         bool widget_found = false;
 25         int ret = 0;
 26 
 27         /* find widget associated with the control */
 28         list_for_each_entry(swidget, &sdev->widget_list, list) {
 29                 if (swidget->comp_id == scontrol->comp_id) {
 30                         widget_found = true;
 31                         break;
 32                 }
 33         }
 34 
 35         if (!widget_found) {
 36                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
 37                 return -ENOENT;
 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         msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
 54         msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
 55 
 56         ret = iops->set_get_data(sdev, msg, msg->data_size, set);
 57         if (!set)
 58                 goto unlock;
 59 
 60         /* It is a set-data operation, and we have a valid backup that we can restore */
 61         if (ret < 0) {
 62                 if (!scontrol->old_ipc_control_data)
 63                         goto unlock;
 64                 /*
 65                  * Current ipc_control_data is not valid, we use the last known good
 66                  * configuration
 67                  */
 68                 memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
 69                        scontrol->max_size);
 70                 kfree(scontrol->old_ipc_control_data);
 71                 scontrol->old_ipc_control_data = NULL;
 72                 /* Send the last known good configuration to firmware */
 73                 ret = iops->set_get_data(sdev, msg, msg->data_size, set);
 74                 if (ret < 0)
 75                         goto unlock;
 76         }
 77 
 78 unlock:
 79         if (lock)
 80                 mutex_unlock(&swidget->setup_mutex);
 81 
 82         return ret;
 83 }
 84 
 85 static int
 86 sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
 87                          struct snd_sof_control *scontrol, bool lock)
 88 {
 89         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
 90         struct sof_ipc4_gain *gain = swidget->private;
 91         struct sof_ipc4_msg *msg = &cdata->msg;
 92         struct sof_ipc4_gain_params params;
 93         bool all_channels_equal = true;
 94         u32 value;
 95         int ret, i;
 96 
 97         /* check if all channel values are equal */
 98         value = cdata->chanv[0].value;
 99         for (i = 1; i < scontrol->num_channels; i++) {
100                 if (cdata->chanv[i].value != value) {
101                         all_channels_equal = false;
102                         break;
103                 }
104         }
105 
106         /*
107          * notify DSP with a single IPC message if all channel values are equal. Otherwise send
108          * a separate IPC for each channel.
109          */
110         for (i = 0; i < scontrol->num_channels; i++) {
111                 if (all_channels_equal) {
112                         params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
113                         params.init_val = cdata->chanv[0].value;
114                 } else {
115                         params.channels = cdata->chanv[i].channel;
116                         params.init_val = cdata->chanv[i].value;
117                 }
118 
119                 /* set curve type and duration from topology */
120                 params.curve_duration_l = gain->data.params.curve_duration_l;
121                 params.curve_duration_h = gain->data.params.curve_duration_h;
122                 params.curve_type = gain->data.params.curve_type;
123 
124                 msg->data_ptr = &params;
125                 msg->data_size = sizeof(params);
126 
127                 ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
128                 msg->data_ptr = NULL;
129                 msg->data_size = 0;
130                 if (ret < 0) {
131                         dev_err(sdev->dev, "Failed to set volume update for %s\n",
132                                 scontrol->name);
133                         return ret;
134                 }
135 
136                 if (all_channels_equal)
137                         break;
138         }
139 
140         return 0;
141 }
142 
143 static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
144                                 struct snd_ctl_elem_value *ucontrol)
145 {
146         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
147         struct snd_soc_component *scomp = scontrol->scomp;
148         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
149         unsigned int channels = scontrol->num_channels;
150         struct snd_sof_widget *swidget;
151         bool widget_found = false;
152         bool change = false;
153         unsigned int i;
154         int ret;
155 
156         /* update each channel */
157         for (i = 0; i < channels; i++) {
158                 u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
159                                          scontrol->volume_table, scontrol->max + 1);
160 
161                 change = change || (value != cdata->chanv[i].value);
162                 cdata->chanv[i].channel = i;
163                 cdata->chanv[i].value = value;
164         }
165 
166         if (!pm_runtime_active(scomp->dev))
167                 return change;
168 
169         /* find widget associated with the control */
170         list_for_each_entry(swidget, &sdev->widget_list, list) {
171                 if (swidget->comp_id == scontrol->comp_id) {
172                         widget_found = true;
173                         break;
174                 }
175         }
176 
177         if (!widget_found) {
178                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
179                 return false;
180         }
181 
182         ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol, true);
183         if (ret < 0)
184                 return false;
185 
186         return change;
187 }
188 
189 static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
190                                struct snd_ctl_elem_value *ucontrol)
191 {
192         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
193         unsigned int channels = scontrol->num_channels;
194         unsigned int i;
195 
196         for (i = 0; i < channels; i++)
197                 ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
198                                                                 scontrol->volume_table,
199                                                                 scontrol->max + 1);
200 
201         return 0;
202 }
203 
204 static int
205 sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev,
206                                   struct snd_sof_widget *swidget,
207                                   struct snd_sof_control *scontrol, bool lock)
208 {
209         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
210         struct sof_ipc4_control_msg_payload *data;
211         struct sof_ipc4_msg *msg = &cdata->msg;
212         size_t data_size;
213         unsigned int i;
214         int ret;
215 
216         data_size = struct_size(data, chanv, scontrol->num_channels);
217         data = kzalloc(data_size, GFP_KERNEL);
218         if (!data)
219                 return -ENOMEM;
220 
221         data->id = cdata->index;
222         data->num_elems = scontrol->num_channels;
223         for (i = 0; i < scontrol->num_channels; i++) {
224                 data->chanv[i].channel = cdata->chanv[i].channel;
225                 data->chanv[i].value = cdata->chanv[i].value;
226         }
227 
228         msg->data_ptr = data;
229         msg->data_size = data_size;
230 
231         ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
232         msg->data_ptr = NULL;
233         msg->data_size = 0;
234         if (ret < 0)
235                 dev_err(sdev->dev, "Failed to set control update for %s\n",
236                         scontrol->name);
237 
238         kfree(data);
239 
240         return ret;
241 }
242 
243 static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol)
244 {
245         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
246         struct snd_soc_component *scomp = scontrol->scomp;
247         struct sof_ipc4_control_msg_payload *data;
248         struct sof_ipc4_msg *msg = &cdata->msg;
249         size_t data_size;
250         unsigned int i;
251         int ret;
252 
253         if (!scontrol->comp_data_dirty)
254                 return;
255 
256         if (!pm_runtime_active(scomp->dev))
257                 return;
258 
259         data_size = struct_size(data, chanv, scontrol->num_channels);
260         data = kmalloc(data_size, GFP_KERNEL);
261         if (!data)
262                 return;
263 
264         data->id = cdata->index;
265         data->num_elems = scontrol->num_channels;
266         msg->data_ptr = data;
267         msg->data_size = data_size;
268 
269         scontrol->comp_data_dirty = false;
270         ret = sof_ipc4_set_get_kcontrol_data(scontrol, false, true);
271         msg->data_ptr = NULL;
272         msg->data_size = 0;
273         if (!ret) {
274                 for (i = 0; i < scontrol->num_channels; i++) {
275                         cdata->chanv[i].channel = data->chanv[i].channel;
276                         cdata->chanv[i].value = data->chanv[i].value;
277                 }
278         } else {
279                 dev_err(scomp->dev, "Failed to read control data for %s\n",
280                         scontrol->name);
281                 scontrol->comp_data_dirty = true;
282         }
283 
284         kfree(data);
285 }
286 
287 static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol,
288                                 struct snd_ctl_elem_value *ucontrol)
289 {
290         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
291         struct snd_soc_component *scomp = scontrol->scomp;
292         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
293         struct snd_sof_widget *swidget;
294         bool widget_found = false;
295         bool change = false;
296         unsigned int i;
297         u32 value;
298         int ret;
299 
300         /* update each channel */
301         for (i = 0; i < scontrol->num_channels; i++) {
302                 value = ucontrol->value.integer.value[i];
303                 change = change || (value != cdata->chanv[i].value);
304                 cdata->chanv[i].channel = i;
305                 cdata->chanv[i].value = value;
306         }
307 
308         if (!pm_runtime_active(scomp->dev))
309                 return change;
310 
311         /* find widget associated with the control */
312         list_for_each_entry(swidget, &sdev->widget_list, list) {
313                 if (swidget->comp_id == scontrol->comp_id) {
314                         widget_found = true;
315                         break;
316                 }
317         }
318 
319         if (!widget_found) {
320                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
321                 return false;
322         }
323 
324         ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true);
325         if (ret < 0)
326                 return false;
327 
328         return change;
329 }
330 
331 static int sof_ipc4_switch_get(struct snd_sof_control *scontrol,
332                                struct snd_ctl_elem_value *ucontrol)
333 {
334         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
335         unsigned int i;
336 
337         sof_ipc4_refresh_generic_control(scontrol);
338 
339         /* read back each channel */
340         for (i = 0; i < scontrol->num_channels; i++)
341                 ucontrol->value.integer.value[i] = cdata->chanv[i].value;
342 
343         return 0;
344 }
345 
346 static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol,
347                               struct snd_ctl_elem_value *ucontrol)
348 {
349         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
350         struct snd_soc_component *scomp = scontrol->scomp;
351         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
352         struct snd_sof_widget *swidget;
353         bool widget_found = false;
354         bool change = false;
355         unsigned int i;
356         u32 value;
357         int ret;
358 
359         /* update each channel */
360         for (i = 0; i < scontrol->num_channels; i++) {
361                 value = ucontrol->value.enumerated.item[i];
362                 change = change || (value != cdata->chanv[i].value);
363                 cdata->chanv[i].channel = i;
364                 cdata->chanv[i].value = value;
365         }
366 
367         if (!pm_runtime_active(scomp->dev))
368                 return change;
369 
370         /* find widget associated with the control */
371         list_for_each_entry(swidget, &sdev->widget_list, list) {
372                 if (swidget->comp_id == scontrol->comp_id) {
373                         widget_found = true;
374                         break;
375                 }
376         }
377 
378         if (!widget_found) {
379                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
380                 return false;
381         }
382 
383         ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true);
384         if (ret < 0)
385                 return false;
386 
387         return change;
388 }
389 
390 static int sof_ipc4_enum_get(struct snd_sof_control *scontrol,
391                              struct snd_ctl_elem_value *ucontrol)
392 {
393         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
394         unsigned int i;
395 
396         sof_ipc4_refresh_generic_control(scontrol);
397 
398         /* read back each channel */
399         for (i = 0; i < scontrol->num_channels; i++)
400                 ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
401 
402         return 0;
403 }
404 
405 static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
406                                        struct snd_sof_control *scontrol,
407                                        bool set, bool lock)
408 {
409         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
410         struct sof_abi_hdr *data = cdata->data;
411         struct sof_ipc4_msg *msg = &cdata->msg;
412         int ret = 0;
413 
414         /* Send the new data to the firmware only if it is powered up */
415         if (set && !pm_runtime_active(sdev->dev))
416                 return 0;
417 
418         msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
419 
420         msg->data_ptr = data->data;
421         msg->data_size = data->size;
422 
423         ret = sof_ipc4_set_get_kcontrol_data(scontrol, set, lock);
424         if (ret < 0)
425                 dev_err(sdev->dev, "Failed to %s for %s\n",
426                         set ? "set bytes update" : "get bytes",
427                         scontrol->name);
428 
429         msg->data_ptr = NULL;
430         msg->data_size = 0;
431 
432         return ret;
433 }
434 
435 static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol,
436                               struct snd_ctl_elem_value *ucontrol)
437 {
438         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
439         struct snd_soc_component *scomp = scontrol->scomp;
440         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
441         struct sof_abi_hdr *data = cdata->data;
442         size_t size;
443 
444         if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
445                 dev_err_ratelimited(scomp->dev,
446                                     "data max %zu exceeds ucontrol data array size\n",
447                                     scontrol->max_size);
448                 return -EINVAL;
449         }
450 
451         /* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
452         if (data->size > scontrol->max_size - sizeof(*data)) {
453                 dev_err_ratelimited(scomp->dev,
454                                     "data size too big %u bytes max is %zu\n",
455                                     data->size, scontrol->max_size - sizeof(*data));
456                 return -EINVAL;
457         }
458 
459         size = data->size + sizeof(*data);
460 
461         /* copy from kcontrol */
462         memcpy(data, ucontrol->value.bytes.data, size);
463 
464         sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
465 
466         return 0;
467 }
468 
469 static int sof_ipc4_bytes_get(struct snd_sof_control *scontrol,
470                               struct snd_ctl_elem_value *ucontrol)
471 {
472         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
473         struct snd_soc_component *scomp = scontrol->scomp;
474         struct sof_abi_hdr *data = cdata->data;
475         size_t size;
476 
477         if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
478                 dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
479                                     scontrol->max_size);
480                 return -EINVAL;
481         }
482 
483         if (data->size > scontrol->max_size - sizeof(*data)) {
484                 dev_err_ratelimited(scomp->dev,
485                                     "%u bytes of control data is invalid, max is %zu\n",
486                                     data->size, scontrol->max_size - sizeof(*data));
487                 return -EINVAL;
488         }
489 
490         size = data->size + sizeof(*data);
491 
492         /* copy back to kcontrol */
493         memcpy(ucontrol->value.bytes.data, data, size);
494 
495         return 0;
496 }
497 
498 static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
499                                   const unsigned int __user *binary_data,
500                                   unsigned int size)
501 {
502         struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
503         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
504         struct snd_soc_component *scomp = scontrol->scomp;
505         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
506         struct sof_abi_hdr *data = cdata->data;
507         struct sof_abi_hdr abi_hdr;
508         struct snd_ctl_tlv header;
509 
510         /*
511          * The beginning of bytes data contains a header from where
512          * the length (as bytes) is needed to know the correct copy
513          * length of data from tlvd->tlv.
514          */
515         if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
516                 return -EFAULT;
517 
518         /* make sure TLV info is consistent */
519         if (header.length + sizeof(struct snd_ctl_tlv) > size) {
520                 dev_err_ratelimited(scomp->dev,
521                                     "Inconsistent TLV, data %d + header %zu > %d\n",
522                                     header.length, sizeof(struct snd_ctl_tlv), size);
523                 return -EINVAL;
524         }
525 
526         /* be->max is coming from topology */
527         if (header.length > scontrol->max_size) {
528                 dev_err_ratelimited(scomp->dev,
529                                     "Bytes data size %d exceeds max %zu\n",
530                                     header.length, scontrol->max_size);
531                 return -EINVAL;
532         }
533 
534         /* Verify the ABI header first */
535         if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr)))
536                 return -EFAULT;
537 
538         if (abi_hdr.magic != SOF_IPC4_ABI_MAGIC) {
539                 dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n",
540                                     abi_hdr.magic);
541                 return -EINVAL;
542         }
543 
544         if (abi_hdr.size > scontrol->max_size - sizeof(abi_hdr)) {
545                 dev_err_ratelimited(scomp->dev,
546                                     "%u bytes of control data is invalid, max is %zu\n",
547                                     abi_hdr.size, scontrol->max_size - sizeof(abi_hdr));
548                 return -EINVAL;
549         }
550 
551         if (!scontrol->old_ipc_control_data) {
552                 /* Create a backup of the current, valid bytes control */
553                 scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data,
554                                                          scontrol->max_size, GFP_KERNEL);
555                 if (!scontrol->old_ipc_control_data)
556                         return -ENOMEM;
557         }
558 
559         /* Copy the whole binary data which includes the ABI header and the payload */
560         if (copy_from_user(data, tlvd->tlv, header.length)) {
561                 memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
562                        scontrol->max_size);
563                 kfree(scontrol->old_ipc_control_data);
564                 scontrol->old_ipc_control_data = NULL;
565                 return -EFAULT;
566         }
567 
568         return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
569 }
570 
571 static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
572                                    const unsigned int __user *binary_data,
573                                    unsigned int size, bool from_dsp)
574 {
575         struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
576         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
577         struct snd_soc_component *scomp = scontrol->scomp;
578         struct sof_abi_hdr *data = cdata->data;
579         struct snd_ctl_tlv header;
580         size_t data_size;
581 
582         /*
583          * Decrement the limit by ext bytes header size to ensure the user space
584          * buffer is not exceeded.
585          */
586         if (size < sizeof(struct snd_ctl_tlv))
587                 return -ENOSPC;
588 
589         size -= sizeof(struct snd_ctl_tlv);
590 
591         /* get all the component data from DSP */
592         if (from_dsp) {
593                 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
594                 int ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, false, true);
595 
596                 if (ret < 0)
597                         return ret;
598 
599                 /* Set the ABI magic (if the control is not initialized) */
600                 data->magic = SOF_IPC4_ABI_MAGIC;
601         }
602 
603         if (data->size > scontrol->max_size - sizeof(*data)) {
604                 dev_err_ratelimited(scomp->dev,
605                                     "%u bytes of control data is invalid, max is %zu\n",
606                                     data->size, scontrol->max_size - sizeof(*data));
607                 return -EINVAL;
608         }
609 
610         data_size = data->size + sizeof(struct sof_abi_hdr);
611 
612         /* make sure we don't exceed size provided by user space for data */
613         if (data_size > size)
614                 return -ENOSPC;
615 
616         header.numid = scontrol->comp_id;
617         header.length = data_size;
618 
619         if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
620                 return -EFAULT;
621 
622         if (copy_to_user(tlvd->tlv, data, data_size))
623                 return -EFAULT;
624 
625         return 0;
626 }
627 
628 static int sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
629                                   const unsigned int __user *binary_data,
630                                   unsigned int size)
631 {
632         return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, false);
633 }
634 
635 static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
636                                            const unsigned int __user *binary_data,
637                                            unsigned int size)
638 {
639         return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true);
640 }
641 
642 static int
643 sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
644                      struct snd_sof_control *scontrol)
645 {
646         if (scontrol->max == 1)
647                 return sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, false);
648 
649         return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false);
650 }
651 
652 #define PARAM_ID_FROM_EXTENSION(_ext)   (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK)  \
653                                          >> SOF_IPC4_MOD_EXT_MSG_PARAM_ID_SHIFT)
654 
655 static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
656 {
657         struct sof_ipc4_msg *ipc4_msg = ipc_message;
658         struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr;
659         struct sof_ipc4_control_msg_payload *msg_data;
660         struct sof_ipc4_control_data *cdata;
661         struct snd_soc_dapm_widget *widget;
662         struct snd_sof_control *scontrol;
663         struct snd_sof_widget *swidget;
664         struct snd_kcontrol *kc = NULL;
665         bool scontrol_found = false;
666         u32 event_param_id;
667         int i, type;
668 
669         if (ndata->event_data_size < sizeof(*msg_data)) {
670                 dev_err(sdev->dev,
671                         "%s: Invalid event data size for module %u.%u: %u\n",
672                         __func__, ndata->module_id, ndata->instance_id,
673                         ndata->event_data_size);
674                 return;
675         }
676 
677         event_param_id = ndata->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK;
678         switch (event_param_id) {
679         case SOF_IPC4_SWITCH_CONTROL_PARAM_ID:
680                 type = SND_SOC_TPLG_TYPE_MIXER;
681                 break;
682         case SOF_IPC4_ENUM_CONTROL_PARAM_ID:
683                 type = SND_SOC_TPLG_TYPE_ENUM;
684                 break;
685         default:
686                 dev_err(sdev->dev,
687                         "%s: Invalid control type for module %u.%u: %u\n",
688                         __func__, ndata->module_id, ndata->instance_id,
689                         event_param_id);
690                 return;
691         }
692 
693         /* Find the swidget based on ndata->module_id and ndata->instance_id */
694         swidget = sof_ipc4_find_swidget_by_ids(sdev, ndata->module_id,
695                                                ndata->instance_id);
696         if (!swidget) {
697                 dev_err(sdev->dev, "%s: Failed to find widget for module %u.%u\n",
698                         __func__, ndata->module_id, ndata->instance_id);
699                 return;
700         }
701 
702         /* Find the scontrol which is the source of the notification */
703         msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data;
704         list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
705                 if (scontrol->comp_id == swidget->comp_id) {
706                         u32 local_param_id;
707 
708                         cdata = scontrol->ipc_control_data;
709                         /*
710                          * The scontrol's param_id is stored in the IPC message
711                          * template's extension
712                          */
713                         local_param_id = PARAM_ID_FROM_EXTENSION(cdata->msg.extension);
714                         if (local_param_id == event_param_id &&
715                             msg_data->id == cdata->index) {
716                                 scontrol_found = true;
717                                 break;
718                         }
719                 }
720         }
721 
722         if (!scontrol_found) {
723                 dev_err(sdev->dev,
724                         "%s: Failed to find control on widget %s: %u:%u\n",
725                         __func__, swidget->widget->name, ndata->event_id & 0xffff,
726                         msg_data->id);
727                 return;
728         }
729 
730         if (msg_data->num_elems) {
731                 /*
732                  * The message includes the updated value/data, update the
733                  * control's local cache using the received notification
734                  */
735                 for (i = 0; i < msg_data->num_elems; i++) {
736                         u32 channel = msg_data->chanv[i].channel;
737 
738                         if (channel >= scontrol->num_channels) {
739                                 dev_warn(sdev->dev,
740                                          "Invalid channel index for %s: %u\n",
741                                          scontrol->name, i);
742 
743                                 /*
744                                  * Mark the scontrol as dirty to force a refresh
745                                  * on next read
746                                  */
747                                 scontrol->comp_data_dirty = true;
748                                 break;
749                         }
750 
751                         cdata->chanv[channel].value = msg_data->chanv[i].value;
752                 }
753         } else {
754                 /*
755                  * Mark the scontrol as dirty because the value/data is changed
756                  * in firmware, forcing a refresh on next read access
757                  */
758                 scontrol->comp_data_dirty = true;
759         }
760 
761         /*
762          * Look up the ALSA kcontrol of the scontrol to be able to send a
763          * notification to user space
764          */
765         widget = swidget->widget;
766         for (i = 0; i < widget->num_kcontrols; i++) {
767                 /* skip non matching types or non matching indexes within type */
768                 if (widget->dobj.widget.kcontrol_type[i] == type &&
769                     widget->kcontrol_news[i].index == cdata->index) {
770                         kc = widget->kcontrols[i];
771                         break;
772                 }
773         }
774 
775         if (!kc)
776                 return;
777 
778         snd_ctl_notify_one(swidget->scomp->card->snd_card,
779                            SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
780 }
781 
782 /* set up all controls for the widget */
783 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
784 {
785         struct snd_sof_control *scontrol;
786         int ret = 0;
787 
788         list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
789                 if (scontrol->comp_id == swidget->comp_id) {
790                         switch (scontrol->info_type) {
791                         case SND_SOC_TPLG_CTL_VOLSW:
792                         case SND_SOC_TPLG_CTL_VOLSW_SX:
793                         case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
794                                 ret = sof_ipc4_volsw_setup(sdev, swidget, scontrol);
795                                 break;
796                         case SND_SOC_TPLG_CTL_BYTES:
797                                 ret = sof_ipc4_set_get_bytes_data(sdev, scontrol,
798                                                                   true, false);
799                                 break;
800                         case SND_SOC_TPLG_CTL_ENUM:
801                         case SND_SOC_TPLG_CTL_ENUM_VALUE:
802                                 ret = sof_ipc4_set_generic_control_data(sdev, swidget,
803                                                                         scontrol, false);
804                                 break;
805                         default:
806                                 break;
807                         }
808 
809                         if (ret < 0) {
810                                 dev_err(sdev->dev,
811                                         "kcontrol %d set up failed for widget %s\n",
812                                         scontrol->comp_id, swidget->widget->name);
813                                 return ret;
814                         }
815                 }
816         }
817 
818         return 0;
819 }
820 
821 static int
822 sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
823 {
824         int i;
825 
826         /* init the volume table */
827         scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
828         if (!scontrol->volume_table)
829                 return -ENOMEM;
830 
831         /* populate the volume table */
832         for (i = 0; i < size ; i++) {
833                 u32 val = vol_compute_gain(i, tlv);
834                 u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */
835 
836                 scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
837                                                 SOF_IPC4_VOL_ZERO_DB : q31val;
838         }
839 
840         return 0;
841 }
842 
843 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
844         .volume_put = sof_ipc4_volume_put,
845         .volume_get = sof_ipc4_volume_get,
846         .switch_put = sof_ipc4_switch_put,
847         .switch_get = sof_ipc4_switch_get,
848         .enum_put = sof_ipc4_enum_put,
849         .enum_get = sof_ipc4_enum_get,
850         .bytes_put = sof_ipc4_bytes_put,
851         .bytes_get = sof_ipc4_bytes_get,
852         .bytes_ext_put = sof_ipc4_bytes_ext_put,
853         .bytes_ext_get = sof_ipc4_bytes_ext_get,
854         .bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get,
855         .update = sof_ipc4_control_update,
856         .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
857         .set_up_volume_table = sof_ipc4_set_up_volume_table,
858 };
859 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php