@@ -649,6 +649,130 @@ sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
649649 return sof_ipc4_set_volume_data (sdev , swidget , scontrol , false);
650650}
651651
652+ struct sof_ipc4_kcontrol_global_priv {
653+ struct snd_card * snd_card ;
654+ struct snd_kcontrol * capture_hw_mute ;
655+ };
656+
657+ static int sof_ipc4_capture_hw_mute_get (struct snd_kcontrol * kcontrol ,
658+ struct snd_ctl_elem_value * ucontrol )
659+ {
660+ ucontrol -> value .integer .value [0 ] = kcontrol -> private_value ;
661+ return 0 ;
662+ }
663+
664+ static const struct snd_kcontrol_new sof_ipc4_capture_hw_mute = {
665+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
666+ .access = SNDRV_CTL_ELEM_ACCESS_READ ,
667+ .name = "Global capture HW mute indicator" ,
668+ .info = snd_ctl_boolean_mono_info ,
669+ .get = sof_ipc4_capture_hw_mute_get ,
670+ };
671+
672+ static struct snd_card * sof_scomp_get_card (struct snd_soc_component * scomp )
673+ {
674+ struct device * dev = scomp -> dev ;
675+
676+ if (!scomp -> card ) {
677+ dev_err (dev , "%s: No snd_soc_card" , __func__ );
678+ return NULL ;
679+ }
680+
681+ return scomp -> card -> snd_card ;
682+ }
683+
684+ static int sof_ipc4_create_non_topology_controls (struct snd_sof_dev * sdev ,
685+ struct snd_soc_component * scomp )
686+ {
687+ struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
688+ struct snd_card * snd_card = sof_scomp_get_card (scomp );
689+ struct device * dev = sdev -> dev ;
690+ struct sof_ipc4_kcontrol_global_priv * priv ;
691+ int ret ;
692+
693+ if (!snd_card ) {
694+ dev_err (dev , "%s: Card not found!" , __func__ );
695+ return - ENODEV ;
696+ }
697+
698+ if (!ipc4_data -> global_kcontrol_mask )
699+ return 0 ;
700+
701+ priv = devm_kzalloc (dev , sizeof (* priv ), GFP_KERNEL );
702+ if (!priv )
703+ return - ENOMEM ;
704+
705+ priv -> snd_card = snd_card ;
706+
707+ if (ipc4_data -> global_kcontrol_mask &
708+ BIT (SOF_IPC4_KCONTROL_GLOBAL_CAPTURE_HW_MUTE )) {
709+ struct snd_kcontrol * kctl ;
710+
711+ kctl = snd_ctl_new1 (& sof_ipc4_capture_hw_mute , NULL );
712+ if (!kctl ) {
713+ dev_err (dev , "%s: snd_ctl_new1(): failed" , __func__ );
714+ return - EINVAL ;
715+ }
716+
717+ kctl -> private_value = 0 ;
718+
719+ ret = snd_ctl_add (snd_card , kctl );
720+ if (ret < 0 )
721+ dev_err (dev , "%s: snd_ctl_add(): failed" , __func__ );
722+ else
723+ priv -> capture_hw_mute = kctl ;
724+ }
725+
726+ ipc4_data -> global_kcontrol_priv = priv ;
727+
728+ return 0 ;
729+ }
730+
731+ static void snd_ipc4_global_capture_hw_mute_report (struct snd_sof_dev * sdev ,
732+ bool status )
733+ {
734+ struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
735+ struct sof_ipc4_kcontrol_global_priv * priv = ipc4_data -> global_kcontrol_priv ;
736+ struct device * dev = sdev -> dev ;
737+ struct snd_kcontrol * kctl ;
738+
739+ if (!priv || !priv -> capture_hw_mute )
740+ return ;
741+
742+ kctl = priv -> capture_hw_mute ;
743+
744+ dev_dbg (dev , "%s: reporting %u, old %lu" , __func__ ,
745+ status , kctl -> private_value );
746+
747+ if (kctl -> private_value == status )
748+ return ;
749+
750+ kctl -> private_value = status ;
751+ snd_ctl_notify (priv -> snd_card , SNDRV_CTL_EVENT_MASK_VALUE , & kctl -> id );
752+ }
753+
754+ static void snd_ipc4_handle_global_event (struct snd_sof_dev * sdev ,
755+ struct sof_ipc4_control_msg_payload * msg_data )
756+ {
757+ struct device * dev = sdev -> dev ;
758+
759+ dev_dbg (dev , "%s: got msg id %u num_elems %u" , __func__ ,
760+ msg_data -> id , msg_data -> num_elems );
761+
762+ switch (msg_data -> id ) {
763+ case SOF_IPC4_KCONTROL_GLOBAL_CAPTURE_HW_MUTE :
764+ if (msg_data -> num_elems == 1 || msg_data -> chanv [0 ].channel == 0 )
765+ snd_ipc4_global_capture_hw_mute_report (sdev , msg_data -> chanv [0 ].value );
766+ else
767+ dev_warn (dev , "%s: bad data for id %u chan 0 %u" , __func__ ,
768+ msg_data -> id , msg_data -> chanv [0 ].channel );
769+ break ;
770+ default :
771+ dev_warn (dev , "%s: unknown global control elem id %u" , __func__ ,
772+ msg_data -> id );
773+ }
774+ }
775+
652776#define PARAM_ID_FROM_EXTENSION (_ext ) (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) \
653777 >> SOF_IPC4_MOD_EXT_MSG_PARAM_ID_SHIFT)
654778
@@ -673,6 +797,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
673797 ndata -> event_data_size );
674798 return ;
675799 }
800+ msg_data = (struct sof_ipc4_control_msg_payload * )ndata -> event_data ;
676801
677802 event_param_id = ndata -> event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK ;
678803 switch (event_param_id ) {
@@ -690,6 +815,14 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
690815 return ;
691816 }
692817
818+ if (ndata -> module_id == SOF_IPC4_MOD_INIT_BASEFW_MOD_ID &&
819+ ndata -> instance_id == SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID ) {
820+ dev_dbg (sdev -> dev , "Received global notifier event_id %#x" ,
821+ event_param_id );
822+ snd_ipc4_handle_global_event (sdev , msg_data );
823+ return ;
824+ }
825+
693826 /* Find the swidget based on ndata->module_id and ndata->instance_id */
694827 swidget = sof_ipc4_find_swidget_by_ids (sdev , ndata -> module_id ,
695828 ndata -> instance_id );
@@ -700,7 +833,6 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
700833 }
701834
702835 /* Find the scontrol which is the source of the notification */
703- msg_data = (struct sof_ipc4_control_msg_payload * )ndata -> event_data ;
704836 list_for_each_entry (scontrol , & sdev -> kcontrol_list , list ) {
705837 if (scontrol -> comp_id == swidget -> comp_id ) {
706838 u32 local_param_id ;
@@ -855,4 +987,5 @@ const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
855987 .update = sof_ipc4_control_update ,
856988 .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup ,
857989 .set_up_volume_table = sof_ipc4_set_up_volume_table ,
990+ .create_non_topology_controls = sof_ipc4_create_non_topology_controls ,
858991};
0 commit comments