It seems that the firmware is broken and does not accept the UAC_EP_CS_ATTR_SAMPLE_RATE URB. There is only one rate (48000Hz) available in the descriptors for the output endpoint. Create a new quirk QUIRK_FLAG_FIXED_RATE to skip the rate setup when only one rate is available (fixed).
Unified · Split
| @@ -131,6 +131,7 @@ struct snd_usb_endpoint { · 130 unmodified lines | ||
| 131 | 131 | bool lowlatency_playback; /* low-latency playback mode */ |
| 132 | 132 | bool need_setup; /* (re-)need for hw_params? */ |
| 133 | 133 | bool need_prepare; /* (re-)need for prepare? */ |
| 134 | + bool fixed_rate; /* skip rate setup */ | |
| 134 | 135 | |
| 135 | 136 | /* for hw constraints */ |
| 136 | 137 | const struct audioformat *cur_audiofmt; |
| @@ -769,7 +769,8 @@ struct snd_usb_endpoint * · 768 unmodified lines | ||
| 769 | 769 | snd_usb_endpoint_open(struct snd_usb_audio *chip, |
| 770 | 770 | const struct audioformat *fp, |
| 771 | 771 | const struct snd_pcm_hw_params *params, |
| 772 | − bool is_sync_ep) | |
| 772 | + bool is_sync_ep, | |
| 773 | + bool fixed_rate) | |
| 773 | 774 | { |
| 774 | 775 | struct snd_usb_endpoint *ep; |
| 775 | 776 | int ep_num = is_sync_ep ? fp->sync_ep : fp->endpoint; |
| @@ -825,6 +826,7 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, · 49 unmodified lines | ||
| 825 | 826 | ep->implicit_fb_sync = fp->implicit_fb; |
| 826 | 827 | ep->need_setup = true; |
| 827 | 828 | ep->need_prepare = true; |
| 829 | + ep->fixed_rate = fixed_rate; | |
| 828 | 830 | |
| 829 | 831 | usb_audio_dbg(chip, " channels=%d, rate=%d, format=%s, period_bytes=%d, periods=%d, implicit_fb=%d\n", |
| 830 | 832 | ep->cur_channels, ep->cur_rate, |
| @@ -1413,11 +1415,13 @@ static int init_sample_rate(struct snd_usb_audio *chip, · 582 unmodified lines | ||
| 1413 | 1415 | if (clock && !clock->need_setup) |
| 1414 | 1416 | return 0; |
| 1415 | 1417 | |
| 1416 | − err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, rate); | |
| 1417 | − if (err < 0) { | |
| 1418 | − if (clock) | |
| 1419 | − clock->rate = 0; /* reset rate */ | |
| 1420 | − return err; | |
| 1418 | + if (!ep->fixed_rate) { | |
| 1419 | + err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, rate); | |
| 1420 | + if (err < 0) { | |
| 1421 | + if (clock) | |
| 1422 | + clock->rate = 0; /* reset rate */ | |
| 1423 | + return err; | |
| 1424 | + } | |
| 1421 | 1425 | } |
| 1422 | 1426 | |
| 1423 | 1427 | if (clock) |
| @@ -14,7 +14,8 @@ struct snd_usb_endpoint * · 13 unmodified lines | ||
| 14 | 14 | snd_usb_endpoint_open(struct snd_usb_audio *chip, |
| 15 | 15 | const struct audioformat *fp, |
| 16 | 16 | const struct snd_pcm_hw_params *params, |
| 17 | − bool is_sync_ep); | |
| 17 | + bool is_sync_ep, | |
| 18 | + bool fixed_rate); | |
| 18 | 19 | void snd_usb_endpoint_close(struct snd_usb_audio *chip, |
| 19 | 20 | struct snd_usb_endpoint *ep); |
| 20 | 21 | int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include "usbaudio.h" |
| 16 | 16 | #include "card.h" |
| 17 | 17 | #include "helper.h" |
| 18 | +#include "pcm.h" | |
| 18 | 19 | #include "implicit.h" |
| 19 | 20 | |
| 20 | 21 | enum { |
| @@ -455,7 +456,8 @@ const struct audioformat * · 434 unmodified lines | ||
| 455 | 456 | snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, |
| 456 | 457 | const struct audioformat *target, |
| 457 | 458 | const struct snd_pcm_hw_params *params, |
| 458 | − int stream) | |
| 459 | + int stream, | |
| 460 | + bool *fixed_rate) | |
| 459 | 461 | { |
| 460 | 462 | struct snd_usb_substream *subs; |
| 461 | 463 | const struct audioformat *fp, *sync_fmt = NULL; |
| @@ -483,6 +485,8 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, · 21 unmodified lines | ||
| 483 | 485 | } |
| 484 | 486 | } |
| 485 | 487 | |
| 488 | + if (fixed_rate) | |
| 489 | + *fixed_rate = snd_usb_pcm_has_fixed_rate(subs); | |
| 486 | 490 | return sync_fmt; |
| 487 | 491 | } |
| 488 | 492 | |
| @@ -9,6 +9,6 @@ const struct audioformat * · 8 unmodified lines | ||
| 9 | 9 | snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, |
| 10 | 10 | const struct audioformat *target, |
| 11 | 11 | const struct snd_pcm_hw_params *params, |
| 12 | − int stream); | |
| 12 | + int stream, bool *fixed_rate); | |
| 13 | 13 | |
| 14 | 14 | #endif /* __USBAUDIO_IMPLICIT_H */ |
| @@ -157,6 +157,31 @@ find_substream_format(struct snd_usb_substream *subs, · 156 unmodified lines | ||
| 157 | 157 | true, subs); |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | +bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs) | |
| 161 | +{ | |
| 162 | + const struct audioformat *fp; | |
| 163 | + struct snd_usb_audio *chip = subs->stream->chip; | |
| 164 | + int rate = -1; | |
| 165 | + | |
| 166 | + if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE)) | |
| 167 | + return false; | |
| 168 | + list_for_each_entry(fp, &subs->fmt_list, list) { | |
| 169 | + if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) | |
| 170 | + return false; | |
| 171 | + if (fp->nr_rates < 1) | |
| 172 | + continue; | |
| 173 | + if (fp->nr_rates > 1) | |
| 174 | + return false; | |
| 175 | + if (rate < 0) { | |
| 176 | + rate = fp->rate_table[0]; | |
| 177 | + continue; | |
| 178 | + } | |
| 179 | + if (rate != fp->rate_table[0]) | |
| 180 | + return false; | |
| 181 | + } | |
| 182 | + return true; | |
| 183 | +} | |
| 184 | + | |
| 160 | 185 | static int init_pitch_v1(struct snd_usb_audio *chip, int ep) |
| 161 | 186 | { |
| 162 | 187 | struct usb_device *dev = chip->dev; |
| @@ -450,12 +475,14 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, · 287 unmodified lines | ||
| 450 | 475 | struct snd_usb_audio *chip = subs->stream->chip; |
| 451 | 476 | const struct audioformat *fmt; |
| 452 | 477 | const struct audioformat *sync_fmt; |
| 478 | + bool fixed_rate, sync_fixed_rate; | |
| 453 | 479 | int ret; |
| 454 | 480 | |
| 455 | 481 | ret = snd_media_start_pipeline(subs); |
| 456 | 482 | if (ret) |
| 457 | 483 | return ret; |
| 458 | 484 | |
| 485 | + fixed_rate = snd_usb_pcm_has_fixed_rate(subs); | |
| 459 | 486 | fmt = find_substream_format(subs, hw_params); |
| 460 | 487 | if (!fmt) { |
| 461 | 488 | usb_audio_dbg(chip, |
| @@ -469,7 +496,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, · 7 unmodified lines | ||
| 469 | 496 | if (fmt->implicit_fb) { |
| 470 | 497 | sync_fmt = snd_usb_find_implicit_fb_sync_format(chip, fmt, |
| 471 | 498 | hw_params, |
| 472 | − !substream->stream); | |
| 499 | + !substream->stream, | |
| 500 | + &sync_fixed_rate); | |
| 473 | 501 | if (!sync_fmt) { |
| 474 | 502 | usb_audio_dbg(chip, |
| 475 | 503 | "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, · 6 unmodified lines | ||
| 482 | 510 | } |
| 483 | 511 | } else { |
| 484 | 512 | sync_fmt = fmt; |
| 513 | + sync_fixed_rate = fixed_rate; | |
| 485 | 514 | } |
| 486 | 515 | |
| 487 | 516 | ret = snd_usb_lock_shutdown(chip); |
| @@ -499,7 +528,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, · 11 unmodified lines | ||
| 499 | 528 | close_endpoints(chip, subs); |
| 500 | 529 | } |
| 501 | 530 | |
| 502 | − subs->data_endpoint = snd_usb_endpoint_open(chip, fmt, hw_params, false); | |
| 531 | + subs->data_endpoint = snd_usb_endpoint_open(chip, fmt, hw_params, false, fixed_rate); | |
| 503 | 532 | if (!subs->data_endpoint) { |
| 504 | 533 | ret = -EINVAL; |
| 505 | 534 | goto unlock; |
| @@ -508,7 +537,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, · 2 unmodified lines | ||
| 508 | 537 | if (fmt->sync_ep) { |
| 509 | 538 | subs->sync_endpoint = snd_usb_endpoint_open(chip, sync_fmt, |
| 510 | 539 | hw_params, |
| 511 | − fmt == sync_fmt); | |
| 540 | + fmt == sync_fmt, | |
| 541 | + sync_fixed_rate); | |
| 512 | 542 | if (!subs->sync_endpoint) { |
| 513 | 543 | ret = -EINVAL; |
| 514 | 544 | goto unlock; |
| @@ -6,6 +6,8 @@ void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); · 5 unmodified lines | ||
| 6 | 6 | int snd_usb_pcm_suspend(struct snd_usb_stream *as); |
| 7 | 7 | int snd_usb_pcm_resume(struct snd_usb_stream *as); |
| 8 | 8 | |
| 9 | +bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *as); | |
| 10 | + | |
| 9 | 11 | int snd_usb_init_pitch(struct snd_usb_audio *chip, |
| 10 | 12 | const struct audioformat *fmt); |
| 11 | 13 | void snd_usb_preallocate_buffer(struct snd_usb_substream *subs); |
| @@ -2152,6 +2152,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { · 2151 unmodified lines | ||
| 2152 | 2152 | QUIRK_FLAG_GENERIC_IMPLICIT_FB), |
| 2153 | 2153 | DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */ |
| 2154 | 2154 | QUIRK_FLAG_IFACE_SKIP_CLOSE), |
| 2155 | + DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */ | |
| 2156 | + QUIRK_FLAG_FIXED_RATE), | |
| 2155 | 2157 | |
| 2156 | 2158 | /* Vendor matches */ |
| 2157 | 2159 | VENDOR_FLG(0x045e, /* MS Lifecam */ |
| @@ -175,6 +175,9 @@ extern bool snd_usb_skip_validation; · 174 unmodified lines | ||
| 175 | 175 | * QUIRK_FLAG_FORCE_IFACE_RESET |
| 176 | 176 | * Force an interface reset whenever stopping & restarting a stream |
| 177 | 177 | * (e.g. after xrun) |
| 178 | + * QUIRK_FLAG_FIXED_RATE | |
| 179 | + * Do not set PCM rate (frequency) when only one rate is available | |
| 180 | + * for the given endpoint. | |
| 178 | 181 | */ |
| 179 | 182 | |
| 180 | 183 | #define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0) |
| @@ -198,5 +201,6 @@ extern bool snd_usb_skip_validation; · 17 unmodified lines | ||
| 198 | 201 | #define QUIRK_FLAG_SKIP_IMPLICIT_FB (1U << 18) |
| 199 | 202 | #define QUIRK_FLAG_IFACE_SKIP_CLOSE (1U << 19) |
| 200 | 203 | #define QUIRK_FLAG_FORCE_IFACE_RESET (1U << 20) |
| 204 | +#define QUIRK_FLAG_FIXED_RATE (1U << 21) | |
| 201 | 205 | |
| 202 | 206 | #endif /* __USBAUDIO_H */ |