diff mbox series

[14/41] ALSA: usb-audio: Create endpoint objects at parsing phase

Message ID 20201123085347.19667-15-tiwai@suse.de
State Accepted
Commit 54cb31901b831befb4f9347dd002dcc8ff2cc263
Headers show
Series USB audio refactoring for better implicit feedback support | expand

Commit Message

Takashi Iwai Nov. 23, 2020, 8:53 a.m. UTC
Currently snd_usb_endpoint objects are created at first when the
substream is opened and tries to assign the endpoints corresponding to
the matching audioformat.  But since basically the all endpoints have
been already parsed and the information have been obtained, we may
create the endpoint objects statically at the init phase.  It's easier
to manage for the implicit fb case, for example.

This patch changes the endpoint object management and lets the parser
to create the all endpoint objects.

This change shouldn't bring any functional changes.

Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/usb/endpoint.c | 87 ++++++++++++++++++++--------------------------------
 sound/usb/endpoint.h | 10 +++---
 sound/usb/pcm.c      | 27 ++++++++--------
 sound/usb/stream.c   | 16 ++++++++++
 4 files changed, 67 insertions(+), 73 deletions(-)

Comments

Takashi Iwai Jan. 3, 2021, 5:19 p.m. UTC | #1
On Sun, 03 Jan 2021 18:09:41 +0100,
František Kučera wrote:
> 
> Dne 23. 11. 20 v 9:53 Takashi Iwai napsal(a):
> > Currently snd_usb_endpoint objects are created at first when the
> > substream is opened and tries to assign the endpoints corresponding to
> > the matching audioformat.  But since basically the all endpoints have
> > been already parsed and the information have been obtained, we may
> > create the endpoint objects statically at the init phase.  It's easier
> > to manage for the implicit fb case, for example.
> >
> > This patch changes the endpoint object management and lets the parser
> > to create the all endpoint objects.
> >
> > This change shouldn't bring any functional changes.
> 
> The Pioneer DJ DJM-250MK2 (implemented in 73d8c9408434, 14335d8b9e1a, cdc01a1558de) stopped working.
> 
> After bisecting, it seems that it worked in 5fd255f4fe97 and stopped working in 54cb31901b83.
> 
> The arecord says: set_params:1407: Unable to install hw params
> 
> And even playback is impossible in this version. But there is no error in the log. However in later versions (e.g. eda809aef534) I found errors in kern.log:
> 
> usb 1-3: Cannot find EP 0x1 to open
> 
> usb 1-3: Cannot find EP 0x82 to open
> 
> (each repeats 20 or more times, seems to be in pcm.c in subs->data_endpoint = snd_usb_endpoint_open(chip, fmt, hw_params, false);)
> 
> Could you please check it? I am not sure whether it should be fixed in the DJM-250MK2 specific code or here.

Could you give lsusb -v output as well as /proc/asound/card*/usbmixer
and stream* files?  The proc files are at best from both older and new
kernels.


thanks,

Takashi
Takashi Iwai Jan. 5, 2021, 9:29 a.m. UTC | #2
On Sun, 03 Jan 2021 19:15:48 +0100,
František Kučera wrote:
> 
> Dne 03. 01. 21 v 18:19 Takashi Iwai napsal(a):
> > Could you give lsusb -v output as well as /proc/asound/card*/usbmixer
> > and stream* files?  The proc files are at best from both older and new
> > kernels.
> 
> Here are the files. They look same. The only difference is in the stream0, but it is probably only formatting. I also attached the kern.log from the new version.

Thanks.

It must be something specific to the devices with the fixed stream
qurik.  Could you try the patch below?


Takashi

-- 8< --
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -155,9 +155,6 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 
 	stream = (fp->endpoint & USB_DIR_IN)
 		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-	err = snd_usb_add_audio_stream(chip, stream, fp);
