summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2020-11-23 09:53:19 +0100
committerTakashi Iwai <tiwai@suse.de>2020-11-23 15:13:15 +0100
commit5fd255f4fe9707b5274e60d94d4aa64536f67ec3 (patch)
tree0439d9d9b23cd8d3aef4ccb6db5187b4b1b9e208 /sound
parent7ec827b9465c427511f05bab02dddbcfdd4ecc53 (diff)
ALSA: usb-audio: Avoid doubly initialization for implicit fb
The implicit feedback mode initializes both the main data stream and the sync data stream. When a sync stream was already opened, this would result in the doubly initialization and might screw up things. Add the check of already opened sync streams and skip the unnecessary initialization. Tested-by: Keith Milner <kamilner@superlative.org> Tested-by: Dylan Robinson <dylan_robinson@motu.com> Link: https://lore.kernel.org/r/20201123085347.19667-14-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/pcm.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index d83a6a6ac023..8ae7d2fdba0d 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -601,8 +601,9 @@ static int set_sync_endpoint(struct snd_usb_substream *subs,
subs->data_endpoint->sync_master = subs->sync_endpoint;
- if (subs->data_endpoint->iface != subs->sync_endpoint->iface ||
- subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting) {
+ if (!subs->sync_endpoint->use_count &&
+ (subs->data_endpoint->iface != subs->sync_endpoint->iface ||
+ subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting)) {
err = usb_set_interface(subs->dev,
subs->sync_endpoint->iface,
subs->sync_endpoint->altsetting);
@@ -625,6 +626,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
struct usb_device *dev = subs->dev;
struct usb_host_interface *alts;
struct usb_interface *iface;
+ struct snd_usb_endpoint *ep;
int err;
iface = usb_ifnum_to_if(dev, fmt->iface);
@@ -637,6 +639,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt)
return 0;
+ /* shared EP with implicit fb */
+ if (fmt->implicit_fb && !subs->need_setup_fmt) {
+ ep = snd_usb_get_endpoint(subs->stream->chip, fmt->endpoint,
+ fmt->iface, fmt->altsetting);
+ if (ep && ep->use_count > 0)
+ goto add_data_ep;
+ }
+
/* close the old interface */
if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) {
if (!subs->stream->chip->keep_iface) {
@@ -673,6 +683,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
snd_usb_set_interface_quirk(dev);
}
+ subs->need_setup_ep = true;
+
+ add_data_ep:
subs->interface = fmt->iface;
subs->altset_idx = fmt->altset_idx;
subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
@@ -686,9 +699,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (err < 0)
return err;
- err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt);
- if (err < 0)
- return err;
+ if (subs->need_setup_ep) {
+ err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt);
+ if (err < 0)
+ return err;
+ }
subs->cur_audiofmt = fmt;
@@ -940,10 +955,6 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
goto unlock;
- subs->interface = fmt->iface;
- subs->altset_idx = fmt->altset_idx;
- subs->need_setup_ep = true;
-
unlock:
snd_usb_unlock_shutdown(subs->stream->chip);
if (ret < 0)