diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/endpoint.c | 7 | ||||
-rw-r--r-- | sound/usb/pcm.c | 13 | ||||
-rw-r--r-- | sound/usb/quirks.c | 2 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 4 |
4 files changed, 24 insertions, 2 deletions
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 310cd6fb0038..4aaf0784940b 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1673,6 +1673,13 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending) stop_urbs(ep, false, keep_pending); if (ep->clock_ref) atomic_dec(&ep->clock_ref->locked); + + if (ep->chip->quirk_flags & QUIRK_FLAG_FORCE_IFACE_RESET && + usb_pipeout(ep->pipe)) { + ep->need_prepare = true; + if (ep->iface_ref) + ep->iface_ref->need_setup = true; + } } } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 8ed165f036a0..9557bd4d1bbc 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -604,6 +604,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = runtime->private_data; struct snd_usb_audio *chip = subs->stream->chip; + int retry = 0; int ret; ret = snd_usb_lock_shutdown(chip); @@ -614,6 +615,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } + again: if (subs->sync_endpoint) { ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); if (ret < 0) @@ -638,9 +640,16 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->lowlatency_playback = lowlatency_playback_available(runtime, subs); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - !subs->lowlatency_playback) + !subs->lowlatency_playback) { ret = start_endpoints(subs); - + /* if XRUN happens at starting streams (possibly with implicit + * fb case), restart again, but only try once. + */ + if (ret == -EPIPE && !retry++) { + sync_pending_stops(subs); + goto again; + } + } unlock: snd_usb_unlock_shutdown(chip); return ret; diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 0f4dd3503a6a..58b37bfc885c 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2044,6 +2044,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x0644, 0x804a, /* TEAC UD-301 */ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY), + DEVICE_FLG(0x0644, 0x805f, /* TEAC Model 12 */ + QUIRK_FLAG_FORCE_IFACE_RESET), DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */ QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index e97141ef730a..2aba508a4831 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -172,6 +172,9 @@ extern bool snd_usb_skip_validation; * Don't apply implicit feedback sync mode * QUIRK_FLAG_IFACE_SKIP_CLOSE * Don't closed interface during setting sample rate + * QUIRK_FLAG_FORCE_IFACE_RESET + * Force an interface reset whenever stopping & restarting a stream + * (e.g. after xrun) */ #define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0) @@ -194,5 +197,6 @@ extern bool snd_usb_skip_validation; #define QUIRK_FLAG_GENERIC_IMPLICIT_FB (1U << 17) #define QUIRK_FLAG_SKIP_IMPLICIT_FB (1U << 18) #define QUIRK_FLAG_IFACE_SKIP_CLOSE (1U << 19) +#define QUIRK_FLAG_FORCE_IFACE_RESET (1U << 20) #endif /* __USBAUDIO_H */ |