~ [ 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 (Architecture mips) and /sound/soc/sof/ipc4-control.c (Architecture alpha)


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