aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2009-08-25 02:15:41 -0400
committerTakashi Iwai <tiwai@suse.de>2009-08-25 02:52:34 -0400
commitb1ddaf681e362ed453182ddee1699d7487069a16 (patch)
tree60d48ea825579d8df50836fd921668a2320adbe6 /sound/core
parentedd1365e90eb32625041d09de427d7b03461bc5c (diff)
sound: pcm_lib: fix unsorted list constraint handling
snd_interval_list() expected a sorted list but did not document this, so there are drivers that give it an unsorted list. To fix this, change the algorithm to work with any list. This fixes the "Slave PCM not usable" error with USB devices that have multiple alternate settings with sample rates in decreasing order, such as the Philips Askey VC010 WebCam. http://bugzilla.kernel.org/show_bug.cgi?id=14028 Reported-and-tested-by: Andrzej <adkadk@gmail.com> Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Cc: <stable@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/pcm_lib.c39
1 files changed, 8 insertions, 31 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 333e4dd29450..d8a7bb28cd83 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -909,47 +909,24 @@ static int snd_interval_ratden(struct snd_interval *i,
909int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask) 909int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask)
910{ 910{
911 unsigned int k; 911 unsigned int k;
912 int changed = 0; 912 struct snd_interval list_range;
913 913
914 if (!count) { 914 if (!count) {
915 i->empty = 1; 915 i->empty = 1;
916 return -EINVAL; 916 return -EINVAL;
917 } 917 }
918 snd_interval_any(&list_range);
919 list_range.min = UINT_MAX;
920 list_range.max = 0;
918 for (k = 0; k < count; k++) { 921 for (k = 0; k < count; k++) {
919 if (mask && !(mask & (1 << k))) 922 if (mask && !(mask & (1 << k)))
920 continue; 923 continue;
921 if (i->min == list[k] && !i->openmin) 924 if (!snd_interval_test(i, list[k]))
922 goto _l1;
923 if (i->min < list[k]) {
924 i->min = list[k];
925 i->openmin = 0;
926 changed = 1;
927 goto _l1;
928 }
929 }
930 i->empty = 1;
931 return -EINVAL;
932 _l1:
933 for (k = count; k-- > 0;) {
934 if (mask && !(mask & (1 << k)))
935 continue; 925 continue;
936 if (i->max == list[k] && !i->openmax) 926 list_range.min = min(list_range.min, list[k]);
937 goto _l2; 927 list_range.max = max(list_range.max, list[k]);
938 if (i->max > list[k]) {
939 i->max = list[k];
940 i->openmax = 0;
941 changed = 1;
942 goto _l2;
943 }
944 } 928 }
945 i->empty = 1; 929 return snd_interval_refine(i, &list_range);
946 return -EINVAL;
947 _l2:
948 if (snd_interval_checkempty(i)) {
949 i->empty = 1;
950 return -EINVAL;
951 }
952 return changed;
953} 930}
954 931
955EXPORT_SYMBOL(snd_interval_list); 932EXPORT_SYMBOL(snd_interval_list);