From: Cezary Rojewski <cezary.rojewski@intel.com>
To: broonie@kernel.org, tiwai@suse.com, perex@perex.cz
Cc: amadeuszx.slawinski@linux.intel.com, linux-sound@vger.kernel.org,
gregkh@linuxfoundation.org, quic_wcheng@quicinc.com,
mathias.nyman@linux.intel.com,
Cezary Rojewski <cezary.rojewski@intel.com>
Subject: [RFC 11/15] ALSA: usb: Export usb_interface driver operations
Date: Wed, 9 Apr 2025 13:07:26 +0200 [thread overview]
Message-ID: <20250409110731.3752332-12-cezary.rojewski@intel.com> (raw)
In-Reply-To: <20250409110731.3752332-1-cezary.rojewski@intel.com>
Existing usb_driver operations can be reused by component-drivers on the
ASoC side.
ASoC embraces modular approach and it is entirely acceptable for
component to be unbound while the USB device is still plugged in. In
such case, PCM list built when scanning USB interfaces can be kept
intact to avoid scanning the device a second time when the component is
probed again. Add snd_usb_release_resources() to cover that scenario.
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
include/sound/usb.h | 8 +++++
sound/usb/card.c | 88 +++++++++++++++++++++++++++++++++++++++------
2 files changed, 85 insertions(+), 11 deletions(-)
diff --git a/include/sound/usb.h b/include/sound/usb.h
index daba868fb6e0..fbcfa2b985f7 100644
--- a/include/sound/usb.h
+++ b/include/sound/usb.h
@@ -90,11 +90,19 @@ struct snd_usb_audio {
struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES];
};
+void snd_usb_release_resources(struct snd_usb_audio *chip);
int snd_usb_bind_card(struct snd_usb_audio *chip, struct snd_card *card,
struct usb_driver *driver);
int snd_usb_bind_pcm(struct list_head *stream_entry, struct snd_pcm *pcm);
void snd_usb_pcm_hw_init(struct list_head *stream_entry, int dir, struct snd_pcm_hardware *hw);
+/* USB interface operations, see struct usb_driver. */
+int snd_usb_probe(struct usb_interface *iface, const struct usb_device_id *usb_id,
+ struct usb_driver *driver);
+void snd_usb_disconnect(struct usb_interface *iface);
+int snd_usb_suspend(struct usb_interface *intf, pm_message_t message);
+int snd_usb_resume(struct usb_interface *intf);
+
/* PCM operations, see struct snd_pcm_ops. */
int snd_usb_pcm_open(struct snd_pcm_substream *substream);
int snd_usb_pcm_close(struct snd_pcm_substream *substream);
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 354bf76988ab..a4bd8ba6a26c 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -773,7 +773,8 @@ static void snd_usb_chip_free(struct snd_usb_audio *chip)
}
/* Must be called under register_mutex due to usb_chip[] manipulation. */
-static void snd_usb_chip_release(struct snd_usb_audio *chip, struct usb_interface *iface)
+static void snd_usb_chip_release(struct snd_usb_audio *chip, struct usb_interface *iface,
+ bool free_card)
{
chip->num_interfaces--;
chip->intf[chip->num_interfaces] = NULL;
@@ -781,7 +782,7 @@ static void snd_usb_chip_release(struct snd_usb_audio *chip, struct usb_interfac
if (!chip->num_interfaces) {
usb_chip[chip->index] = NULL;
- if (chip->card)
+ if (free_card && chip->card)
snd_card_free(chip->card);
snd_usb_chip_free(chip);
}
@@ -1018,10 +1019,18 @@ static int snd_usb_probe_unlocked(struct usb_interface *iface, const struct usb_
goto err;
return 0;
err:
- snd_usb_chip_release(chip, iface);
+ snd_usb_chip_release(chip, iface, false);
return ret;
}
+int snd_usb_probe(struct usb_interface *iface, const struct usb_device_id *usb_id,
+ struct usb_driver *driver)
+{
+ guard(mutex)(®ister_mutex);
+ return snd_usb_probe_unlocked(iface, usb_id, driver);
+}
+EXPORT_SYMBOL_GPL(snd_usb_probe);
+
int snd_usb_bind_card(struct snd_usb_audio *chip, struct snd_card *card,
struct usb_driver *driver)
{
@@ -1140,15 +1149,59 @@ static int usb_audio_probe(struct usb_interface *iface, const struct usb_device_
err_no_register:
atomic_dec(&chip->active);
- snd_usb_chip_release(chip, iface);
+ snd_usb_chip_release(chip, iface, true);
return ret;
}
+/**
+ * snd_usb_release_resources - Release resources occupied by USB AC device
+ *
+ * @chip: Driver context for the USB AC device
+ *
+ * Note: PCMs and endpoints created when scanning USB interface descriptors
+ * are not freed here. That information is static and can be used to re-create
+ * PCMs without the need to scan the interfaces again.
+ *
+ * Compared to usb_disconnect(), this does free midi2.0 resources.
+ */
+void snd_usb_release_resources(struct snd_usb_audio *chip)
+{
+ struct usb_mixer_interface *mixer;
+ struct list_head *midi_entry;
+ struct snd_usb_endpoint *ep;
+ struct snd_usb_stream *as;
+
+ /* release the pcm resources */
+ list_for_each_entry(as, &chip->pcm_list, list)
+ snd_usb_stream_disconnect(as);
+
+ /* release the endpoint resources */
+ list_for_each_entry(ep, &chip->ep_list, list)
+ snd_usb_endpoint_release(ep);
+
+ /* release the midi resources */
+ list_for_each(midi_entry, &chip->midi_list)
+ snd_usbmidi_disconnect(midi_entry);
+
+ snd_usb_midi_v2_disconnect_all(chip);
+ snd_usb_midi_v2_free_all(chip);
+ /*
+ * snd_media_device_delete() accesses mixer_list, do it
+ * before releasing mixers.
+ */
+ snd_media_device_delete(chip);
+
+ /* release mixer resources */
+ list_for_each_entry(mixer, &chip->mixer_list, list)
+ snd_usb_mixer_disconnect(mixer);
+}
+EXPORT_SYMBOL_GPL(snd_usb_release_resources);
+
/*
* we need to take care of counter, since disconnection can be called also
* many times as well as usb_audio_probe().
*/
-static void usb_audio_disconnect(struct usb_interface *intf)
+static void usb_disconnect(struct usb_interface *intf, bool free_card)
{
struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct snd_card *card;
@@ -1196,10 +1249,21 @@ static void usb_audio_disconnect(struct usb_interface *intf)
if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
usb_enable_autosuspend(interface_to_usbdev(intf));
- snd_usb_chip_release(chip, intf);
+ snd_usb_chip_release(chip, intf, free_card);
mutex_unlock(®ister_mutex);
}
+static void usb_audio_disconnect(struct usb_interface *iface)
+{
+ usb_disconnect(iface, true);
+}
+
+void snd_usb_disconnect(struct usb_interface *iface)
+{
+ usb_disconnect(iface, false);
+}
+EXPORT_SYMBOL_GPL(snd_usb_disconnect);
+
/* lock the shutdown (disconnect) task and autoresume */
int snd_usb_lock_shutdown(struct snd_usb_audio *chip)
{
@@ -1264,7 +1328,7 @@ void snd_usb_autosuspend(struct snd_usb_audio *chip)
usb_autopm_put_interface(chip->intf[i]);
}
-static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
+int snd_usb_suspend(struct usb_interface *intf, pm_message_t message)
{
struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct snd_usb_stream *as;
@@ -1294,8 +1358,9 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_usb_suspend);
-static int usb_audio_resume(struct usb_interface *intf)
+int snd_usb_resume(struct usb_interface *intf)
{
struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct snd_usb_stream *as;
@@ -1343,6 +1408,7 @@ static int usb_audio_resume(struct usb_interface *intf)
atomic_dec(&chip->active); /* allow autopm after this point */
return err;
}
+EXPORT_SYMBOL_GPL(snd_usb_resume);
static const struct usb_device_id usb_audio_ids [] = {
#include "quirks-table.h"
@@ -1361,9 +1427,9 @@ static struct usb_driver usb_audio_driver = {
.name = "snd-usb-audio",
.probe = usb_audio_probe,
.disconnect = usb_audio_disconnect,
- .suspend = usb_audio_suspend,
- .resume = usb_audio_resume,
- .reset_resume = usb_audio_resume,
+ .suspend = snd_usb_suspend,
+ .resume = snd_usb_resume,
+ .reset_resume = snd_usb_resume,
.id_table = usb_audio_ids,
.supports_autosuspend = 1,
};
--
2.25.1
next prev parent reply other threads:[~2025-04-09 10:51 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-09 11:07 [RFC 00/15] ALSA/ASoC: USB Audio Offload Cezary Rojewski
2025-04-09 11:07 ` [RFC 01/15] ALSA: usb: Move media-filters to the media code Cezary Rojewski
2025-04-09 11:07 ` [RFC 02/15] ALSA: usb: Drop private_free() usage for card and pcms Cezary Rojewski
2025-04-09 11:07 ` [RFC 03/15] ALSA: usb: Relocate the usbaudio header file Cezary Rojewski
2025-04-09 11:07 ` [RFC 04/15] ALSA: usb: Implement two-stage quirk applying mechanism Cezary Rojewski
2025-04-09 11:07 ` [RFC 05/15] ALSA: usb: Implement two-stage stream creation mechanism Cezary Rojewski
2025-04-09 11:07 ` [RFC 06/15] ALSA: usb: Implement two-stage chip probing mechanism Cezary Rojewski
2025-04-09 11:07 ` [RFC 07/15] ALSA: usb: Switch to the two-stage chip probing Cezary Rojewski
2025-04-09 11:07 ` [RFC 08/15] ALSA: usb: Switch to the two-stage stream creation Cezary Rojewski
2025-04-09 11:07 ` [RFC 09/15] ALSA: usb: Switch to the two-stage quirk applying Cezary Rojewski
2025-04-09 11:07 ` [RFC 10/15] ALSA: usb: Export PCM operations Cezary Rojewski
2025-04-09 11:07 ` Cezary Rojewski [this message]
2025-04-09 11:07 ` [RFC 12/15] ALSA: usb: Export card-naming procedure Cezary Rojewski
2025-04-09 11:07 ` [RFC 13/15] ALSA: usb: Add getters to obtain endpoint information Cezary Rojewski
2025-04-09 11:07 ` [RFC 14/15] ASoC: codecs: Add USB-Audio driver Cezary Rojewski
2025-04-09 11:07 ` [RFC 15/15] ASoC: Intel: avs: Add USB machine board Cezary Rojewski
2025-04-09 12:10 ` [RFC 00/15] ALSA/ASoC: USB Audio Offload Greg KH
2025-04-09 13:06 ` Cezary Rojewski
2025-04-10 10:10 ` Takashi Iwai
2025-04-10 10:24 ` Takashi Iwai
2025-04-11 9:39 ` Cezary Rojewski
2025-04-15 16:15 ` Takashi Iwai
2025-04-17 10:15 ` Cezary Rojewski
2025-04-22 11:28 ` Pierre-Louis Bossart
2025-04-22 14:15 ` Cezary Rojewski
2025-04-25 16:53 ` Pierre-Louis Bossart
2025-04-11 14:04 ` Greg KH
2025-04-11 16:51 ` Cezary Rojewski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250409110731.3752332-12-cezary.rojewski@intel.com \
--to=cezary.rojewski@intel.com \
--cc=amadeuszx.slawinski@linux.intel.com \
--cc=broonie@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-sound@vger.kernel.org \
--cc=mathias.nyman@linux.intel.com \
--cc=perex@perex.cz \
--cc=quic_wcheng@quicinc.com \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox