@@ -789,11 +789,27 @@ static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin,
789
789
return changed ;
790
790
}
791
791
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
+
792
807
static int hw_rule_rate (struct snd_pcm_hw_params * params ,
793
808
struct snd_pcm_hw_rule * rule )
794
809
{
795
810
struct snd_usb_substream * subs = rule -> private ;
796
811
struct snd_usb_audio * chip = subs -> stream -> chip ;
812
+ const struct snd_usb_endpoint * ep ;
797
813
const struct audioformat * fp ;
798
814
struct snd_interval * it = hw_param_interval (params , SNDRV_PCM_HW_PARAM_RATE );
799
815
unsigned int rmin , rmax , r ;
@@ -805,6 +821,29 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
805
821
list_for_each_entry (fp , & subs -> fmt_list , list ) {
806
822
if (!hw_check_valid_format (subs , params , fp ))
807
823
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
+
808
847
r = snd_usb_endpoint_get_clock_rate (chip , fp -> clock );
809
848
if (r > 0 ) {
810
849
if (!snd_interval_test (it , r ))
@@ -874,6 +913,8 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
874
913
struct snd_pcm_hw_rule * rule )
875
914
{
876
915
struct snd_usb_substream * subs = rule -> private ;
916
+ struct snd_usb_audio * chip = subs -> stream -> chip ;
917
+ const struct snd_usb_endpoint * ep ;
877
918
const struct audioformat * fp ;
878
919
struct snd_mask * fmt = hw_param_mask (params , SNDRV_PCM_HW_PARAM_FORMAT );
879
920
u64 fbits ;
@@ -883,6 +924,27 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
883
924
list_for_each_entry (fp , & subs -> fmt_list , list ) {
884
925
if (!hw_check_valid_format (subs , params , fp ))
885
926
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
+
886
948
fbits |= fp -> formats ;
887
949
}
888
950
return apply_hw_params_format_bits (fmt , fbits );
@@ -915,103 +977,95 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
915
977
return apply_hw_params_minmax (it , pmin , UINT_MAX );
916
978
}
917
979
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 )
921
983
{
984
+ struct snd_usb_substream * subs = rule -> private ;
922
985
struct snd_usb_audio * chip = subs -> stream -> chip ;
923
986
const struct audioformat * fp ;
924
987
const struct snd_usb_endpoint * ep ;
988
+ struct snd_interval * it ;
989
+ unsigned int rmin , rmax ;
925
990
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 ;
926
995
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 );
937
1005
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 ;
946
1006
}
947
- }
948
- return NULL ;
949
- }
950
1007
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
+ }
993
1020
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 );
998
1024
}
999
1025
1000
1026
static int hw_rule_periods_implicit_fb (struct snd_pcm_hw_params * params ,
1001
1027
struct snd_pcm_hw_rule * rule )
1002
1028
{
1003
1029
struct snd_usb_substream * subs = rule -> private ;
1030
+ struct snd_usb_audio * chip = subs -> stream -> chip ;
1031
+ const struct audioformat * fp ;
1004
1032
const struct snd_usb_endpoint * ep ;
1005
1033
struct snd_interval * it ;
1034
+ unsigned int rmin , rmax ;
1006
1035
1007
- ep = get_sync_ep_from_substream (subs );
1008
- if (!ep )
1009
- return 0 ;
1010
-
1011
- hwc_debug ("applying %s\n" , __func__ );
1012
1036
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 );
1015
1069
}
1016
1070
1017
1071
/*
@@ -1120,16 +1174,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
1120
1174
return err ;
1121
1175
1122
1176
/* 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 ;
1133
1177
err = snd_pcm_hw_rule_add (runtime , 0 , SNDRV_PCM_HW_PARAM_PERIOD_SIZE ,
1134
1178
hw_rule_period_size_implicit_fb , subs ,
1135
1179
SNDRV_PCM_HW_PARAM_PERIOD_SIZE , -1 );
0 commit comments