-	if (err < 0)
-		goto error;
 	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
 	    fp->altset_idx >= iface->num_altsetting) {
 		err = -EINVAL;
@@ -176,6 +173,11 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 		fp->datainterval = snd_usb_parse_datainterval(chip, alts);
 	if (fp->maxpacksize == 0)
 		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+
+	err = snd_usb_add_audio_stream(chip, stream, fp);
+	if (err < 0)
+		goto error;
+
 	usb_set_interface(chip->dev, fp->iface, 0);
 	snd_usb_init_pitch(chip, fp);
 	snd_usb_init_sample_rate(chip, fp, fp->rate_max);
Takashi Iwai Jan. 5, 2021, 1:20 p.m. UTC | #3
On Tue, 05 Jan 2021 10:29:24 +0100,
Takashi Iwai wrote:
> 
> On Sun, 03 Jan 2021 19:15:48 +0100,
> František Kučera wrote:
> > 
> > Dne 03. 01. 21 v 18:19 Takashi Iwai napsal(a):
> > > Could you give lsusb -v output as well as /proc/asound/card*/usbmixer
> > > and stream* files?  The proc files are at best from both older and new
> > > kernels.
> > 
> > Here are the files. They look same. The only difference is in the stream0, but it is probably only formatting. I also attached the kern.log from the new version.
> 
> Thanks.
> 
> It must be something specific to the devices with the fixed stream
> qurik.  Could you try the patch below?

Scratch that.  The call of snd_usb_add_endpoint() is needed explicitly
now at the quirk itself.

Below is the v2 patch.  Please give it a try.


thanks,

Takashi

-- 8< --
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -120,6 +120,38 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
 	return 0;
 }
 
+static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
+					   struct audioformat *fp)
+{
+	int stream, err;
+
+	stream = (fp->endpoint & USB_DIR_IN) ?
+		SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+
+	snd_usb_audioformat_set_sync_ep(chip, fp);
+
+	err = snd_usb_add_audio_stream(chip, stream, fp);
+	if (err < 0)
+		return err;
+
+	/* add endpoints */
+	err = snd_usb_add_endpoint(chip, fp->endpoint,
+				   SND_USB_ENDPOINT_TYPE_DATA);
+	if (err < 0)
+		return err;
+
+	if (fp->sync_ep) {
+		err = snd_usb_add_endpoint(chip, fp->sync_ep,
+					   fp->implicit_fb ?
+					   SND_USB_ENDPOINT_TYPE_DATA :
+					   SND_USB_ENDPOINT_TYPE_SYNC);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
 /*
  * create a stream for an endpoint/altsetting without proper descriptors
  */
@@ -131,8 +163,8 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 	struct audioformat *fp;
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
-	int stream, err;
 	unsigned *rate_table = NULL;
+	int err;
 
 	fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
 	if (!fp)
@@ -153,11 +185,6 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 		fp->rate_table = rate_table;
 	}
 
-	stream = (fp->endpoint & USB_DIR_IN)
-		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-	err = snd_usb_add_audio_stream(chip, stream, fp);
-	if (err < 0)
-		goto error;
 	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
 	    fp->altset_idx >= iface->num_altsetting) {
 		err = -EINVAL;
@@ -176,6 +203,11 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 		fp->datainterval = snd_usb_parse_datainterval(chip, alts);
 	if (fp->maxpacksize == 0)
 		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+
+	err = add_audio_stream_from_fixed_fmt(chip, fp);
+	if (err < 0)
+		goto error;
+
 	usb_set_interface(chip->dev, fp->iface, 0);
 	snd_usb_init_pitch(chip, fp);
 	snd_usb_init_sample_rate(chip, fp, fp->rate_max);
@@ -417,7 +449,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
 	struct audioformat *fp;
-	int stream, err;
+	int err;
 
 	/* both PCM and MIDI interfaces have 2 or more altsettings */
 	if (iface->num_altsetting < 2)
@@ -482,9 +514,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
 		return -ENXIO;
 	}
 
