diff mbox series

[RFC,08/15] ALSA: usb: Switch to the two-stage stream creation

Message ID 20250409110731.3752332-9-cezary.rojewski@intel.com (mailing list archive)
State RFC
Headers show
Series ALSA/ASoC: USB Audio Offload | expand

Commit Message

Cezary Rojewski April 9, 2025, 11:07 a.m. UTC
Utilize newly added functions and update existing stream craetion
procedure for USB Audio-Class (AC) device from one-stage into
two-stage process. In consequence, snd_usb_create_stream() and
__snd_usb_add_audio_stream().

To complete the process, update snd_usb_create_streams() so that it
performs correct operation: parse pcms -or- create non-pcms based on
the SubClass value of the USB interface.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/usb/card.c   | 119 ++++++++++-----------------------------------
 sound/usb/stream.c |  97 +-----------------------------------
 2 files changed, 29 insertions(+), 187 deletions(-)
diff mbox series

Patch

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4af69a69b5ce..354bf76988ab 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -138,87 +138,6 @@  static void snd_usb_stream_disconnect(struct snd_usb_stream *as)
 	}
 }
 
-static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int interface)
-{
-	struct usb_device *dev = chip->dev;
-	struct usb_host_interface *alts;
-	struct usb_interface_descriptor *altsd;
-	struct usb_interface *iface = usb_ifnum_to_if(dev, interface);
-
-	if (!iface) {
-		dev_err(&dev->dev, "%u:%d : does not exist\n",
-			ctrlif, interface);
-		return -EINVAL;
-	}
-
-	alts = &iface->altsetting[0];
-	altsd = get_iface_desc(alts);
-
-	/*
-	 * Android with both accessory and audio interfaces enabled gets the
-	 * interface numbers wrong.
-	 */
-	if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) ||
-	     chip->usb_id == USB_ID(0x18d1, 0x2d05)) &&
-	    interface == 0 &&
-	    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
-	    altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) {
-		interface = 2;
-		iface = usb_ifnum_to_if(dev, interface);
-		if (!iface)
-			return -EINVAL;
-		alts = &iface->altsetting[0];
-		altsd = get_iface_desc(alts);
-	}
-
-	if (usb_interface_claimed(iface)) {
-		dev_dbg(&dev->dev, "%d:%d: skipping, already claimed\n",
-			ctrlif, interface);
-		return -EINVAL;
-	}
-
-	if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
-	     altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
-	    altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) {
-		int err = snd_usb_midi_v2_create(chip, iface, NULL,
-						 chip->usb_id);
-		if (err < 0) {
-			dev_err(&dev->dev,
-				"%u:%d: cannot create sequencer device\n",
-				ctrlif, interface);
-			return -EINVAL;
-		}
-		return usb_driver_claim_interface(&usb_audio_driver, iface,
-						  USB_AUDIO_IFACE_UNUSED);
-	}
-
-	if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
-	     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
-	    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) {
-		dev_dbg(&dev->dev,
-			"%u:%d: skipping non-supported interface %d\n",
-			ctrlif, interface, altsd->bInterfaceClass);
-		/* skip non-supported classes */
-		return -EINVAL;
-	}
-
-	if (snd_usb_get_speed(dev) == USB_SPEED_LOW) {
-		dev_err(&dev->dev, "low speed audio streaming not supported\n");
-		return -EINVAL;
-	}
-
-	snd_usb_add_ctrl_interface_link(chip, interface, ctrlif);
-
-	if (! snd_usb_parse_audio_interface(chip, interface)) {
-		usb_set_interface(dev, interface, 0); /* reset the current interface */
-		return usb_driver_claim_interface(&usb_audio_driver, iface,
-						  USB_AUDIO_IFACE_UNUSED);
-	}
-
-	return 0;
-}
-
-__maybe_unused
 static struct usb_interface *snd_usb_streaming_iface(struct snd_usb_audio *chip, int ctrlif,
 						     int interface, u8 subclass)
 {
@@ -274,7 +193,6 @@  static struct usb_interface *snd_usb_streaming_iface(struct snd_usb_audio *chip,
 	return NULL;
 }
 
-__maybe_unused
 static int snd_usb_parse_claim_pcm(struct snd_usb_audio *chip, int ctrlif,
 				   struct usb_interface *iface,
 				   struct usb_driver *iface_driver)
@@ -301,7 +219,6 @@  static int snd_usb_parse_claim_pcm(struct snd_usb_audio *chip, int ctrlif,
 	return 0;
 }
 
-__maybe_unused
 static int snd_usb_create_claim_midi(struct snd_usb_audio *chip, int ctrlif,
 				     struct usb_interface *iface,
 				     struct usb_driver *iface_driver)
@@ -325,18 +242,30 @@  static int snd_usb_create_claim_midi(struct snd_usb_audio *chip, int ctrlif,
 /*
  * parse audio control descriptor and create pcm/midi streams
  */
-static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
+static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif,
+				  struct usb_driver *iface_driver, u8 subclass)
 {
+	int (*create_stream)(struct snd_usb_audio *, int,
+			     struct usb_interface *, struct usb_driver *);
 	struct usb_device *dev = chip->dev;
 	struct usb_host_interface *host_iface;
 	struct usb_interface_descriptor *altsd;
+	struct usb_interface *iface;
 	int i, protocol;
+	int ifnum;
 
 	/* find audiocontrol interface */
 	host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
 	altsd = get_iface_desc(host_iface);
 	protocol = altsd->bInterfaceProtocol;
 
+	if (subclass == USB_SUBCLASS_AUDIOSTREAMING)
+		create_stream = snd_usb_parse_claim_pcm;
+	else if (subclass == USB_SUBCLASS_MIDISTREAMING)
+		create_stream = snd_usb_create_claim_midi;
+	else
+		return -EINVAL;
+
 	switch (protocol) {
 	default:
 		dev_warn(&dev->dev,
@@ -385,8 +314,12 @@  static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
 			return -EINVAL;
 		}
 
-		for (i = 0; i < h1->bInCollection; i++)
-			snd_usb_create_stream(chip, ctrlif, h1->baInterfaceNr[i]);
+		for (i = 0; i < h1->bInCollection; i++) {
+			ifnum = h1->baInterfaceNr[i];
+			iface = snd_usb_streaming_iface(chip, ctrlif, ifnum, subclass);
+			if (!IS_ERR_OR_NULL(iface))
+				create_stream(chip, ctrlif, iface, iface_driver);
+		}
 
 		break;
 	}
@@ -431,10 +364,12 @@  static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
 		}
 
 		for (i = 0; i < assoc->bInterfaceCount; i++) {
-			int intf = assoc->bFirstInterface + i;
-
-			if (intf != ctrlif)
-				snd_usb_create_stream(chip, ctrlif, intf);
+			ifnum = assoc->bFirstInterface + i;
+			if (ifnum == ctrlif)
+				continue;
+			iface = snd_usb_streaming_iface(chip, ctrlif, ifnum, subclass);
+			if (!IS_ERR_OR_NULL(iface))
+				create_stream(chip, ctrlif, iface, iface_driver);
 		}
 
 		break;
@@ -784,7 +719,7 @@  static int snd_usb_parse_pcms(struct snd_usb_audio *chip, struct usb_interface *
 	}
 
 	/* Parse pcm interfaces in generic fashion. */
-	ret = snd_usb_create_streams(chip, ifnum);
+	ret = snd_usb_create_streams(chip, ifnum, driver, USB_SUBCLASS_AUDIOSTREAMING);
 	if (ret < 0)
 		return ret;
 
@@ -813,7 +748,7 @@  static int snd_usb_create_nonpcms(struct snd_usb_audio *chip, struct usb_interfa
 	}
 
 	/* Create midi/mixer interfaces in generic fashion. */
-	ret = snd_usb_create_streams(chip, ifnum);
+	ret = snd_usb_create_streams(chip, ifnum, driver, USB_SUBCLASS_MIDISTREAMING);
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 1cf59e6d8ce6..601dc9ed020a 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -94,8 +94,6 @@  static void snd_usb_init_substream(struct snd_usb_stream *as,
 	subs->pkt_offset_adj = 0;
 	subs->stream_offset_adj = 0;
 
-	snd_usb_set_pcm_ops(as->pcm, stream);
-
 	list_add_tail(&fp->list, &subs->fmt_list);
 	subs->formats |= fp->formats;
 	subs->num_formats++;
@@ -110,8 +108,6 @@  static void snd_usb_init_substream(struct snd_usb_stream *as,
 		snd_usb_power_domain_set(subs->stream->chip, pd,
 					 UAC3_PD_STATE_D1);
 	}
-
-	snd_usb_preallocate_buffer(subs);
 }
 
 /* kctl callbacks for usb-audio channel maps */
@@ -468,96 +464,7 @@  snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
 	return chmap;
 }
 
