@@ -74,8 +74,8 @@ struct macaudio_snd_data {
7474 unsigned int tdm_mask ;
7575 } * link_props ;
7676
77- bool speakers_streaming ;
78- struct snd_kcontrol * speakers_streaming_kctl ;
77+ int speaker_sample_rate ;
78+ struct snd_kcontrol * speaker_sample_rate_kctl ;
7979};
8080
8181static bool please_blow_up_my_speakers ;
@@ -483,10 +483,37 @@ static int macaudio_dpcm_hw_params(struct snd_pcm_substream *substream,
483483 struct snd_pcm_hw_params * params )
484484{
485485 struct snd_soc_pcm_runtime * rtd = snd_soc_substream_to_rtd (substream );
486+ struct macaudio_snd_data * ma = snd_soc_card_get_drvdata (rtd -> card );
487+ struct macaudio_link_props * props = & ma -> link_props [rtd -> dai_link -> id ];
486488 struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
489+ struct snd_interval * rate = hw_param_interval (params ,
490+ SNDRV_PCM_HW_PARAM_RATE );
487491 int bclk_ratio = macaudio_get_runtime_bclk_ratio (substream );
488492 int i ;
489493
494+ if (props -> is_sense ) {
495+ rate -> min = rate -> max = cpu_dai -> symmetric_rate ;
496+ return 0 ;
497+ }
498+
499+ /* Speakers BE */
500+ if (props -> is_speakers ) {
501+ if (substream -> stream == SNDRV_PCM_STREAM_CAPTURE ) {
502+ /* Sense PCM: keep the existing BE rate (0 if not already running) */
503+ rate -> min = rate -> max = cpu_dai -> symmetric_rate ;
504+
505+ return 0 ;
506+ } else {
507+ /*
508+ * Set the sense PCM rate control to inform userspace of the
509+ * new sample rate.
510+ */
511+ ma -> speaker_sample_rate = params_rate (params );
512+ snd_ctl_notify (ma -> card .snd_card , SNDRV_CTL_EVENT_MASK_VALUE ,
513+ & ma -> speaker_sample_rate_kctl -> id );
514+ }
515+ }
516+
490517 if (bclk_ratio ) {
491518 struct snd_soc_dai * dai ;
492519 int mclk = params_rate (params ) * bclk_ratio ;
@@ -511,8 +538,14 @@ static int macaudio_fe_startup(struct snd_pcm_substream *substream)
511538 struct macaudio_link_props * props = & ma -> link_props [rtd -> dai_link -> id ];
512539 int max_rate , ret ;
513540
514- if (props -> is_sense )
541+ if (props -> is_sense ) {
542+ /*
543+ * Sense stream will not return data while playback is inactive,
544+ * so do not time out.
545+ */
546+ substream -> wait_time = MAX_SCHEDULE_TIMEOUT ;
515547 return 0 ;
548+ }
516549
517550 ret = snd_pcm_hw_constraint_minmax (substream -> runtime ,
518551 SNDRV_PCM_HW_PARAM_CHANNELS ,
@@ -569,31 +602,28 @@ static void macaudio_dpcm_shutdown(struct snd_pcm_substream *substream)
569602 }
570603}
571604
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-
587605static int macaudio_be_hw_free (struct snd_pcm_substream * substream )
588606{
589607 struct snd_soc_pcm_runtime * rtd = snd_soc_substream_to_rtd (substream );
590608 struct macaudio_snd_data * ma = snd_soc_card_get_drvdata (rtd -> card );
591609 struct macaudio_link_props * props = & ma -> link_props [rtd -> dai_link -> id ];
610+ struct snd_soc_dai * dai ;
611+ int i ;
592612
593- if (props -> is_speakers ) {
594- ma -> speakers_streaming = false;
613+ if (props -> is_speakers && substream -> stream == SNDRV_PCM_STREAM_PLAYBACK ) {
614+ /*
615+ * Clear the DAI rates, so the next open can change the sample rate.
616+ * This won't happen automatically if the sense PCM is open.
617+ */
618+ for_each_rtd_dais (rtd , i , dai ) {
619+ dai -> symmetric_rate = 0 ;
620+ }
621+
622+ /* Notify userspace that the speakers are closed */
623+ ma -> speaker_sample_rate = 0 ;
595624 snd_ctl_notify (ma -> card .snd_card , SNDRV_CTL_EVENT_MASK_VALUE ,
596- & ma -> speakers_streaming_kctl -> id );
625+ & ma -> speaker_sample_rate_kctl -> id );
626+
597627 }
598628
599629 return 0 ;
@@ -606,7 +636,6 @@ static const struct snd_soc_ops macaudio_fe_ops = {
606636};
607637
608638static const struct snd_soc_ops macaudio_be_ops = {
609- .prepare = macaudio_be_prepare ,
610639 .hw_free = macaudio_be_hw_free ,
611640 .shutdown = macaudio_dpcm_shutdown ,
612641 .hw_params = macaudio_dpcm_hw_params ,
@@ -838,7 +867,7 @@ static int macaudio_late_probe(struct snd_soc_card *card)
838867 }
839868 }
840869
841- ma -> speakers_streaming_kctl = snd_soc_card_get_kcontrol (card , "Speakers Up Indicator " );
870+ ma -> speaker_sample_rate_kctl = snd_soc_card_get_kcontrol (card , "Speaker Sample Rate " );
842871
843872 return 0 ;
844873}
@@ -1017,10 +1046,10 @@ static const struct snd_soc_dapm_widget macaudio_snd_widgets[] = {
10171046
10181047static int macaudio_sss_info (struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
10191048{
1020- uinfo -> type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
1049+ uinfo -> type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
10211050 uinfo -> count = 1 ;
10221051 uinfo -> value .integer .min = 0 ;
1023- uinfo -> value .integer .max = 1 ;
1052+ uinfo -> value .integer .max = 192000 ;
10241053
10251054 return 0 ;
10261055}
@@ -1035,7 +1064,7 @@ static int macaudio_sss_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
10351064 * assume there is some ALSA-level lock, but DAPM implementations
10361065 * of kcontrol ops do explicit locking, so look into it.
10371066 */
1038- uvalue -> value .integer .value [0 ] = ma -> speakers_streaming ;
1067+ uvalue -> value .integer .value [0 ] = ma -> speaker_sample_rate ;
10391068
10401069 return 0 ;
10411070}
@@ -1048,7 +1077,7 @@ static const struct snd_kcontrol_new macaudio_controls[] = {
10481077 .iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
10491078 .access = SNDRV_CTL_ELEM_ACCESS_READ |
10501079 SNDRV_CTL_ELEM_ACCESS_VOLATILE ,
1051- .name = "Speakers Up Indicator " ,
1080+ .name = "Speaker Sample Rate " ,
10521081 .info = macaudio_sss_info , .get = macaudio_sss_get ,
10531082 },
10541083};
0 commit comments