@@ -789,11 +789,27 @@ static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin,
789789 return changed ;
790790}
791791
792+ /* get the specified endpoint object that is being used by other streams
793+ * (i.e. the parameter is locked)
794+ */
795+ static const struct snd_usb_endpoint *
796+ get_endpoint_in_use (struct snd_usb_audio * chip , int endpoint ,
797+ const struct snd_usb_endpoint * ref_ep )
798+ {
799+ const struct snd_usb_endpoint * ep ;
800+
801+ ep = snd_usb_get_endpoint (chip , endpoint );
802+ if (ep && ep -> cur_audiofmt && (ep != ref_ep || ep -> opened > 1 ))
803+ return ep ;
804+ return NULL ;
805+ }
806+
792807static int hw_rule_rate (struct snd_pcm_hw_params * params ,
793808 struct snd_pcm_hw_rule * rule )
794809{
795810 struct snd_usb_substream * subs = rule -> private ;
796811 struct snd_usb_audio * chip = subs -> stream -> chip ;
812+ const struct snd_usb_endpoint * ep ;
797813 const struct audioformat * fp ;
798814 struct snd_interval * it = hw_param_interval (params , SNDRV_PCM_HW_PARAM_RATE );
799815 unsigned int rmin , rmax , r ;
@@ -805,6 +821,29 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
805821 list_for_each_entry (fp , & subs -> fmt_list , list ) {
806822 if (!hw_check_valid_format (subs , params , fp ))
807823 continue ;
824+
825+ ep = get_endpoint_in_use (chip , fp -> endpoint ,
826+ subs -> data_endpoint );
827+ if (ep ) {
828+ hwc_debug ("rate limit %d for ep#%x\n" ,
829+ ep -> cur_rate , fp -> endpoint );
830+ rmin = min (rmin , ep -> cur_rate );
831+ rmax = max (rmax , ep -> cur_rate );
832+ continue ;
833+ }
834+
835+ if (fp -> implicit_fb ) {
836+ ep = get_endpoint_in_use (chip , fp -> sync_ep ,
837+ subs -> sync_endpoint );
838+ if (ep ) {
839+ hwc_debug ("rate limit %d for sync_ep#%x\n" ,
840+ ep -> cur_rate , fp -> sync_ep );
841+ rmin = min (rmin , ep -> cur_rate );
842+ rmax = max (rmax , ep -> cur_rate );
843+ continue ;
844+ }
845+ }
846+
808847 r = snd_usb_endpoint_get_clock_rate (chip , fp -> clock );
809848 if (r > 0 ) {
810849 if (!snd_interval_test (it , r ))
@@ -874,6 +913,8 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
874913 struct snd_pcm_hw_rule * rule )
875914{
876915 struct snd_usb_substream * subs = rule -> private ;
916+ struct snd_usb_audio * chip = subs -> stream -> chip ;
917+ const struct snd_usb_endpoint * ep ;
877918 const struct audioformat * fp ;
878919 struct snd_mask * fmt = hw_param_mask (params , SNDRV_PCM_HW_PARAM_FORMAT );
879920 u64 fbits ;
@@ -883,6 +924,27 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
883924 list_for_each_entry (fp , & subs -> fmt_list , list ) {
884925 if (!hw_check_valid_format (subs , params , fp ))
885926 continue ;
927+
928+ ep = get_endpoint_in_use (chip , fp -> endpoint ,
929+ subs -> data_endpoint );
930+ if (ep ) {
931+ hwc_debug ("format limit %d for ep#%x\n" ,
932+ ep -> cur_format , fp -> endpoint );
933+ fbits |= pcm_format_to_bits (ep -> cur_format );
934+ continue ;
935+ }
936+
937+ if (fp -> implicit_fb ) {
938+ ep = get_endpoint_in_use (chip , fp -> sync_ep ,
939+ subs -> sync_endpoint );
940+ if (ep ) {
941+ hwc_debug ("format limit %d for sync_ep#%x\n" ,
942+ ep -> cur_format , fp -> sync_ep );
943+ fbits |= pcm_format_to_bits (ep -> cur_format );
944+ continue ;
945+ }
946+ }
947+
886948 fbits |= fp -> formats ;
887949 }
888950 return apply_hw_params_format_bits (fmt , fbits );
@@ -915,103 +977,95 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
915977 return apply_hw_params_minmax (it , pmin , UINT_MAX );
916978}
917979
918- /* get the EP or the sync EP for implicit fb when it's already set up */
919- static const struct snd_usb_endpoint *
920- get_sync_ep_from_substream ( struct snd_usb_substream * subs )
980+ /* additional hw constraints for implicit feedback mode */
981+ static int hw_rule_period_size_implicit_fb ( struct snd_pcm_hw_params * params ,
982+ struct snd_pcm_hw_rule * rule )
921983{
984+ struct snd_usb_substream * subs = rule -> private ;
922985 struct snd_usb_audio * chip = subs -> stream -> chip ;
923986 const struct audioformat * fp ;
924987 const struct snd_usb_endpoint * ep ;
988+ struct snd_interval * it ;
989+ unsigned int rmin , rmax ;
925990
991+ it = hw_param_interval (params , SNDRV_PCM_HW_PARAM_PERIOD_SIZE );
992+ hwc_debug ("hw_rule_period_size: (%u,%u)\n" , it -> min , it -> max );
993+ rmin = UINT_MAX ;
994+ rmax = 0 ;
926995 list_for_each_entry (fp , & subs -> fmt_list , list ) {
927- ep = snd_usb_get_endpoint (chip , fp -> endpoint );
928- if (ep && ep -> cur_audiofmt ) {
929- /* if EP is already opened solely for this substream,
930- * we still allow us to change the parameter; otherwise
931- * this substream has to follow the existing parameter
932- */
933- if (ep -> cur_audiofmt != subs -> cur_audiofmt || ep -> opened > 1 )
934- return ep ;
935- }
936- if (!fp -> implicit_fb )
996+ if (!hw_check_valid_format (subs , params , fp ))
997+ continue ;
998+ ep = get_endpoint_in_use (chip , fp -> endpoint ,
999+ subs -> data_endpoint );
1000+ if (ep ) {
1001+ hwc_debug ("period size limit %d for ep#%x\n" ,
1002+ ep -> cur_period_frames , fp -> endpoint );
1003+ rmin = min (rmin , ep -> cur_period_frames );
1004+ rmax = max (rmax , ep -> cur_period_frames );
9371005 continue ;
938- /* for the implicit fb, check the sync ep as well */
939- ep = snd_usb_get_endpoint (chip , fp -> sync_ep );
940- if (ep && ep -> cur_audiofmt ) {
941- /* ditto, if the sync (data) ep is used by others,
942- * this stream is restricted by the sync ep
943- */
944- if (ep != subs -> sync_endpoint || ep -> opened > 1 )
945- return ep ;
9461006 }
947- }
948- return NULL ;
949- }
9501007
951- /* additional hw constraints for implicit feedback mode */
952- static int hw_rule_format_implicit_fb (struct snd_pcm_hw_params * params ,
953- struct snd_pcm_hw_rule * rule )
954- {
955- struct snd_usb_substream * subs = rule -> private ;
956- const struct snd_usb_endpoint * ep ;
957- struct snd_mask * fmt = hw_param_mask (params , SNDRV_PCM_HW_PARAM_FORMAT );
958-
959- ep = get_sync_ep_from_substream (subs );
960- if (!ep )
961- return 0 ;
962-
963- hwc_debug ("applying %s\n" , __func__ );
964- return apply_hw_params_format_bits (fmt , pcm_format_to_bits (ep -> cur_format ));
965- }
966-
967- static int hw_rule_rate_implicit_fb (struct snd_pcm_hw_params * params ,
968- struct snd_pcm_hw_rule * rule )
969- {
970- struct snd_usb_substream * subs = rule -> private ;
971- const struct snd_usb_endpoint * ep ;
972- struct snd_interval * it ;
973-
974- ep = get_sync_ep_from_substream (subs );
975- if (!ep )
976- return 0 ;
977-
978- hwc_debug ("applying %s\n" , __func__ );
979- it = hw_param_interval (params , SNDRV_PCM_HW_PARAM_RATE );
980- return apply_hw_params_minmax (it , ep -> cur_rate , ep -> cur_rate );
981- }
982-
983- static int hw_rule_period_size_implicit_fb (struct snd_pcm_hw_params * params ,
984- struct snd_pcm_hw_rule * rule )
985- {
986- struct snd_usb_substream * subs = rule -> private ;
987- const struct snd_usb_endpoint * ep ;
988- struct snd_interval * it ;
989-
990- ep = get_sync_ep_from_substream (subs );
991- if (!ep )
992- return 0 ;
1008+ if (fp -> implicit_fb ) {
1009+ ep = get_endpoint_in_use (chip , fp -> sync_ep ,
1010+ subs -> sync_endpoint );
1011+ if (ep ) {
1012+ hwc_debug ("period size limit %d for sync_ep#%x\n" ,
1013+ ep -> cur_period_frames , fp -> sync_ep );
1014+ rmin = min (rmin , ep -> cur_period_frames );
1015+ rmax = max (rmax , ep -> cur_period_frames );
1016+ continue ;
1017+ }
1018+ }
1019+ }
9931020
994- hwc_debug ("applying %s\n" , __func__ );
995- it = hw_param_interval (params , SNDRV_PCM_HW_PARAM_PERIOD_SIZE );
996- return apply_hw_params_minmax (it , ep -> cur_period_frames ,
997- ep -> cur_period_frames );
1021+ if (!rmax )
1022+ return 0 ; /* no limit by implicit fb */
1023+ return apply_hw_params_minmax (it , rmin , rmax );
9981024}
9991025
10001026static int hw_rule_periods_implicit_fb (struct snd_pcm_hw_params * params ,
10011027 struct snd_pcm_hw_rule * rule )
10021028{
10031029 struct snd_usb_substream * subs = rule -> private ;
1030+ struct snd_usb_audio * chip = subs -> stream -> chip ;
1031+ const struct audioformat * fp ;
10041032 const struct snd_usb_endpoint * ep ;
10051033 struct snd_interval * it ;
1034+ unsigned int rmin , rmax ;
10061035
1007- ep = get_sync_ep_from_substream (subs );
1008- if (!ep )
1009- return 0 ;
1010-
1011- hwc_debug ("applying %s\n" , __func__ );
10121036 it = hw_param_interval (params , SNDRV_PCM_HW_PARAM_PERIODS );
1013- return apply_hw_params_minmax (it , ep -> cur_buffer_periods ,
1014- ep -> cur_buffer_periods );
1037+ hwc_debug ("hw_rule_periods: (%u,%u)\n" , it -> min , it -> max );
1038+ rmin = UINT_MAX ;
1039+ rmax = 0 ;
1040+ list_for_each_entry (fp , & subs -> fmt_list , list ) {
1041+ if (!hw_check_valid_format (subs , params , fp ))
1042+ continue ;
1043+ ep = get_endpoint_in_use (chip , fp -> endpoint ,
1044+ subs -> data_endpoint );
1045+ if (ep ) {
1046+ hwc_debug ("periods limit %d for ep#%x\n" ,
1047+ ep -> cur_buffer_periods , fp -> endpoint );
1048+ rmin = min (rmin , ep -> cur_buffer_periods );
1049+ rmax = max (rmax , ep -> cur_buffer_periods );
1050+ continue ;
1051+ }
1052+
1053+ if (fp -> implicit_fb ) {
1054+ ep = get_endpoint_in_use (chip , fp -> sync_ep ,
1055+ subs -> sync_endpoint );
1056+ if (ep ) {
1057+ hwc_debug ("periods limit %d for sync_ep#%x\n" ,
1058+ ep -> cur_buffer_periods , fp -> sync_ep );
1059+ rmin = min (rmin , ep -> cur_buffer_periods );
1060+ rmax = max (rmax , ep -> cur_buffer_periods );
1061+ continue ;
1062+ }
1063+ }
1064+ }
1065+
1066+ if (!rmax )
1067+ return 0 ; /* no limit by implicit fb */
1068+ return apply_hw_params_minmax (it , rmin , rmax );
10151069}
10161070
10171071/*
@@ -1120,16 +1174,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
11201174 return err ;
11211175
11221176 /* additional hw constraints for implicit fb */
1123- err = snd_pcm_hw_rule_add (runtime , 0 , SNDRV_PCM_HW_PARAM_FORMAT ,
1124- hw_rule_format_implicit_fb , subs ,
1125- SNDRV_PCM_HW_PARAM_FORMAT , -1 );
1126- if (err < 0 )
1127- return err ;
1128- err = snd_pcm_hw_rule_add (runtime , 0 , SNDRV_PCM_HW_PARAM_RATE ,
1129- hw_rule_rate_implicit_fb , subs ,
1130- SNDRV_PCM_HW_PARAM_RATE , -1 );
1131- if (err < 0 )
1132- return err ;
11331177 err = snd_pcm_hw_rule_add (runtime , 0 , SNDRV_PCM_HW_PARAM_PERIOD_SIZE ,
11341178 hw_rule_period_size_implicit_fb , subs ,
11351179 SNDRV_PCM_HW_PARAM_PERIOD_SIZE , -1 );
0 commit comments