| From stable-bounces@linux.kernel.org Tue Feb 6 10:14:56 2007 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Tue, 06 Feb 2007 19:13:31 +0100 |
| Subject: USB audio fixes 2 |
| To: stable@kernel.org |
| Message-ID: <s5h1wl3w3w4.wl%tiwai@suse.de> |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| [PATCH] 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: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| sound/usb/usbaudio.c | 43 +++++++++++++++++++++++++------------------ |
| 1 file changed, 25 insertions(+), 18 deletions(-) |
| |
| --- linux-2.6.20.1.orig/sound/usb/usbaudio.c |
| +++ linux-2.6.20.1/sound/usb/usbaudio.c |
| @@ -186,6 +186,7 @@ struct snd_usb_substream { |
| u64 formats; /* format bitmasks (all or'ed) */ |
| unsigned int num_formats; /* number of supported audio formats (list) */ |
| struct list_head fmt_list; /* format list */ |
| + struct snd_pcm_hw_constraint_list rate_list; /* limited rates */ |
| spinlock_t lock; |
| |
| struct snd_urb_ops ops; /* callbacks (must be filled at init) */ |
| @@ -1810,28 +1811,33 @@ static int check_hw_params_convention(st |
| static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, |
| struct snd_usb_substream *subs) |
| { |
| - struct list_head *p; |
| - struct snd_pcm_hw_constraint_list constraints_rates; |
| + struct audioformat *fp; |
| + int count = 0, needs_knot = 0; |
| int err; |
| |
| - list_for_each(p, &subs->fmt_list) { |
| - struct audioformat *fp; |
| - fp = list_entry(p, struct audioformat, list); |
| - |
| - if (!fp->needs_knot) |
| - continue; |
| - |
| - constraints_rates.count = fp->nr_rates; |
| - constraints_rates.list = fp->rate_table; |
| - constraints_rates.mask = 0; |
| - |
| - err = snd_pcm_hw_constraint_list(runtime, 0, |
| - SNDRV_PCM_HW_PARAM_RATE, |
| - &constraints_rates); |
| + list_for_each_entry(fp, &subs->fmt_list, list) { |
| + if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) |
| + return 0; |
| + count += fp->nr_rates; |
| + if (fp->needs_knot) |
| + needs_knot = 1; |
| + } |
| + if (!needs_knot) |
| + return 0; |
| |
| - if (err < 0) |
| - return err; |
| + subs->rate_list.count = count; |
| + subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); |
| + subs->rate_list.mask = 0; |
| + count = 0; |
| + list_for_each_entry(fp, &subs->fmt_list, list) { |
| + int i; |
| + for (i = 0; i < fp->nr_rates; i++) |
| + subs->rate_list.list[count++] = fp->rate_table[i]; |
| } |
| + err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
| + &subs->rate_list); |
| + if (err < 0) |
| + return err; |
| |
| return 0; |
| } |
| @@ -2231,6 +2237,7 @@ static void free_substream(struct snd_us |
| kfree(fp->rate_table); |
| kfree(fp); |
| } |
| + kfree(subs->rate_list.list); |
| } |
| |
| |