diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2009-08-25 02:15:41 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-08-25 02:52:34 -0400 |
commit | b1ddaf681e362ed453182ddee1699d7487069a16 (patch) | |
tree | 60d48ea825579d8df50836fd921668a2320adbe6 | |
parent | edd1365e90eb32625041d09de427d7b03461bc5c (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>
-rw-r--r-- | sound/core/pcm_lib.c | 39 |
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, | |||
909 | int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask) | 909 | int 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 | ||
955 | EXPORT_SYMBOL(snd_interval_list); | 932 | EXPORT_SYMBOL(snd_interval_list); |