@@ -73,6 +73,9 @@ struct macaudio_snd_data {
7373 bool is_headphones ;
7474 unsigned int tdm_mask ;
7575 } * link_props ;
76+
77+ bool speakers_streaming ;
78+ struct snd_kcontrol * speakers_streaming_kctl ;
7679};
7780
7881static bool please_blow_up_my_speakers ;
@@ -566,13 +569,45 @@ static void macaudio_dpcm_shutdown(struct snd_pcm_substream *substream)
566569 }
567570}
568571
572+ static int macaudio_be_prepare (struct snd_pcm_substream * substream )
573+ {
574+ struct snd_soc_pcm_runtime * rtd = snd_soc_substream_to_rtd (substream );
575+ struct macaudio_snd_data * ma = snd_soc_card_get_drvdata (rtd -> card );
576+ struct macaudio_link_props * props = & ma -> link_props [rtd -> dai_link -> id ];
577+
578+ if (props -> is_speakers ) {
579+ ma -> speakers_streaming = true;
580+ snd_ctl_notify (ma -> card .snd_card , SNDRV_CTL_EVENT_MASK_VALUE ,
581+ & ma -> speakers_streaming_kctl -> id );
582+ }
583+
584+ return 0 ;
585+ }
586+
587+ static int macaudio_be_hw_free (struct snd_pcm_substream * substream )
588+ {
589+ struct snd_soc_pcm_runtime * rtd = snd_soc_substream_to_rtd (substream );
590+ struct macaudio_snd_data * ma = snd_soc_card_get_drvdata (rtd -> card );
591+ struct macaudio_link_props * props = & ma -> link_props [rtd -> dai_link -> id ];
592+
593+ if (props -> is_speakers ) {
594+ ma -> speakers_streaming = false;
595+ snd_ctl_notify (ma -> card .snd_card , SNDRV_CTL_EVENT_MASK_VALUE ,
596+ & ma -> speakers_streaming_kctl -> id );
597+ }
598+
599+ return 0 ;
600+ }
601+
569602static const struct snd_soc_ops macaudio_fe_ops = {
570603 .startup = macaudio_fe_startup ,
571604 .shutdown = macaudio_dpcm_shutdown ,
572605 .hw_params = macaudio_fe_hw_params ,
573606};
574607
575608static const struct snd_soc_ops macaudio_be_ops = {
609+ .prepare = macaudio_be_prepare ,
610+ .hw_free = macaudio_be_hw_free ,
576611 .shutdown = macaudio_dpcm_shutdown ,
577612 .hw_params = macaudio_dpcm_hw_params ,
578613};
@@ -803,6 +838,8 @@ static int macaudio_late_probe(struct snd_soc_card *card)
803838 }
804839 }
805840
841+ ma -> speakers_streaming_kctl = snd_soc_card_get_kcontrol (card , "Speakers Up Indicator" );
842+
806843 return 0 ;
807844}
808845
@@ -976,10 +1013,42 @@ static const struct snd_soc_dapm_widget macaudio_snd_widgets[] = {
9761013 SND_SOC_DAPM_AIF_IN ("Speaker Sense Capture" , NULL , 0 , SND_SOC_NOPM , 0 , 0 ),
9771014};
9781015
1016+ static int macaudio_sss_info (struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
1017+ {
1018+ uinfo -> type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
1019+ uinfo -> count = 1 ;
1020+ uinfo -> value .integer .min = 0 ;
1021+ uinfo -> value .integer .max = 1 ;
1022+
1023+ return 0 ;
1024+ }
1025+
1026+ static int macaudio_sss_get (struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * uvalue )
1027+ {
1028+ struct snd_soc_card * card = snd_kcontrol_chip (kcontrol );
1029+ struct macaudio_snd_data * ma = snd_soc_card_get_drvdata (card );
1030+
1031+ /*
1032+ * TODO: Check if any locking is in order here. I would
1033+ * assume there is some ALSA-level lock, but DAPM implementations
1034+ * of kcontrol ops do explicit locking, so look into it.
1035+ */
1036+ uvalue -> value .integer .value [0 ] = ma -> speakers_streaming ;
1037+
1038+ return 0 ;
1039+ }
1040+
9791041static const struct snd_kcontrol_new macaudio_controls [] = {
9801042 SOC_DAPM_PIN_SWITCH ("Speaker" ),
9811043 SOC_DAPM_PIN_SWITCH ("Headphone" ),
9821044 SOC_DAPM_PIN_SWITCH ("Headset Mic" ),
1045+ {
1046+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
1047+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
1048+ SNDRV_CTL_ELEM_ACCESS_VOLATILE ,
1049+ .name = "Speakers Up Indicator" ,
1050+ .info = macaudio_sss_info , .get = macaudio_sss_get ,
1051+ },
9831052};
9841053
9851054static const struct snd_soc_dapm_route macaudio_dapm_routes [] = {
0 commit comments