-/*
- * add this endpoint to the chip instance.
- * if a stream with the same endpoint already exists, append to it.
- * if not, create a new pcm stream. note, fp is added to the substream
- * fmt_list and will be freed on the chip instance release. do not free
- * fp or do remove it from the substream fmt_list to avoid double-free.
- */
-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
-				      int stream,
-				      struct audioformat *fp,
-				      struct snd_usb_power_domain *pd)
-
-{
-	struct snd_usb_stream *as;
-	struct snd_usb_substream *subs;
-	struct snd_pcm *pcm;
-	int err;
-
-	list_for_each_entry(as, &chip->pcm_list, list) {
-		if (as->fmt_type != fp->fmt_type)
-			continue;
-		subs = &as->substream[stream];
-		if (subs->ep_num == fp->endpoint) {
-			list_add_tail(&fp->list, &subs->fmt_list);
-			subs->num_formats++;
-			subs->formats |= fp->formats;
-			return 0;
-		}
-	}
-
-	if (chip->card->registered)
-		chip->need_delayed_register = true;
-
-	/* look for an empty stream */
-	list_for_each_entry(as, &chip->pcm_list, list) {
-		if (as->fmt_type != fp->fmt_type)
-			continue;
-		subs = &as->substream[stream];
-		if (subs->ep_num)
-			continue;
-		err = snd_pcm_new_stream(as->pcm, stream, 1);
-		if (err < 0)
-			return err;
-		snd_usb_init_substream(as, stream, fp, pd);
-		return add_chmap(as->pcm, stream, subs);
-	}
-
-	/* create a new pcm */
-	as = kzalloc(sizeof(*as), GFP_KERNEL);
-	if (!as)
-		return -ENOMEM;
-	as->pcm_index = chip->pcm_devs;
-	as->chip = chip;
-	as->fmt_type = fp->fmt_type;
-	err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
-			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
-			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
-			  &pcm);
-	if (err < 0) {
-		kfree(as);
-		return err;
-	}
-	as->pcm = pcm;
-	pcm->private_data = as;
-	pcm->info_flags = 0;
-	if (chip->pcm_devs > 0)
-		sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
-	else
-		strcpy(pcm->name, "USB Audio");
-
-	snd_usb_init_substream(as, stream, fp, pd);
-
-	/*
-	 * Keep using head insertion for M-Audio Audiophile USB (tm) which has a
-	 * fix to swap capture stream order in conf/cards/USB-audio.conf
-	 */
-	if (chip->usb_id == USB_ID(0x0763, 0x2003))
-		list_add(&as->list, &chip->pcm_list);
-	else
-		list_add_tail(&as->list, &chip->pcm_list);
-
-	chip->pcm_devs++;
-
-	snd_usb_proc_pcm_format_add(as);
-
-	return add_chmap(pcm, stream, &as->substream[stream]);
-}
-
 /* Parse and build ->pcm_list but do not create PCMs yet. */
-__maybe_unused
 static int snd_usb_parse_pcm(struct snd_usb_audio *chip, int stream, struct audioformat *fp,
 			     struct snd_usb_power_domain *pd)
 {
@@ -705,7 +612,7 @@  int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
 			     int stream,
 			     struct audioformat *fp)
 {
-	return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
+	return snd_usb_parse_pcm(chip, stream, fp, NULL);
 }
 
 static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
@@ -713,7 +620,7 @@  static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
 				       struct audioformat *fp,
 				       struct snd_usb_power_domain *pd)
 {
-	return __snd_usb_add_audio_stream(chip, stream, fp, pd);
+	return snd_usb_parse_pcm(chip, stream, fp, pd);
 }
 
 static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,