@@ -65,6 +65,40 @@ static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
6565 return i - 1 ;
6666}
6767
68+ static void snd_sof_refresh_control (struct snd_sof_control * scontrol )
69+ {
70+ struct sof_ipc_ctrl_data * cdata = scontrol -> control_data ;
71+ struct snd_soc_component * scomp = scontrol -> scomp ;
72+ enum sof_ipc_ctrl_type ctrl_type ;
73+ int ret ;
74+
75+ if (!scontrol -> comp_data_dirty )
76+ return ;
77+
78+ if (!pm_runtime_active (scomp -> dev ))
79+ return ;
80+
81+ if (scontrol -> cmd == SOF_CTRL_CMD_BINARY )
82+ ctrl_type = SOF_IPC_COMP_GET_DATA ;
83+ else
84+ ctrl_type = SOF_IPC_COMP_GET_VALUE ;
85+
86+ /* set the ABI header values */
87+ cdata -> data -> magic = SOF_ABI_MAGIC ;
88+ cdata -> data -> abi = SOF_ABI_VERSION ;
89+
90+ /* refresh the component data from DSP */
91+ scontrol -> comp_data_dirty = false;
92+ ret = snd_sof_ipc_set_get_comp_data (scontrol , ctrl_type ,
93+ SOF_CTRL_TYPE_VALUE_CHAN_GET ,
94+ scontrol -> cmd , false);
95+ if (ret < 0 ) {
96+ dev_err (scomp -> dev , "error: failed to get control data: %d\n" , ret );
97+ /* Set the flag to re-try next time to get the data */
98+ scontrol -> comp_data_dirty = true;
99+ }
100+ }
101+
68102int snd_sof_volume_get (struct snd_kcontrol * kcontrol ,
69103 struct snd_ctl_elem_value * ucontrol )
70104{
@@ -74,6 +108,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
74108 struct sof_ipc_ctrl_data * cdata = scontrol -> control_data ;
75109 unsigned int i , channels = scontrol -> num_channels ;
76110
111+ snd_sof_refresh_control (scontrol );
112+
77113 /* read back each channel */
78114 for (i = 0 ; i < channels ; i ++ )
79115 ucontrol -> value .integer .value [i ] =
@@ -145,6 +181,8 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
145181 struct sof_ipc_ctrl_data * cdata = scontrol -> control_data ;
146182 unsigned int i , channels = scontrol -> num_channels ;
147183
184+ snd_sof_refresh_control (scontrol );
185+
148186 /* read back each channel */
149187 for (i = 0 ; i < channels ; i ++ )
150188 ucontrol -> value .integer .value [i ] = cdata -> chanv [i ].value ;
@@ -195,6 +233,8 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
195233 struct sof_ipc_ctrl_data * cdata = scontrol -> control_data ;
196234 unsigned int i , channels = scontrol -> num_channels ;
197235
236+ snd_sof_refresh_control (scontrol );
237+
198238 /* read back each channel */
199239 for (i = 0 ; i < channels ; i ++ )
200240 ucontrol -> value .enumerated .item [i ] = cdata -> chanv [i ].value ;
@@ -244,6 +284,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
244284 struct sof_abi_hdr * data = cdata -> data ;
245285 size_t size ;
246286
287+ snd_sof_refresh_control (scontrol );
288+
247289 if (be -> max > sizeof (ucontrol -> value .bytes .data )) {
248290 dev_err_ratelimited (scomp -> dev ,
249291 "error: data max %d exceeds ucontrol data array size\n" ,
@@ -475,6 +517,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
475517 (struct snd_ctl_tlv __user * )binary_data ;
476518 size_t data_size ;
477519
520+ snd_sof_refresh_control (scontrol );
521+
478522 /*
479523 * Decrement the limit by ext bytes header size to
480524 * ensure the user space buffer is not exceeded.
@@ -511,3 +555,145 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
511555
512556 return 0 ;
513557}
558+
559+ static void snd_sof_update_control (struct snd_sof_control * scontrol ,
560+ struct sof_ipc_ctrl_data * cdata )
561+ {
562+ struct snd_soc_component * scomp = scontrol -> scomp ;
563+ struct sof_ipc_ctrl_data * local_cdata ;
564+ int i ;
565+
566+ local_cdata = scontrol -> control_data ;
567+
568+ if (cdata -> cmd == SOF_CTRL_CMD_BINARY ) {
569+ if (cdata -> num_elems != local_cdata -> data -> size ) {
570+ dev_err (scomp -> dev ,
571+ "error: cdata binary size mismatch %u - %u\n" ,
572+ cdata -> num_elems , local_cdata -> data -> size );
573+ return ;
574+ }
575+
576+ /* copy the new binary data */
577+ memcpy (local_cdata -> data , cdata -> data , cdata -> num_elems );
578+ } else if (cdata -> num_elems != scontrol -> num_channels ) {
579+ dev_err (scomp -> dev ,
580+ "error: cdata channel count mismatch %u - %d\n" ,
581+ cdata -> num_elems , scontrol -> num_channels );
582+ } else {
583+ /* copy the new values */
584+ for (i = 0 ; i < cdata -> num_elems ; i ++ )
585+ local_cdata -> chanv [i ].value = cdata -> chanv [i ].value ;
586+ }
587+ }
588+
589+ void snd_sof_control_notify (struct snd_sof_dev * sdev ,
590+ struct sof_ipc_ctrl_data * cdata )
591+ {
592+ struct snd_soc_dapm_widget * widget ;
593+ struct snd_sof_control * scontrol ;
594+ struct snd_sof_widget * swidget ;
595+ struct snd_kcontrol * kc = NULL ;
596+ struct soc_mixer_control * sm ;
597+ struct soc_bytes_ext * be ;
598+ size_t expected_size ;
599+ struct soc_enum * se ;
600+ bool found = false;
601+ int i , type ;
602+
603+ /* Find the swidget first */
604+ list_for_each_entry (swidget , & sdev -> widget_list , list ) {
605+ if (swidget -> comp_id == cdata -> comp_id ) {
606+ found = true;
607+ break ;
608+ }
609+ }
610+
611+ if (!found )
612+ return ;
613+
614+ /* Translate SOF cmd to TPLG type */
615+ switch (cdata -> cmd ) {
616+ case SOF_CTRL_CMD_VOLUME :
617+ case SOF_CTRL_CMD_SWITCH :
618+ type = SND_SOC_TPLG_TYPE_MIXER ;
619+ break ;
620+ case SOF_CTRL_CMD_BINARY :
621+ type = SND_SOC_TPLG_TYPE_BYTES ;
622+ break ;
623+ case SOF_CTRL_CMD_ENUM :
624+ type = SND_SOC_TPLG_TYPE_ENUM ;
625+ break ;
626+ default :
627+ dev_err (sdev -> dev , "error: unknown cmd %u\n" , cdata -> cmd );
628+ return ;
629+ }
630+
631+ widget = swidget -> widget ;
632+ for (i = 0 ; i < widget -> num_kcontrols ; i ++ ) {
633+ /* skip non matching types or non matching indexes within type */
634+ if (widget -> dobj .widget .kcontrol_type [i ] == type &&
635+ widget -> kcontrol_news [i ].index == cdata -> index ) {
636+ kc = widget -> kcontrols [i ];
637+ break ;
638+ }
639+ }
640+
641+ if (!kc )
642+ return ;
643+
644+ switch (cdata -> cmd ) {
645+ case SOF_CTRL_CMD_VOLUME :
646+ case SOF_CTRL_CMD_SWITCH :
647+ sm = (struct soc_mixer_control * )kc -> private_value ;
648+ scontrol = sm -> dobj .private ;
649+ break ;
650+ case SOF_CTRL_CMD_BINARY :
651+ be = (struct soc_bytes_ext * )kc -> private_value ;
652+ scontrol = be -> dobj .private ;
653+ break ;
654+ case SOF_CTRL_CMD_ENUM :
655+ se = (struct soc_enum * )kc -> private_value ;
656+ scontrol = se -> dobj .private ;
657+ break ;
658+ default :
659+ return ;
660+ }
661+
662+ expected_size = sizeof (struct sof_ipc_ctrl_data );
663+ switch (cdata -> type ) {
664+ case SOF_CTRL_TYPE_VALUE_CHAN_GET :
665+ case SOF_CTRL_TYPE_VALUE_CHAN_SET :
666+ expected_size += cdata -> num_elems *
667+ sizeof (struct sof_ipc_ctrl_value_chan );
668+ break ;
669+ case SOF_CTRL_TYPE_VALUE_COMP_GET :
670+ case SOF_CTRL_TYPE_VALUE_COMP_SET :
671+ expected_size += cdata -> num_elems *
672+ sizeof (struct sof_ipc_ctrl_value_comp );
673+ break ;
674+ case SOF_CTRL_TYPE_DATA_GET :
675+ case SOF_CTRL_TYPE_DATA_SET :
676+ expected_size += cdata -> num_elems + sizeof (struct sof_abi_hdr );
677+ break ;
678+ default :
679+ return ;
680+ }
681+
682+ if (cdata -> rhdr .hdr .size != expected_size ) {
683+ dev_err (sdev -> dev , "error: component notification size mismatch\n" );
684+ return ;
685+ }
686+
687+ if (cdata -> num_elems )
688+ /*
689+ * The message includes the updated value/data, update the
690+ * control's local cache using the received notification
691+ */
692+ snd_sof_update_control (scontrol , cdata );
693+ else
694+ /* Mark the scontrol that the value/data is changed in SOF */
695+ scontrol -> comp_data_dirty = true;
696+
697+ snd_ctl_notify_one (swidget -> scomp -> card -> snd_card ,
698+ SNDRV_CTL_EVENT_MASK_VALUE , kc , 0 );
699+ }
0 commit comments