aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/usbaudio.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-02-01 05:50:56 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:03:29 -0500
commit8fec560d9beb3957bf45ac93b1c0c616abd77a07 (patch)
tree595d5d391dad07e89792969365f5953bc5e71629 /sound/usb/usbaudio.c
parent3b6baa5a0b0a2877c18a76fa1f508cacdbc08edf (diff)
[ALSA] usbaudio - Fix Oops with unconventional sample rates
The patch fixes the memory corruption by the support of unconventional sample rates. Also, it avoids the too restrictive constraints if any of usb descriptions contain continuous rates. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/usb/usbaudio.c')
-rw-r--r--sound/usb/usbaudio.c45
1 files changed, 26 insertions, 19 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 56e42b88addf..8fd37596e3a1 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -186,6 +186,7 @@ struct snd_usb_substream {
186 u64 formats; /* format bitmasks (all or'ed) */ 186 u64 formats; /* format bitmasks (all or'ed) */
187 unsigned int num_formats; /* number of supported audio formats (list) */ 187 unsigned int num_formats; /* number of supported audio formats (list) */
188 struct list_head fmt_list; /* format list */ 188 struct list_head fmt_list; /* format list */
189 struct snd_pcm_hw_constraint_list rate_list; /* limited rates */
189 spinlock_t lock; 190 spinlock_t lock;
190 191
191 struct snd_urb_ops ops; /* callbacks (must be filled at init) */ 192 struct snd_urb_ops ops; /* callbacks (must be filled at init) */
@@ -1818,28 +1819,33 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
1818static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, 1819static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
1819 struct snd_usb_substream *subs) 1820 struct snd_usb_substream *subs)
1820{ 1821{
1821 struct list_head *p; 1822 struct audioformat *fp;
1822 struct snd_pcm_hw_constraint_list constraints_rates; 1823 int count = 0, needs_knot = 0;
1823 int err; 1824 int err;
1824 1825
1825 list_for_each(p, &subs->fmt_list) { 1826 list_for_each_entry(fp, &subs->fmt_list, list) {
1826 struct audioformat *fp; 1827 if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
1827 fp = list_entry(p, struct audioformat, list); 1828 return 0;
1828 1829 count += fp->nr_rates;
1829 if (!fp->needs_knot) 1830 if (fp->needs_knot)
1830 continue; 1831 needs_knot = 1;
1831
1832 constraints_rates.count = fp->nr_rates;
1833 constraints_rates.list = fp->rate_table;
1834 constraints_rates.mask = 0;
1835
1836 err = snd_pcm_hw_constraint_list(runtime, 0,
1837 SNDRV_PCM_HW_PARAM_RATE,
1838 &constraints_rates);
1839
1840 if (err < 0)
1841 return err;
1842 } 1832 }
1833 if (!needs_knot)
1834 return 0;
1835
1836 subs->rate_list.count = count;
1837 subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
1838 subs->rate_list.mask = 0;
1839 count = 0;
1840 list_for_each_entry(fp, &subs->fmt_list, list) {
1841 int i;
1842 for (i = 0; i < fp->nr_rates; i++)
1843 subs->rate_list.list[count++] = fp->rate_table[i];
1844 }
1845 err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
1846 &subs->rate_list);
1847 if (err < 0)
1848 return err;
1843 1849
1844 return 0; 1850 return 0;
1845} 1851}
@@ -2238,6 +2244,7 @@ static void free_substream(struct snd_usb_substream *subs)
2238 kfree(fp->rate_table); 2244 kfree(fp->rate_table);
2239 kfree(fp); 2245 kfree(fp);
2240 } 2246 }
2247 kfree(subs->rate_list.list);
2241} 2248}
2242 2249
2243 2250