diff options
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r-- | sound/usb/pcm.c | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 9557bd4d1bbc..99a66d0ef5b2 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -157,6 +157,31 @@ find_substream_format(struct snd_usb_substream *subs, true, subs); } +bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs) +{ + const struct audioformat *fp; + struct snd_usb_audio *chip = subs->stream->chip; + int rate = -1; + + if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE)) + return false; + list_for_each_entry(fp, &subs->fmt_list, list) { + if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) + return false; + if (fp->nr_rates < 1) + continue; + if (fp->nr_rates > 1) + return false; + if (rate < 0) { + rate = fp->rate_table[0]; + continue; + } + if (rate != fp->rate_table[0]) + return false; + } + return true; +} + static int init_pitch_v1(struct snd_usb_audio *chip, int ep) { struct usb_device *dev = chip->dev; @@ -450,12 +475,14 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, struct snd_usb_audio *chip = subs->stream->chip; const struct audioformat *fmt; const struct audioformat *sync_fmt; + bool fixed_rate, sync_fixed_rate; int ret; ret = snd_media_start_pipeline(subs); if (ret) return ret; + fixed_rate = snd_usb_pcm_has_fixed_rate(subs); fmt = find_substream_format(subs, hw_params); if (!fmt) { usb_audio_dbg(chip, @@ -469,7 +496,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, if (fmt->implicit_fb) { sync_fmt = snd_usb_find_implicit_fb_sync_format(chip, fmt, hw_params, - !substream->stream); + !substream->stream, + &sync_fixed_rate); if (!sync_fmt) { usb_audio_dbg(chip, "cannot find sync format: ep=0x%x, iface=%d:%d, format=%s, rate=%d, channels=%d\n", @@ -482,6 +510,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, } } else { sync_fmt = fmt; + sync_fixed_rate = fixed_rate; } ret = snd_usb_lock_shutdown(chip); @@ -499,7 +528,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, close_endpoints(chip, subs); } - subs->data_endpoint = snd_usb_endpoint_open(chip, fmt, hw_params, false); + subs->data_endpoint = snd_usb_endpoint_open(chip, fmt, hw_params, false, fixed_rate); if (!subs->data_endpoint) { ret = -EINVAL; goto unlock; @@ -508,7 +537,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, if (fmt->sync_ep) { subs->sync_endpoint = snd_usb_endpoint_open(chip, sync_fmt, hw_params, - fmt == sync_fmt); + fmt == sync_fmt, + sync_fixed_rate); if (!subs->sync_endpoint) { ret = -EINVAL; goto unlock; |