-	stream = (fp->endpoint & USB_DIR_IN)
-		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-	err = snd_usb_add_audio_stream(chip, stream, fp);
+	err = add_audio_stream_from_fixed_fmt(chip, fp);
 	if (err < 0) {
 		list_del(&fp->list); /* unlink for avoiding double-free */
 		kfree(fp);
František Kučera Jan. 5, 2021, 10:27 p.m. UTC | #4
Dne 05. 01. 21 v 14:20 Takashi Iwai napsal(a):
> The call of snd_usb_add_endpoint() is needed explicitly
> now at the quirk itself.
>
> Below is the v2 patch.  Please give it a try.

I applied your v2 patch to f6e7a024bfe5 version and tested with DJM-250MK2. It seems working (playback, recording).

The original error messages (usb 1-3: Cannot find EP 0x1 to open, usb 1-3: Cannot find EP 0x82 to open) disappeared from the log. And new one occurred (Incompatible EP setup for 0x82 - repeats many times). However DJM-250MK2 works again.

Thanks,

Franta
František Kučera Jan. 6, 2021, 7:01 p.m. UTC | #5
Dne 06. 01. 21 v 10:03 Takashi Iwai napsal(a):
> OK, then could you try the v3 patch below?

I tried v3 patch. Playback works, but recording does not - i found errors like these in the log during recording:

Jan  6 18:07:08 antracit kernel: [  619.973372] retire_capture_urb: 21 callbacks suppressed
Jan  6 18:07:13 antracit kernel: [  624.974175] retire_capture_urb: 9993 callbacks suppressed
Jan  6 18:07:18 antracit kernel: [  629.978015] retire_capture_urb: 9999 callbacks suppressed
Jan  6 18:08:04 antracit kernel: [  675.932930] retire_capture_urb: 102 callbacks suppressed
Jan  6 18:08:09 antracit kernel: [  680.936305] retire_capture_urb: 9998 callbacks suppressed
Jan  6 18:08:14 antracit kernel: [  685.940643] retire_capture_urb: 10000 callbacks suppressed
Jan  6 18:09:45 antracit kernel: [  776.168655] retire_capture_urb: 302 callbacks suppressed
Jan  6 18:09:50 antracit kernel: [  781.169504] retire_capture_urb: 9993 callbacks suppressed
Jan  6 18:09:55 antracit kernel: [  786.173337] retire_capture_urb: 9999 callbacks suppressed

(the original "Incompatible EP setup for 0x82" error was also present in the log)

The arecord command does nothing and after few seconds it fails with:

$ arecord -D hw:CARD=DJM250MK2 -f S24_3LE -c 8 -r 48000 > v3.wav
Recording WAVE 'stdin' : Signed 24 bit Little Endian in 3bytes, Rate 48000 Hz, Channels 8
arecord: pcm_read:2153: read error: Input/output error

The stream0 files from v2 and v3 differs in: Playback / Implicit Feedback Mode: Yes/No


BTW: playback or capture sometimes returns error for the first time but next attempts are successful. However I saw this behavior even in the older versions, so it is nothing v3 specific.

This is the error I got sometimes during the first run:

$ arecord -D hw:CARD=DJM250MK2 -f S24_3LE -c 8 -r 48000 > v3.wav
Recording WAVE 'stdin' : Signed 24 bit Little Endian in 3bytes, Rate 48000 Hz, Channels 8
arecord: set_params:1407: Unable to install hw params:
ACCESS:  RW_INTERLEAVED
FORMAT:  S24_3LE
SUBFORMAT:  STD
SAMPLE_BITS: 24
FRAME_BITS: 192
CHANNELS: 8
RATE: 48000
PERIOD_TIME: (455104 455105)
PERIOD_SIZE: 21845
PERIOD_BYTES: 524280
PERIODS: 2
BUFFER_TIME: (910208 910209)
BUFFER_SIZE: 43690
BUFFER_BYTES: 1048560
TICK_TIME: 0

If I execute the same command again, it works. (but not in v3).

Franta
Pioneer DJ Corporation DJM-250MK2 at usb-0000:00:12.2-3, high speed : USB Audio

Playback:
  Status: Stop
  Interface 0
    Altset 1
    Format: S24_3LE
    Channels: 8
    Endpoint: 0x01 (1 OUT) (ASYNC)
    Rates: 48000
    Data packet interval: 500 us
    Bits: 0
    Sync Endpoint: 0x82 (2 IN)
    Sync EP Interface: 0
    Sync EP Altset: 1
    Implicit Feedback Mode: No

Capture:
  Status: Stop
  Interface 0
    Altset 1
    Format: S24_3LE
    Channels: 8
    Endpoint: 0x82 (2 IN) (ASYNC)
    Rates: 48000
    Data packet interval: 500 us
    Bits: 0
    Sync Endpoint: 0x82 (2 IN)
    Sync EP Interface: 0
    Sync EP Altset: 1
    Implicit Feedback Mode: No
diff mbox series

Patch

diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 94490d706013..eb459db511f8 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -440,22 +440,19 @@  static void snd_complete_urb(struct urb *urb)
 }
 
 /*
- * Get the existing endpoint object corresponding EP, iface and alt numbers
+ * Get the existing endpoint object corresponding EP
  * Returns NULL if not present.
- * Call inside chip->mutex locking for avoiding the race.
  */
 struct snd_usb_endpoint *
