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

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

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ 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.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /sound/soc/sof/ipc4-control.c (Version linux-6.12-rc7) and /sound/soc/sof/ipc4-control.c (Version linux-6.0.19)


  1 // SPDX-License-Identifier: (GPL-2.0-only OR B      1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
  2 //                                                  2 //
  3 // This file is provided under a dual BSD/GPLv      3 // This file is provided under a dual BSD/GPLv2 license.  When using or
  4 // redistributing this file, you may do so und      4 // redistributing this file, you may do so under either license.
  5 //                                                  5 //
  6 // Copyright(c) 2022 Intel Corporation         !!   6 // Copyright(c) 2022 Intel Corporation. All rights reserved.
  7 //                                                  7 //
  8 //                                                  8 //
  9                                                     9 
 10 #include "sof-priv.h"                              10 #include "sof-priv.h"
 11 #include "sof-audio.h"                             11 #include "sof-audio.h"
 12 #include "ipc4-priv.h"                             12 #include "ipc4-priv.h"
 13 #include "ipc4-topology.h"                         13 #include "ipc4-topology.h"
 14                                                    14 
 15 static int sof_ipc4_set_get_kcontrol_data(stru !!  15 static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
 16                                           bool << 
 17 {                                                  16 {
 18         struct sof_ipc4_control_data *cdata =      17         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
 19         struct snd_soc_component *scomp = scon     18         struct snd_soc_component *scomp = scontrol->scomp;
 20         struct snd_sof_dev *sdev = snd_soc_com     19         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
 21         const struct sof_ipc_ops *iops = sdev-     20         const struct sof_ipc_ops *iops = sdev->ipc->ops;
 22         struct sof_ipc4_msg *msg = &cdata->msg     21         struct sof_ipc4_msg *msg = &cdata->msg;
 23         struct snd_sof_widget *swidget;            22         struct snd_sof_widget *swidget;
 24         bool widget_found = false;                 23         bool widget_found = false;
 25         int ret = 0;                           << 
 26                                                    24 
 27         /* find widget associated with the con     25         /* find widget associated with the control */
 28         list_for_each_entry(swidget, &sdev->wi     26         list_for_each_entry(swidget, &sdev->widget_list, list) {
 29                 if (swidget->comp_id == scontr     27                 if (swidget->comp_id == scontrol->comp_id) {
 30                         widget_found = true;       28                         widget_found = true;
 31                         break;                     29                         break;
 32                 }                                  30                 }
 33         }                                          31         }
 34                                                    32 
 35         if (!widget_found) {                       33         if (!widget_found) {
 36                 dev_err(scomp->dev, "Failed to     34                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
 37                 return -ENOENT;                    35                 return -ENOENT;
 38         }                                          36         }
 39                                                    37 
 40         if (lock)                              << 
 41                 mutex_lock(&swidget->setup_mut << 
 42         else                                   << 
 43                 lockdep_assert_held(&swidget-> << 
 44                                                << 
 45         /*                                         38         /*
 46          * Volatile controls should always be  !!  39          * Volatile controls should always be part of static pipelines and the widget use_count
 47          * widget use_count would always be >  !!  40          * would always be > 0 in this case. For the others, just return the cached value if the
 48          * just return the cached value if the !!  41          * widget is not set up.
 49          */                                        42          */
 50         if (!swidget->use_count)                   43         if (!swidget->use_count)
 51                 goto unlock;                   !!  44                 return 0;
 52                                                    45 
 53         msg->primary &= ~SOF_IPC4_MOD_INSTANCE     46         msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
 54         msg->primary |= SOF_IPC4_MOD_INSTANCE(     47         msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
 55                                                    48 
 56         ret = iops->set_get_data(sdev, msg, ms !!  49         return 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  << 
 61         if (ret < 0) {                         << 
 62                 if (!scontrol->old_ipc_control << 
 63                         goto unlock;           << 
 64                 /*                             << 
 65                  * Current ipc_control_data is << 
 66                  * configuration               << 
 67                  */                            << 
 68                 memcpy(scontrol->ipc_control_d << 
 69                        scontrol->max_size);    << 
 70                 kfree(scontrol->old_ipc_contro << 
 71                 scontrol->old_ipc_control_data << 
 72                 /* Send the last known good co << 
 73                 ret = iops->set_get_data(sdev, << 
 74                 if (ret < 0)                   << 
 75                         goto unlock;           << 
 76         }                                      << 
 77                                                << 
 78 unlock:                                        << 
 79         if (lock)                              << 
 80                 mutex_unlock(&swidget->setup_m << 
 81                                                << 
 82         return ret;                            << 
 83 }                                                  50 }
 84                                                    51 
 85 static int                                         52 static int
 86 sof_ipc4_set_volume_data(struct snd_sof_dev *s     53 sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
 87                          struct snd_sof_contro !!  54                          struct snd_sof_control *scontrol)
 88 {                                                  55 {
 89         struct sof_ipc4_control_data *cdata =      56         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
 90         struct sof_ipc4_gain *gain = swidget->     57         struct sof_ipc4_gain *gain = swidget->private;
 91         struct sof_ipc4_msg *msg = &cdata->msg     58         struct sof_ipc4_msg *msg = &cdata->msg;
 92         struct sof_ipc4_gain_params params;    !!  59         struct sof_ipc4_gain_data data;
 93         bool all_channels_equal = true;            60         bool all_channels_equal = true;
 94         u32 value;                                 61         u32 value;
 95         int ret, i;                                62         int ret, i;
 96                                                    63 
 97         /* check if all channel values are equ     64         /* check if all channel values are equal */
 98         value = cdata->chanv[0].value;             65         value = cdata->chanv[0].value;
 99         for (i = 1; i < scontrol->num_channels     66         for (i = 1; i < scontrol->num_channels; i++) {
100                 if (cdata->chanv[i].value != v     67                 if (cdata->chanv[i].value != value) {
101                         all_channels_equal = f     68                         all_channels_equal = false;
102                         break;                     69                         break;
103                 }                                  70                 }
104         }                                          71         }
105                                                    72 
106         /*                                         73         /*
107          * notify DSP with a single IPC messag     74          * notify DSP with a single IPC message if all channel values are equal. Otherwise send
108          * a separate IPC for each channel.        75          * a separate IPC for each channel.
109          */                                        76          */
110         for (i = 0; i < scontrol->num_channels     77         for (i = 0; i < scontrol->num_channels; i++) {
111                 if (all_channels_equal) {          78                 if (all_channels_equal) {
112                         params.channels = SOF_ !!  79                         data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
113                         params.init_val = cdat !!  80                         data.init_val = cdata->chanv[0].value;
114                 } else {                           81                 } else {
115                         params.channels = cdat !!  82                         data.channels = cdata->chanv[i].channel;
116                         params.init_val = cdat !!  83                         data.init_val = cdata->chanv[i].value;
117                 }                                  84                 }
118                                                    85 
119                 /* set curve type and duration     86                 /* set curve type and duration from topology */
120                 params.curve_duration_l = gain !!  87                 data.curve_duration = gain->data.curve_duration;
121                 params.curve_duration_h = gain !!  88                 data.curve_type = gain->data.curve_type;
122                 params.curve_type = gain->data << 
123                                                    89 
124                 msg->data_ptr = &params;       !!  90                 msg->data_ptr = &data;
125                 msg->data_size = sizeof(params !!  91                 msg->data_size = sizeof(data);
126                                                    92 
127                 ret = sof_ipc4_set_get_kcontro !!  93                 ret = sof_ipc4_set_get_kcontrol_data(scontrol, true);
128                 msg->data_ptr = NULL;              94                 msg->data_ptr = NULL;
129                 msg->data_size = 0;                95                 msg->data_size = 0;
130                 if (ret < 0) {                     96                 if (ret < 0) {
131                         dev_err(sdev->dev, "Fa     97                         dev_err(sdev->dev, "Failed to set volume update for %s\n",
132                                 scontrol->name     98                                 scontrol->name);
133                         return ret;                99                         return ret;
134                 }                                 100                 }
135                                                   101 
136                 if (all_channels_equal)           102                 if (all_channels_equal)
137                         break;                    103                         break;
138         }                                         104         }
139                                                   105 
140         return 0;                                 106         return 0;
141 }                                                 107 }
142                                                   108 
143 static bool sof_ipc4_volume_put(struct snd_sof    109 static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
144                                 struct snd_ctl    110                                 struct snd_ctl_elem_value *ucontrol)
145 {                                                 111 {
146         struct sof_ipc4_control_data *cdata =     112         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
147         struct snd_soc_component *scomp = scon    113         struct snd_soc_component *scomp = scontrol->scomp;
148         struct snd_sof_dev *sdev = snd_soc_com    114         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
149         unsigned int channels = scontrol->num_    115         unsigned int channels = scontrol->num_channels;
150         struct snd_sof_widget *swidget;           116         struct snd_sof_widget *swidget;
151         bool widget_found = false;                117         bool widget_found = false;
152         bool change = false;                      118         bool change = false;
153         unsigned int i;                           119         unsigned int i;
154         int ret;                                  120         int ret;
155                                                   121 
156         /* update each channel */                 122         /* update each channel */
157         for (i = 0; i < channels; i++) {          123         for (i = 0; i < channels; i++) {
158                 u32 value = mixer_to_ipc(ucont    124                 u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
159                                          scont    125                                          scontrol->volume_table, scontrol->max + 1);
160                                                   126 
161                 change = change || (value != c    127                 change = change || (value != cdata->chanv[i].value);
162                 cdata->chanv[i].channel = i;      128                 cdata->chanv[i].channel = i;
163                 cdata->chanv[i].value = value;    129                 cdata->chanv[i].value = value;
164         }                                         130         }
165                                                   131 
166         if (!pm_runtime_active(scomp->dev))       132         if (!pm_runtime_active(scomp->dev))
167                 return change;                    133                 return change;
168                                                   134 
169         /* find widget associated with the con    135         /* find widget associated with the control */
170         list_for_each_entry(swidget, &sdev->wi    136         list_for_each_entry(swidget, &sdev->widget_list, list) {
171                 if (swidget->comp_id == scontr    137                 if (swidget->comp_id == scontrol->comp_id) {
172                         widget_found = true;      138                         widget_found = true;
173                         break;                    139                         break;
174                 }                                 140                 }
175         }                                         141         }
176                                                   142 
177         if (!widget_found) {                      143         if (!widget_found) {
178                 dev_err(scomp->dev, "Failed to    144                 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
179                 return false;                     145                 return false;
180         }                                         146         }
181                                                   147 
182         ret = sof_ipc4_set_volume_data(sdev, s !! 148         ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
183         if (ret < 0)                              149         if (ret < 0)
184                 return false;                     150                 return false;
185                                                   151 
186         return change;                            152         return change;
187 }                                                 153 }
188                                                   154 
189 static int sof_ipc4_volume_get(struct snd_sof_    155 static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
190                                struct snd_ctl_    156                                struct snd_ctl_elem_value *ucontrol)
191 {                                                 157 {
192         struct sof_ipc4_control_data *cdata =     158         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
193         unsigned int channels = scontrol->num_    159         unsigned int channels = scontrol->num_channels;
194         unsigned int i;                           160         unsigned int i;
195                                                   161 
196         for (i = 0; i < channels; i++)            162         for (i = 0; i < channels; i++)
197                 ucontrol->value.integer.value[    163                 ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
198                                                   164                                                                 scontrol->volume_table,
199                                                   165                                                                 scontrol->max + 1);
200                                                   166 
201         return 0;                                 167         return 0;
202 }                                                 168 }
203                                                   169 
204 static int                                     << 
205 sof_ipc4_set_generic_control_data(struct snd_s << 
206                                   struct snd_s << 
207                                   struct snd_s << 
208 {                                              << 
209         struct sof_ipc4_control_data *cdata =  << 
210         struct sof_ipc4_control_msg_payload *d << 
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, s << 
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_channe << 
223         for (i = 0; i < scontrol->num_channels << 
224                 data->chanv[i].channel = cdata << 
225                 data->chanv[i].value = cdata-> << 
226         }                                      << 
227                                                << 
228         msg->data_ptr = data;                  << 
229         msg->data_size = data_size;            << 
230                                                << 
231         ret = sof_ipc4_set_get_kcontrol_data(s << 
232         msg->data_ptr = NULL;                  << 
233         msg->data_size = 0;                    << 
234         if (ret < 0)                           << 
235                 dev_err(sdev->dev, "Failed to  << 
236                         scontrol->name);       << 
237                                                << 
238         kfree(data);                           << 
239                                                << 
240         return ret;                            << 
241 }                                              << 
242                                                << 
243 static void sof_ipc4_refresh_generic_control(s << 
244 {                                              << 
245         struct sof_ipc4_control_data *cdata =  << 
246         struct snd_soc_component *scomp = scon << 
247         struct sof_ipc4_control_msg_payload *d << 
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, s << 
260         data = kmalloc(data_size, GFP_KERNEL); << 
261         if (!data)                             << 
262                 return;                        << 
263                                                << 
264         data->id = cdata->index;               << 
265         data->num_elems = scontrol->num_channe << 
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(s << 
271         msg->data_ptr = NULL;                  << 
272         msg->data_size = 0;                    << 
273         if (!ret) {                            << 
274                 for (i = 0; i < scontrol->num_ << 
275                         cdata->chanv[i].channe << 
276                         cdata->chanv[i].value  << 
277                 }                              << 
278         } else {                               << 
279                 dev_err(scomp->dev, "Failed to << 
280                         scontrol->name);       << 
281                 scontrol->comp_data_dirty = tr << 
282         }                                      << 
283                                                << 
284         kfree(data);                           << 
285 }                                              << 
286                                                << 
287 static bool sof_ipc4_switch_put(struct snd_sof << 
288                                 struct snd_ctl << 
289 {                                              << 
290         struct sof_ipc4_control_data *cdata =  << 
291         struct snd_soc_component *scomp = scon << 
292         struct snd_sof_dev *sdev = snd_soc_com << 
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 << 
302                 value = ucontrol->value.intege << 
303                 change = change || (value != c << 
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 con << 
312         list_for_each_entry(swidget, &sdev->wi << 
313                 if (swidget->comp_id == scontr << 
314                         widget_found = true;   << 
315                         break;                 << 
316                 }                              << 
317         }                                      << 
318                                                << 
319         if (!widget_found) {                   << 
320                 dev_err(scomp->dev, "Failed to << 
321                 return false;                  << 
322         }                                      << 
323                                                << 
324         ret = sof_ipc4_set_generic_control_dat << 
325         if (ret < 0)                           << 
326                 return false;                  << 
327                                                << 
328         return change;                         << 
329 }                                              << 
330                                                << 
331 static int sof_ipc4_switch_get(struct snd_sof_ << 
332                                struct snd_ctl_ << 
333 {                                              << 
334         struct sof_ipc4_control_data *cdata =  << 
335         unsigned int i;                        << 
336                                                << 
337         sof_ipc4_refresh_generic_control(scont << 
338                                                << 
339         /* read back each channel */           << 
340         for (i = 0; i < scontrol->num_channels << 
341                 ucontrol->value.integer.value[ << 
342                                                << 
343         return 0;                              << 
344 }                                              << 
345                                                << 
346 static bool sof_ipc4_enum_put(struct snd_sof_c << 
347                               struct snd_ctl_e << 
348 {                                              << 
349         struct sof_ipc4_control_data *cdata =  << 
350         struct snd_soc_component *scomp = scon << 
351         struct snd_sof_dev *sdev = snd_soc_com << 
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 << 
361                 value = ucontrol->value.enumer << 
362                 change = change || (value != c << 
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 con << 
371         list_for_each_entry(swidget, &sdev->wi << 
372                 if (swidget->comp_id == scontr << 
373                         widget_found = true;   << 
374                         break;                 << 
375                 }                              << 
376         }                                      << 
377                                                << 
378         if (!widget_found) {                   << 
379                 dev_err(scomp->dev, "Failed to << 
380                 return false;                  << 
381         }                                      << 
382                                                << 
383         ret = sof_ipc4_set_generic_control_dat << 
384         if (ret < 0)                           << 
385                 return false;                  << 
386                                                << 
387         return change;                         << 
388 }                                              << 
389                                                << 
390 static int sof_ipc4_enum_get(struct snd_sof_co << 
391                              struct snd_ctl_el << 
392 {                                              << 
393         struct sof_ipc4_control_data *cdata =  << 
394         unsigned int i;                        << 
395                                                << 
396         sof_ipc4_refresh_generic_control(scont << 
397                                                << 
398         /* read back each channel */           << 
399         for (i = 0; i < scontrol->num_channels << 
400                 ucontrol->value.enumerated.ite << 
401                                                << 
402         return 0;                              << 
403 }                                              << 
404                                                << 
405 static int sof_ipc4_set_get_bytes_data(struct  << 
406                                        struct  << 
407                                        bool se << 
408 {                                              << 
409         struct sof_ipc4_control_data *cdata =  << 
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 o << 
415         if (set && !pm_runtime_active(sdev->de << 
416                 return 0;                      << 
417                                                << 
418         msg->extension = SOF_IPC4_MOD_EXT_MSG_ << 
419                                                << 
420         msg->data_ptr = data->data;            << 
421         msg->data_size = data->size;           << 
422                                                << 
423         ret = sof_ipc4_set_get_kcontrol_data(s << 
424         if (ret < 0)                           << 
425                 dev_err(sdev->dev, "Failed to  << 
426                         set ? "set bytes updat << 
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_c << 
436                               struct snd_ctl_e << 
437 {                                              << 
438         struct sof_ipc4_control_data *cdata =  << 
439         struct snd_soc_component *scomp = scon << 
440         struct snd_sof_dev *sdev = snd_soc_com << 
441         struct sof_abi_hdr *data = cdata->data << 
442         size_t size;                           << 
443                                                << 
444         if (scontrol->max_size > sizeof(ucontr << 
445                 dev_err_ratelimited(scomp->dev << 
446                                     "data max  << 
447                                     scontrol-> << 
448                 return -EINVAL;                << 
449         }                                      << 
450                                                << 
451         /* scontrol->max_size has been verifie << 
452         if (data->size > scontrol->max_size -  << 
453                 dev_err_ratelimited(scomp->dev << 
454                                     "data size << 
455                                     data->size << 
456                 return -EINVAL;                << 
457         }                                      << 
458                                                << 
459         size = data->size + sizeof(*data);     << 
460                                                << 
461         /* copy from kcontrol */               << 
462         memcpy(data, ucontrol->value.bytes.dat << 
463                                                << 
464         sof_ipc4_set_get_bytes_data(sdev, scon << 
465                                                << 
466         return 0;                              << 
467 }                                              << 
468                                                << 
469 static int sof_ipc4_bytes_get(struct snd_sof_c << 
470                               struct snd_ctl_e << 
471 {                                              << 
472         struct sof_ipc4_control_data *cdata =  << 
473         struct snd_soc_component *scomp = scon << 
474         struct sof_abi_hdr *data = cdata->data << 
475         size_t size;                           << 
476                                                << 
477         if (scontrol->max_size > sizeof(ucontr << 
478                 dev_err_ratelimited(scomp->dev << 
479                                     scontrol-> << 
480                 return -EINVAL;                << 
481         }                                      << 
482                                                << 
483         if (data->size > scontrol->max_size -  << 
484                 dev_err_ratelimited(scomp->dev << 
485                                     "%u bytes  << 
486                                     data->size << 
487                 return -EINVAL;                << 
488         }                                      << 
489                                                << 
490         size = data->size + sizeof(*data);     << 
491                                                << 
492         /* copy back to kcontrol */            << 
493         memcpy(ucontrol->value.bytes.data, dat << 
494                                                << 
495         return 0;                              << 
496 }                                              << 
497                                                << 
498 static int sof_ipc4_bytes_ext_put(struct snd_s << 
499                                   const unsign << 
500                                   unsigned int << 
501 {                                              << 
502         struct snd_ctl_tlv __user *tlvd = (str << 
503         struct sof_ipc4_control_data *cdata =  << 
504         struct snd_soc_component *scomp = scon << 
505         struct snd_sof_dev *sdev = snd_soc_com << 
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 contain << 
512          * the length (as bytes) is needed to  << 
513          * length of data from tlvd->tlv.      << 
514          */                                    << 
515         if (copy_from_user(&header, tlvd, size << 
516                 return -EFAULT;                << 
517                                                << 
518         /* make sure TLV info is consistent */ << 
519         if (header.length + sizeof(struct snd_ << 
520                 dev_err_ratelimited(scomp->dev << 
521                                     "Inconsist << 
522                                     header.len << 
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 dat << 
530                                     header.len << 
531                 return -EINVAL;                << 
532         }                                      << 
533                                                << 
534         /* Verify the ABI header first */      << 
535         if (copy_from_user(&abi_hdr, tlvd->tlv << 
536                 return -EFAULT;                << 
537                                                << 
538         if (abi_hdr.magic != SOF_IPC4_ABI_MAGI << 
539                 dev_err_ratelimited(scomp->dev << 
540                                     abi_hdr.ma << 
541                 return -EINVAL;                << 
542         }                                      << 
543                                                << 
544         if (abi_hdr.size > scontrol->max_size  << 
545                 dev_err_ratelimited(scomp->dev << 
546                                     "%u bytes  << 
547                                     abi_hdr.si << 
548                 return -EINVAL;                << 
549         }                                      << 
550                                                << 
551         if (!scontrol->old_ipc_control_data) { << 
552                 /* Create a backup of the curr << 
553                 scontrol->old_ipc_control_data << 
554                                                << 
555                 if (!scontrol->old_ipc_control << 
556                         return -ENOMEM;        << 
557         }                                      << 
558                                                << 
559         /* Copy the whole binary data which in << 
560         if (copy_from_user(data, tlvd->tlv, he << 
561                 memcpy(scontrol->ipc_control_d << 
562                        scontrol->max_size);    << 
563                 kfree(scontrol->old_ipc_contro << 
564                 scontrol->old_ipc_control_data << 
565                 return -EFAULT;                << 
566         }                                      << 
567                                                << 
568         return sof_ipc4_set_get_bytes_data(sde << 
569 }                                              << 
570                                                << 
571 static int _sof_ipc4_bytes_ext_get(struct snd_ << 
572                                    const unsig << 
573                                    unsigned in << 
574 {                                              << 
575         struct snd_ctl_tlv __user *tlvd = (str << 
576         struct sof_ipc4_control_data *cdata =  << 
577         struct snd_soc_component *scomp = scon << 
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 he << 
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 << 
594                 int ret = sof_ipc4_set_get_byt << 
595                                                << 
596                 if (ret < 0)                   << 
597                         return ret;            << 
598                                                << 
599                 /* Set the ABI magic (if the c << 
600                 data->magic = SOF_IPC4_ABI_MAG << 
601         }                                      << 
602                                                << 
603         if (data->size > scontrol->max_size -  << 
604                 dev_err_ratelimited(scomp->dev << 
605                                     "%u bytes  << 
606                                     data->size << 
607                 return -EINVAL;                << 
608         }                                      << 
609                                                << 
610         data_size = data->size + sizeof(struct << 
611                                                << 
612         /* make sure we don't exceed size prov << 
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 << 
620                 return -EFAULT;                << 
621                                                << 
622         if (copy_to_user(tlvd->tlv, data, data << 
623                 return -EFAULT;                << 
624                                                << 
625         return 0;                              << 
626 }                                              << 
627                                                << 
628 static int sof_ipc4_bytes_ext_get(struct snd_s << 
629                                   const unsign << 
630                                   unsigned int << 
631 {                                              << 
632         return _sof_ipc4_bytes_ext_get(scontro << 
633 }                                              << 
634                                                << 
635 static int sof_ipc4_bytes_ext_volatile_get(str << 
636                                            con << 
637                                            uns << 
638 {                                              << 
639         return _sof_ipc4_bytes_ext_get(scontro << 
640 }                                              << 
641                                                << 
642 static int                                     << 
643 sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, << 
644                      struct snd_sof_control *s << 
645 {                                              << 
646         if (scontrol->max == 1)                << 
647                 return sof_ipc4_set_generic_co << 
648                                                << 
649         return sof_ipc4_set_volume_data(sdev,  << 
650 }                                              << 
651                                                << 
652 #define PARAM_ID_FROM_EXTENSION(_ext)   (((_ex << 
653                                          >> SO << 
654                                                << 
655 static void sof_ipc4_control_update(struct snd << 
656 {                                              << 
657         struct sof_ipc4_msg *ipc4_msg = ipc_me << 
658         struct sof_ipc4_notify_module_data *nd << 
659         struct sof_ipc4_control_msg_payload *m << 
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(*m << 
670                 dev_err(sdev->dev,             << 
671                         "%s: Invalid event dat << 
672                         __func__, ndata->modul << 
673                         ndata->event_data_size << 
674                 return;                        << 
675         }                                      << 
676                                                << 
677         event_param_id = ndata->event_id & SOF << 
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 t << 
688                         __func__, ndata->modul << 
689                         event_param_id);       << 
690                 return;                        << 
691         }                                      << 
692                                                << 
693         /* Find the swidget based on ndata->mo << 
694         swidget = sof_ipc4_find_swidget_by_ids << 
695                                                << 
696         if (!swidget) {                        << 
697                 dev_err(sdev->dev, "%s: Failed << 
698                         __func__, ndata->modul << 
699                 return;                        << 
700         }                                      << 
701                                                << 
702         /* Find the scontrol which is the sour << 
703         msg_data = (struct sof_ipc4_control_ms << 
704         list_for_each_entry(scontrol, &sdev->k << 
705                 if (scontrol->comp_id == swidg << 
706                         u32 local_param_id;    << 
707                                                << 
708                         cdata = scontrol->ipc_ << 
709                         /*                     << 
710                          * The scontrol's para << 
711                          * template's extensio << 
712                          */                    << 
713                         local_param_id = PARAM << 
714                         if (local_param_id ==  << 
715                             msg_data->id == cd << 
716                                 scontrol_found << 
717                                 break;         << 
718                         }                      << 
719                 }                              << 
720         }                                      << 
721                                                << 
722         if (!scontrol_found) {                 << 
723                 dev_err(sdev->dev,             << 
724                         "%s: Failed to find co << 
725                         __func__, swidget->wid << 
726                         msg_data->id);         << 
727                 return;                        << 
728         }                                      << 
729                                                << 
730         if (msg_data->num_elems) {             << 
731                 /*                             << 
732                  * The message includes the up << 
733                  * control's local cache using << 
734                  */                            << 
735                 for (i = 0; i < msg_data->num_ << 
736                         u32 channel = msg_data << 
737                                                << 
738                         if (channel >= scontro << 
739                                 dev_warn(sdev- << 
740                                          "Inva << 
741                                          scont << 
742                                                << 
743                                 /*             << 
744                                  * Mark the sc << 
745                                  * on next rea << 
746                                  */            << 
747                                 scontrol->comp << 
748                                 break;         << 
749                         }                      << 
750                                                << 
751                         cdata->chanv[channel]. << 
752                 }                              << 
753         } else {                               << 
754                 /*                             << 
755                  * Mark the scontrol as dirty  << 
756                  * in firmware, forcing a refr << 
757                  */                            << 
758                 scontrol->comp_data_dirty = tr << 
759         }                                      << 
760                                                << 
761         /*                                     << 
762          * Look up the ALSA kcontrol of the sc << 
763          * notification to user space          << 
764          */                                    << 
765         widget = swidget->widget;              << 
766         for (i = 0; i < widget->num_kcontrols; << 
767                 /* skip non matching types or  << 
768                 if (widget->dobj.widget.kcontr << 
769                     widget->kcontrol_news[i].i << 
770                         kc = widget->kcontrols << 
771                         break;                 << 
772                 }                              << 
773         }                                      << 
774                                                << 
775         if (!kc)                               << 
776                 return;                        << 
777                                                << 
778         snd_ctl_notify_one(swidget->scomp->car << 
779                            SNDRV_CTL_EVENT_MAS << 
780 }                                              << 
781                                                << 
782 /* set up all controls for the widget */          170 /* set up all controls for the widget */
783 static int sof_ipc4_widget_kcontrol_setup(stru    171 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
784 {                                                 172 {
785         struct snd_sof_control *scontrol;         173         struct snd_sof_control *scontrol;
786         int ret = 0;                           !! 174         int ret;
787                                                   175 
788         list_for_each_entry(scontrol, &sdev->k !! 176         list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
789                 if (scontrol->comp_id == swidg    177                 if (scontrol->comp_id == swidget->comp_id) {
790                         switch (scontrol->info !! 178                         ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
791                         case SND_SOC_TPLG_CTL_ << 
792                         case SND_SOC_TPLG_CTL_ << 
793                         case SND_SOC_TPLG_CTL_ << 
794                                 ret = sof_ipc4 << 
795                                 break;         << 
796                         case SND_SOC_TPLG_CTL_ << 
797                                 ret = sof_ipc4 << 
798                                                << 
799                                 break;         << 
800                         case SND_SOC_TPLG_CTL_ << 
801                         case SND_SOC_TPLG_CTL_ << 
802                                 ret = sof_ipc4 << 
803                                                << 
804                                 break;         << 
805                         default:               << 
806                                 break;         << 
807                         }                      << 
808                                                << 
809                         if (ret < 0) {            179                         if (ret < 0) {
810                                 dev_err(sdev-> !! 180                                 dev_err(sdev->dev, "%s: kcontrol %d set up failed for widget %s\n",
811                                         "kcont !! 181                                         __func__, scontrol->comp_id, swidget->widget->name);
812                                         scontr << 
813                                 return ret;       182                                 return ret;
814                         }                         183                         }
815                 }                                 184                 }
816         }                                      << 
817                                                   185 
818         return 0;                                 186         return 0;
819 }                                                 187 }
820                                                   188 
821 static int                                        189 static int
822 sof_ipc4_set_up_volume_table(struct snd_sof_co    190 sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
823 {                                                 191 {
824         int i;                                    192         int i;
825                                                   193 
826         /* init the volume table */               194         /* init the volume table */
827         scontrol->volume_table = kcalloc(size,    195         scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
828         if (!scontrol->volume_table)              196         if (!scontrol->volume_table)
829                 return -ENOMEM;                   197                 return -ENOMEM;
830                                                   198 
831         /* populate the volume table */           199         /* populate the volume table */
832         for (i = 0; i < size ; i++) {             200         for (i = 0; i < size ; i++) {
833                 u32 val = vol_compute_gain(i,     201                 u32 val = vol_compute_gain(i, tlv);
834                 u64 q31val = ((u64)val) << 15;    202                 u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */
835                                                   203 
836                 scontrol->volume_table[i] = q3    204                 scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
837                                                   205                                                 SOF_IPC4_VOL_ZERO_DB : q31val;
838         }                                         206         }
839                                                   207 
840         return 0;                                 208         return 0;
841 }                                                 209 }
842                                                   210 
843 const struct sof_ipc_tplg_control_ops tplg_ipc    211 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
844         .volume_put = sof_ipc4_volume_put,        212         .volume_put = sof_ipc4_volume_put,
845         .volume_get = sof_ipc4_volume_get,        213         .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_pu << 
853         .bytes_ext_get = sof_ipc4_bytes_ext_ge << 
854         .bytes_ext_volatile_get = sof_ipc4_byt << 
855         .update = sof_ipc4_control_update,     << 
856         .widget_kcontrol_setup = sof_ipc4_widg    214         .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
857         .set_up_volume_table = sof_ipc4_set_up    215         .set_up_volume_table = sof_ipc4_set_up_volume_table,
858 };                                                216 };
859                                                   217 

~ [ 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