mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
ALSA: usb-audio: Release components on probe errors
usb_audio_probe() can create USB-audio component resources before the first interface is recorded in chip->num_interfaces. If a later probe step fails, the error path drops chip->active and frees the card directly when no interfaces have been registered. Normal disconnect first releases USB-audio components in a fixed order before the card is freed. The first-interface probe error path skipped that sequence, so partially initialized PCM, endpoint, MIDI, media, or mixer resources could be left for the card private_free path without their disconnect handling having run. Move the existing normal-disconnect component release sequence into a helper and call it from the zero-interface probe error path before snd_card_free(). Keep the normal disconnect ordering unchanged: PCM streams, endpoint resources, MIDI 1.0 resources, MIDI 2.0 resources, media device cleanup, then mixer resources. Assisted-by: Codex:gpt-5.5 Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Link: https://patch.msgid.link/20260618170026.192212-1-zzzccc427@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
e096c24e7f
commit
3213bf9885
|
|
@ -905,6 +905,40 @@ static int try_to_register_card(struct snd_usb_audio *chip, int ifnum)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void usb_audio_disconnect_components(struct snd_usb_audio *chip)
|
||||
{
|
||||
struct snd_usb_stream *as;
|
||||
struct snd_usb_endpoint *ep;
|
||||
struct usb_mixer_interface *mixer;
|
||||
struct list_head *p;
|
||||
|
||||
/* 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(p, &chip->midi_list) {
|
||||
snd_usbmidi_disconnect(p);
|
||||
}
|
||||
snd_usb_midi_v2_disconnect_all(chip);
|
||||
/*
|
||||
* Nice to check quirk && quirk->shares_media_device and
|
||||
* then call the snd_media_device_delete(). Don't have
|
||||
* access to the quirk here. snd_media_device_delete()
|
||||
* accesses mixer_list
|
||||
*/
|
||||
snd_media_device_delete(chip);
|
||||
|
||||
/* release mixer resources */
|
||||
list_for_each_entry(mixer, &chip->mixer_list, list) {
|
||||
snd_usb_mixer_disconnect(mixer);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* probe the active usb device
|
||||
*
|
||||
|
|
@ -1077,8 +1111,10 @@ static int usb_audio_probe(struct usb_interface *intf,
|
|||
* decrement before memory is possibly returned.
|
||||
*/
|
||||
atomic_dec(&chip->active);
|
||||
if (!chip->num_interfaces)
|
||||
if (!chip->num_interfaces) {
|
||||
usb_audio_disconnect_components(chip);
|
||||
snd_card_free(chip->card);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1091,48 +1127,18 @@ static bool __usb_audio_disconnect(struct usb_interface *intf,
|
|||
struct snd_usb_audio *chip,
|
||||
struct snd_card *card)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
guard(mutex)(®ister_mutex);
|
||||
|
||||
if (platform_ops && platform_ops->disconnect_cb)
|
||||
platform_ops->disconnect_cb(chip);
|
||||
|
||||
if (atomic_inc_return(&chip->shutdown) == 1) {
|
||||
struct snd_usb_stream *as;
|
||||
struct snd_usb_endpoint *ep;
|
||||
struct usb_mixer_interface *mixer;
|
||||
|
||||
/* wait until all pending tasks done;
|
||||
* they are protected by snd_usb_lock_shutdown()
|
||||
*/
|
||||
snd_refcount_sync(&chip->usage_count);
|
||||
snd_card_disconnect(card);
|
||||
/* 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(p, &chip->midi_list) {
|
||||
snd_usbmidi_disconnect(p);
|
||||
}
|
||||
snd_usb_midi_v2_disconnect_all(chip);
|
||||
/*
|
||||
* Nice to check quirk && quirk->shares_media_device and
|
||||
* then call the snd_media_device_delete(). Don't have
|
||||
* access to the quirk here. snd_media_device_delete()
|
||||
* accesses mixer_list
|
||||
*/
|
||||
snd_media_device_delete(chip);
|
||||
|
||||
/* release mixer resources */
|
||||
list_for_each_entry(mixer, &chip->mixer_list, list) {
|
||||
snd_usb_mixer_disconnect(mixer);
|
||||
}
|
||||
usb_audio_disconnect_components(chip);
|
||||
}
|
||||
|
||||
if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user