-snd_usb_get_endpoint(struct snd_usb_audio *chip,
-		     int ep_num, int iface, int altsetting)
+snd_usb_get_endpoint(struct snd_usb_audio *chip, int ep_num)
 {
 	struct snd_usb_endpoint *ep;
 
 	list_for_each_entry(ep, &chip->ep_list, list) {
-		if (ep->ep_num == ep_num &&
-		    ep->iface == iface &&
-		    ep->altsetting == altsetting)
+		if (ep->ep_num == ep_num)
 			return ep;
 	}
+
 	return NULL;
 }
 
@@ -466,14 +463,13 @@  snd_usb_get_endpoint(struct snd_usb_audio *chip,
  * snd_usb_add_endpoint: Add an endpoint to an USB audio chip
  *
  * @chip: The chip
- * @alts: The USB host interface
  * @ep_num: The number of the endpoint to use
- * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE
  * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC
  *
  * If the requested endpoint has not been added to the given chip before,
- * a new instance is created. Otherwise, a pointer to the previoulsy
- * created instance is returned. In case of any error, NULL is returned.
+ * a new instance is created.
+ *
+ * Returns zero on success or a negative error code.
  *
  * New endpoints will be added to chip->ep_list and must be freed by
  * calling snd_usb_endpoint_free().
@@ -481,74 +477,59 @@  snd_usb_get_endpoint(struct snd_usb_audio *chip,
  * For SND_USB_ENDPOINT_TYPE_SYNC, the caller needs to guarantee that
  * bNumEndpoints > 1 beforehand.
  */
-struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
-					      struct usb_host_interface *alts,
-					      int ep_num, int direction, int type)
+int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type)
 {
 	struct snd_usb_endpoint *ep;
-	int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
-
-	if (WARN_ON(!alts))
-		return NULL;
+	bool is_playback;
 
-	mutex_lock(&chip->mutex);
-
-	ep = snd_usb_get_endpoint(chip, ep_num,
-				  alts->desc.bInterfaceNumber,
-				  alts->desc.bAlternateSetting);
-	if (ep) {
-		usb_audio_dbg(ep->chip, "Re-using EP %x in iface %d,%d\n",
-			      ep_num, ep->iface, ep->altsetting);
-		goto __exit_unlock;
-	}
+	ep = snd_usb_get_endpoint(chip, ep_num);
+	if (ep)
+		return 0;
 
-	usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n",
-		      is_playback ? "playback" : "capture",
+	usb_audio_dbg(chip, "Creating new %s endpoint #%x\n",
 		      ep_type_name(type),
 		      ep_num);
-
 	ep = kzalloc(sizeof(*ep), GFP_KERNEL);
 	if (!ep)
-		goto __exit_unlock;
+		return -ENOMEM;
 
 	ep->chip = chip;
 	spin_lock_init(&ep->lock);
 	ep->type = type;
 	ep->ep_num = ep_num;
-	ep->iface = alts->desc.bInterfaceNumber;
-	ep->altsetting = alts->desc.bAlternateSetting;
 	INIT_LIST_HEAD(&ep->ready_playback_urbs);
-	ep_num &= USB_ENDPOINT_NUMBER_MASK;
 
+	is_playback = ((ep_num & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+	ep_num &= USB_ENDPOINT_NUMBER_MASK;
 	if (is_playback)
 		ep->pipe = usb_sndisocpipe(chip->dev, ep_num);
 	else
 		ep->pipe = usb_rcvisocpipe(chip->dev, ep_num);
 
-	if (type == SND_USB_ENDPOINT_TYPE_SYNC) {
-		if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
-		    get_endpoint(alts, 1)->bRefresh >= 1 &&
-		    get_endpoint(alts, 1)->bRefresh <= 9)
-			ep->syncinterval = get_endpoint(alts, 1)->bRefresh;
+	list_add_tail(&ep->list, &chip->ep_list);
+	return 0;
+}
+
+/* Set up syncinterval and maxsyncsize for a sync EP */
+void snd_usb_endpoint_set_syncinterval(struct snd_usb_audio *chip,
+				       struct snd_usb_endpoint *ep,
+				       struct usb_host_interface *alts)
+{
+	struct usb_endpoint_descriptor *desc = get_endpoint(alts, 1);
+
+	if (ep->type == SND_USB_ENDPOINT_TYPE_SYNC) {
+		if (desc->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+		    desc->bRefresh >= 1 && desc->bRefresh <= 9)
+			ep->syncinterval = desc->bRefresh;
 		else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL)
 			ep->syncinterval = 1;
-		else if (get_endpoint(alts, 1)->bInterval >= 1 &&
-			 get_endpoint(alts, 1)->bInterval <= 16)
-			ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
+		else if (desc->bInterval >= 1 && desc->bInterval <= 16)
+			ep->syncinterval = desc->bInterval - 1;
 		else
 			ep->syncinterval = 3;
 
-		ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
+		ep->syncmaxsize = le16_to_cpu(desc->wMaxPacketSize);
 	}
-
-	list_add_tail(&ep->list, &chip->ep_list);
-
-	ep->is_implicit_feedback = 0;
-
-__exit_unlock:
-	mutex_unlock(&chip->mutex);
-
-	return ep;
 }
 
 /*
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 61487095a766..76b6de7de991 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -6,12 +6,9 @@ 
 #define SND_USB_ENDPOINT_TYPE_SYNC     1
 
 struct snd_usb_endpoint *snd_usb_get_endpoint(struct snd_usb_audio *chip,
-					      int ep_num, int iface,
-					      int altsetting);
+					      int ep_num);
 
-struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
-					      struct usb_host_interface *alts,
-					      int ep_num, int direction, int type);
+int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type);
 
 int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
 				snd_pcm_format_t pcm_format,
@@ -34,6 +31,9 @@  void snd_usb_endpoint_free(struct snd_usb_endpoint *ep);
 int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
 int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep);
 int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_set_syncinterval(struct snd_usb_audio *chip,
+				       struct snd_usb_endpoint *ep,
+				       struct usb_host_interface *alts);
 
 void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
 			     struct snd_usb_endpoint *sender,
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 8ae7d2fdba0d..03b1a02bcff4 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -585,11 +585,7 @@  static int set_sync_endpoint(struct snd_usb_substream *subs,
 	if (!alts)
 		return 0;
 
-	subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
-						   alts, ep, !subs->direction,
-						   fmt->implicit_fb ?
-						   SND_USB_ENDPOINT_TYPE_DATA :
-						   SND_USB_ENDPOINT_TYPE_SYNC);
+	subs->sync_endpoint = snd_usb_get_endpoint(subs->stream->chip, ep);
 	if (!subs->sync_endpoint) {
 		if (is_playback &&
 		    (fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) == USB_ENDPOINT_SYNC_NONE)
@@ -597,10 +593,14 @@  static int set_sync_endpoint(struct snd_usb_substream *subs,
 		return -EINVAL;
 	}
 
+	subs->sync_endpoint->iface = fmt->sync_iface;
+	subs->sync_endpoint->altsetting = fmt->sync_altsetting;
 	subs->sync_endpoint->is_implicit_feedback = fmt->implicit_fb;
 
 	subs->data_endpoint->sync_master = subs->sync_endpoint;
 
+	snd_usb_endpoint_set_syncinterval(subs->stream->chip, subs->sync_endpoint, alts);
+
 	if (!subs->sync_endpoint->use_count &&
 	    (subs->data_endpoint->iface != subs->sync_endpoint->iface ||
 	     subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting)) {
@@ -641,8 +641,7 @@  static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 
 	/* 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);
+		ep = snd_usb_get_endpoint(subs->stream->chip, fmt->endpoint);
 		if (ep && ep->use_count > 0)
 			goto add_data_ep;
 	}
@@ -688,12 +687,12 @@  static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
  add_data_ep:
 	subs->interface = fmt->iface;
 	subs->altset_idx = fmt->altset_idx;
-	subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
-						   alts, fmt->endpoint, subs->direction,
-						   SND_USB_ENDPOINT_TYPE_DATA);
-
+	subs->data_endpoint = snd_usb_get_endpoint(subs->stream->chip,
+						   fmt->endpoint);
 	if (!subs->data_endpoint)
 		return -EINVAL;
+	subs->data_endpoint->iface = fmt->iface;
+	subs->data_endpoint->altsetting = fmt->altsetting;
 
 	err = set_sync_endpoint(subs, fmt);
 	if (err < 0)
@@ -1294,15 +1293,13 @@  static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime,
 
 	subs->fixed_hw = 0;
 	list_for_each_entry(fp, &subs->fmt_list, list) {
-		ep = snd_usb_get_endpoint(chip, fp->endpoint, fp->iface,
-					  fp->altsetting);
+		ep = snd_usb_get_endpoint(chip, fp->endpoint);
 		if (ep && ep->cur_rate)
 			goto found;
 		if (!fp->implicit_fb)
 			continue;
 		/* for the implicit fb, check the sync ep as well */
-		ep = snd_usb_get_endpoint(chip, fp->sync_ep, fp->sync_iface,
-					  fp->sync_altsetting);
+		ep = snd_usb_get_endpoint(chip, fp->sync_ep);
 		if (ep && ep->cur_rate)
 			goto found;
 	}
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 7087ee2c8174..816fd3e5aada 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -1206,6 +1206,22 @@  static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
 			kfree(pd);
 			return err;
 		}
+
+		/* add endpoints */
+		err = snd_usb_add_endpoint(chip, fp->endpoint,
+					   SND_USB_ENDPOINT_TYPE_DATA);
+		if (err < 0)
+			return err;
+
+		if (fp->sync_ep) {
+			err = snd_usb_add_endpoint(chip, fp->sync_ep,
+						   fp->implicit_fb ?
+						   SND_USB_ENDPOINT_TYPE_DATA :
+						   SND_USB_ENDPOINT_TYPE_SYNC);
+			if (err < 0)
+				return err;
+		}
+
 		/* try to set the interface... */
 		usb_set_interface(chip->dev, iface_no, altno);
 		snd_usb_init_pitch(chip, iface_no, alts, fp);