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


  1 // SPDX-License-Identifier: (GPL-2.0-only OR B      1 
  2 //                                                
  3 // This file is provided under a dual BSD/GPLv    
  4 // redistributing this file, you may do so und    
  5 //                                                
  6 // Copyright(c) 2022 Intel Corporation            
  7 //                                                
  8 //                                                
  9                                                   
 10 #include "sof-priv.h"                             
 11 #include "sof-audio.h"                            
 12 #include "ipc4-priv.h"                            
 13 #include "ipc4-topology.h"                        
 14                                                   
 15 static int sof_ipc4_set_get_kcontrol_data(stru    
 16                                           bool    
 17 {                                                 
 18         struct sof_ipc4_control_data *cdata =     
 19         struct snd_soc_component *scomp = scon    
 20         struct snd_sof_dev *sdev = snd_soc_com    
 21         const struct sof_ipc_ops *iops = sdev-    
 22         struct sof_ipc4_msg *msg = &cdata->msg    
 23         struct snd_sof_widget *swidget;           
 24         bool widget_found = false;                
 25         int ret = 0;                              
 26                                                   
 27         /* find widget associated with the con    
 28         list_for_each_entry(swidget, &sdev->wi    
 29                 if (swidget->comp_id == scontr    
 30                         widget_found = true;      
 31                         break;                    
 32                 }                                 
 33         }                                         
 34                                                   
 35         if (!widget_found) {                      
 36                 dev_err(scomp->dev, "Failed to    
 37                 return -ENOENT;                   
 38         }                                         
 39                                                   
 40         if (lock)                                 
 41                 mutex_lock(&swidget->setup_mut    
 42         else                                      
 43                 lockdep_assert_held(&swidget->    
 44                                                   
 45         /*                                        
 46          * Volatile controls should always be     
 47          * widget use_count would always be >     
 48          * just return the cached value if the    
 49          */                                       
 50         if (!swidget->use_count)                  
 51                 goto unlock;                      
 52                                                   
 53         msg->primary &= ~SOF_IPC4_MOD_INSTANCE    
 54         msg->primary |= SOF_IPC4_MOD_INSTANCE(    
 55                                                   
 56         ret = iops->set_get_data(sdev, msg, ms    
 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 }                                                 
 84                                                   
 85 static int                                        
 86 sof_ipc4_set_volume_data(struct snd_sof_dev *s    
 87                          struct snd_sof_contro    
 88 {                                                 
 89         struct sof_ipc4_control_data *cdata =     
 90         struct sof_ipc4_gain *gain = swidget->    
 91         struct sof_ipc4_msg *msg = &cdata->msg    
 92         struct sof_ipc4_gain_params params;       
 93         bool all_channels_equal = true;           
 94         u32 value;                                
 95         int ret, i;                               
 96                                                   
 97         /* check if all channel values are equ    
 98         value = cdata->chanv[0].value;            
 99         for (i = 1; i < scontrol->num_channels    
100                 if (cdata->chanv[i].value != v    
101                         all_channels_equal = f    
102                         break;                    
103                 }                                 
104         }                                         
105                                                   
106         /*                                        
107          * notify DSP with a single IPC messag    
108          * a separate IPC for each channel.       
109          */                                       
110         for (i = 0; i < scontrol->num_channels    
111                 if (all_channels_equal) {         
112                         params.channels = SOF_    
113                         params.init_val = cdat    
114                 } else {                          
115                         params.channels = cdat    
116                         params.init_val = cdat    
117                 }                                 
118                                                   
119                 /* set curve type and duration    
120                 params.curve_duration_l = gain    
121                 params.curve_duration_h = gain    
122                 params.curve_type = gain->data    
123                                                   
124                 msg->data_ptr = &params;          
125                 msg->data_size = sizeof(params    
126                                                   
127                 ret = sof_ipc4_set_get_kcontro    
128                 msg->data_ptr = NULL;             
129                 msg->data_size = 0;               
130                 if (ret < 0) {                    
131                         dev_err(sdev->dev, "Fa    
132                                 scontrol->name    
133                         return ret;               
134                 }                                 
135                                                   
136                 if (all_channels_equal)           
137                         break;                    
138         }                                         
139                                                   
140         return 0;                                 
141 }                                                 
142                                                   
143 static bool sof_ipc4_volume_put(struct snd_sof    
144                                 struct snd_ctl    
145 {                                                 
146         struct sof_ipc4_control_data *cdata =     
147         struct snd_soc_component *scomp = scon    
148         struct snd_sof_dev *sdev = snd_soc_com    
149         unsigned int channels = scontrol->num_    
150         struct snd_sof_widget *swidget;           
151         bool widget_found = false;                
152         bool change = false;                      
153         unsigned int i;                           
154         int ret;                                  
155                                                   
156         /* update each channel */                 
157         for (i = 0; i < channels; i++) {          
158                 u32 value = mixer_to_ipc(ucont    
159                                          scont    
160                                                   
161                 change = change || (value != c    
162                 cdata->chanv[i].channel = i;      
163                 cdata->chanv[i].value = value;    
164         }                                         
165                                                   
166         if (!pm_runtime_active(scomp->dev))       
167                 return change;                    
168                                                   
169         /* find widget associated with the con    
170         list_for_each_entry(swidget, &sdev->wi    
171                 if (swidget->comp_id == scontr    
172                         widget_found = true;      
173                         break;                    
174                 }                                 
175         }                                         
176                                                   
177         if (!widget_found) {                      
178                 dev_err(scomp->dev, "Failed to    
179                 return false;                     
180         }                                         
181                                                   
182         ret = sof_ipc4_set_volume_data(sdev, s    
183         if (ret < 0)                              
184                 return false;                     
185                                                   
186         return change;                            
187 }                                                 
188                                                   
189 static int sof_ipc4_volume_get(struct snd_sof_    
190                                struct snd_ctl_    
191 {                                                 
192         struct sof_ipc4_control_data *cdata =     
193         unsigned int channels = scontrol->num_    
194         unsigned int i;                           
195                                                   
196         for (i = 0; i < channels; i++)            
197                 ucontrol->value.integer.value[    
198                                                   
199                                                   
200                                                   
201         return 0;                                 
202 }                                                 
203                                                   
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 */          
783 static int sof_ipc4_widget_kcontrol_setup(stru    
784 {                                                 
785         struct snd_sof_control *scontrol;         
786         int ret = 0;                              
787                                                   
788         list_for_each_entry(scontrol, &sdev->k    
789                 if (scontrol->comp_id == swidg    
790                         switch (scontrol->info    
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) {            
810                                 dev_err(sdev->    
811                                         "kcont    
812                                         scontr    
813                                 return ret;       
814                         }                         
815                 }                                 
816         }                                         
817                                                   
818         return 0;                                 
819 }                                                 
820                                                   
821 static int                                        
822 sof_ipc4_set_up_volume_table(struct snd_sof_co    
823 {                                                 
824         int i;                                    
825                                                   
826         /* init the volume table */               
827         scontrol->volume_table = kcalloc(size,    
828         if (!scontrol->volume_table)              
829                 return -ENOMEM;                   
830                                                   
831         /* populate the volume table */           
832         for (i = 0; i < size ; i++) {             
833                 u32 val = vol_compute_gain(i,     
834                 u64 q31val = ((u64)val) << 15;    
835                                                   
836                 scontrol->volume_table[i] = q3    
837                                                   
838         }                                         
839                                                   
840         return 0;                                 
841 }                                                 
842                                                   
843 const struct sof_ipc_tplg_control_ops tplg_ipc    
844         .volume_put = sof_ipc4_volume_put,        
845         .volume_get = sof_ipc4_volume_get,        
846         .switch_put = sof_ipc4_switch_put,        
847         .switch_get = sof_ipc4_switch_get,        
848         .enum_put = sof_ipc4_enum_put,            
849         .enum_get = sof_ipc4_enum_get,            
850         .bytes_put = sof_ipc4_bytes_put,          
851         .bytes_get = sof_ipc4_bytes_get,          
852         .bytes_ext_put = sof_ipc4_bytes_ext_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    
857         .set_up_volume_table = sof_ipc4_set_up    
858 };                                                
859                                                   

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

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

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

sflogo.php