* [PATCH v2] ALSA: usx2y: Release the URBs when the DSP load fails
2026-10-31 16:00 ` Takashi Iwai
@ 2026-10-31 17:16 ` YuanZhe Liu
2026-10-31 18:56 ` [PATCH v3] " YuanZhe Liu
2026-10-31 19:15 ` [PATCH v4] ALSA: usx2y: Refuse a retried DSP load after a failure YuanZhe Liu
2 siblings, 0 replies; 10+ messages in thread
From: YuanZhe Liu @ 2026-10-31 17:16 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: Bin Yu, Cheng Wen, linux-sound, linux-kernel, stable
snd_usx2y_hwdep_dsp_load() sets up the asynchronous sequence URBs and
the interrupt URB when the FPGA firmware image with index 1 is loaded,
and then creates the ALSA devices. If usx2y_in04_init() or
usx2y_create_alsa_devices() fails, the URBs that were already set up
are left in place.
The core keeps the index unloaded when the callback fails, so user
space may issue the same request again. The second attempt then enters
usx2y_async_seq04_init() or usx2y_in04_init() with the URBs still
allocated and trips WARN_ON(usx2y->as04.buffer) or
WARN_ON(usx2y->in04_urb).
Release the URBs on these error paths instead. A retried request then
starts from a clean state and the assertions keep their meaning.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Co-developed-by: Bin Yu <byu@xidian.edu.cn>
Signed-off-by: Bin Yu <byu@xidian.edu.cn>
Co-developed-by: Cheng Wen <wencheng@xidian.edu.cn>
Signed-off-by: Cheng Wen <wencheng@xidian.edu.cn>
Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn>
---
v2: release the URBs on the failing paths of snd_usx2y_hwdep_dsp_load()
instead of removing the WARN_ON()s, as suggested by Takashi Iwai.
sound/usb/usx2y/usX2Yhwdep.c | 2 ++
sound/usb/usx2y/usbusx2y.c | 16 ++++++++++++++++
sound/usb/usx2y/usbusx2y.h | 1 +
3 files changed, 19 insertions(+)
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 7f153a2fcdd8..13995e81d2ae 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -201,11 +201,13 @@ static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw,
err = usx2y_in04_init(priv);
if (err) {
dev_err(&dev->dev, "usx2y_in04_init error\n");
+ usx2y_free_urbs(priv);
return err;
}
err = usx2y_create_alsa_devices(hw->card);
if (err) {
dev_err(&dev->dev, "usx2y_create_alsa_devices error %i\n", err);
+ usx2y_free_urbs(priv);
return err;
}
priv->chip_status |= USX2Y_STAT_CHIP_INIT;
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 108f9bddf9aa..8a551abe47dc 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -349,6 +349,22 @@ static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s)
s->buffer = NULL;
}
+/*
+ * Release the URBs set up by usx2y_async_seq04_init() and usx2y_in04_init().
+ * Used when a later step of the DSP loading fails.
+ */
+void usx2y_free_urbs(struct usx2ydev *usx2y)
+{
+ if (usx2y->in04_urb) {
+ usb_kill_urb(usx2y->in04_urb);
+ usb_free_urb(usx2y->in04_urb);
+ usx2y->in04_urb = NULL;
+ kfree(usx2y->in04_buf);
+ usx2y->in04_buf = NULL;
+ }
+ usx2y_unlinkseq(&usx2y->as04);
+}
+
static const struct usb_device_id snd_usx2y_usb_id_table[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index 7b6deed17d4b..e5e26ac8dc04 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -110,6 +110,7 @@ int usx2y_audio_create(struct snd_card *card);
int usx2y_async_seq04_init(struct usx2ydev *usx2y);
int usx2y_in04_init(struct usx2ydev *usx2y);
+void usx2y_free_urbs(struct usx2ydev *usx2y);
#define NAME_ALLCAPS "US-X2Y"
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3] ALSA: usx2y: Release the URBs when the DSP load fails
2026-10-31 16:00 ` Takashi Iwai
2026-10-31 17:16 ` [PATCH v2] ALSA: usx2y: Release the URBs when the DSP load fails YuanZhe Liu
@ 2026-10-31 18:56 ` YuanZhe Liu
2026-10-31 19:15 ` [PATCH v4] ALSA: usx2y: Refuse a retried DSP load after a failure YuanZhe Liu
2 siblings, 0 replies; 10+ messages in thread
From: YuanZhe Liu @ 2026-10-31 18:56 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: Bin Yu, Cheng Wen, linux-sound, linux-kernel, stable
snd_usx2y_hwdep_dsp_load() sets up the asynchronous sequence URBs and
the interrupt URB when the FPGA firmware image with index 1 is loaded,
and then creates the ALSA devices. If usx2y_in04_init() or
usx2y_create_alsa_devices() fails, the URBs that were already set up
are left in place.
The core keeps the index unloaded when the callback fails, so user
space may issue the same request again. The second attempt then enters
usx2y_async_seq04_init() or usx2y_in04_init() with the URBs still
allocated and trips WARN_ON(usx2y->as04.buffer) or
WARN_ON(usx2y->in04_urb).
Release the URBs on these error paths instead, so that a retried
request starts from a clean state and the assertions keep their
meaning.
Releasing the URBs also lets a retried request reach
usx2y_create_alsa_devices() again, on a card that keeps the MIDI and
PCM devices created by the failed attempt. For the US-428 the audio
streams would then index usx2y->subs[] past its end, so do not
initialise a partially created card a second time: mark the chip as
hung when the ALSA devices could not be created, and refuse further DSP
load requests. A failure of usx2y_in04_init() leaves the card
untouched and remains retryable.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Co-developed-by: Bin Yu <byu@xidian.edu.cn>
Signed-off-by: Bin Yu <byu@xidian.edu.cn>
Co-developed-by: Cheng Wen <wencheng@xidian.edu.cn>
Signed-off-by: Cheng Wen <wencheng@xidian.edu.cn>
Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn>
---
v3: do not initialise a partially created card a second time. A failed
usx2y_create_alsa_devices() now marks the chip as hung, so a retried
DSP load request returns -ENODEV instead of running the ALSA device
creation again.
sound/usb/usx2y/usX2Yhwdep.c | 6 ++++++
sound/usb/usx2y/usbusx2y.c | 16 ++++++++++++++++
sound/usb/usx2y/usbusx2y.h | 1 +
3 files changed, 23 insertions(+)
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 7f153a2fcdd8..366167c62575 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -179,6 +179,9 @@ static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw,
int lret, err;
char *buf;
+ if (priv->chip_status & USX2Y_STAT_CHIP_HUP)
+ return -ENODEV;
+
buf = memdup_user(dsp->image, dsp->length);
if (IS_ERR(buf))
return PTR_ERR(buf);
@@ -201,11 +204,14 @@ static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw,
err = usx2y_in04_init(priv);
if (err) {
dev_err(&dev->dev, "usx2y_in04_init error\n");
+ usx2y_free_urbs(priv);
return err;
}
err = usx2y_create_alsa_devices(hw->card);
if (err) {
dev_err(&dev->dev, "usx2y_create_alsa_devices error %i\n", err);
+ usx2y_free_urbs(priv);
+ priv->chip_status |= USX2Y_STAT_CHIP_HUP;
return err;
}
priv->chip_status |= USX2Y_STAT_CHIP_INIT;
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 108f9bddf9aa..8a551abe47dc 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -349,6 +349,22 @@ static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s)
s->buffer = NULL;
}
+/*
+ * Release the URBs set up by usx2y_async_seq04_init() and usx2y_in04_init().
+ * Used when a later step of the DSP loading fails.
+ */
+void usx2y_free_urbs(struct usx2ydev *usx2y)
+{
+ if (usx2y->in04_urb) {
+ usb_kill_urb(usx2y->in04_urb);
+ usb_free_urb(usx2y->in04_urb);
+ usx2y->in04_urb = NULL;
+ kfree(usx2y->in04_buf);
+ usx2y->in04_buf = NULL;
+ }
+ usx2y_unlinkseq(&usx2y->as04);
+}
+
static const struct usb_device_id snd_usx2y_usb_id_table[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index 7b6deed17d4b..e5e26ac8dc04 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -110,6 +110,7 @@ int usx2y_audio_create(struct snd_card *card);
int usx2y_async_seq04_init(struct usx2ydev *usx2y);
int usx2y_in04_init(struct usx2ydev *usx2y);
+void usx2y_free_urbs(struct usx2ydev *usx2y);
#define NAME_ALLCAPS "US-X2Y"
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v4] ALSA: usx2y: Refuse a retried DSP load after a failure
2026-10-31 16:00 ` Takashi Iwai
2026-10-31 17:16 ` [PATCH v2] ALSA: usx2y: Release the URBs when the DSP load fails YuanZhe Liu
2026-10-31 18:56 ` [PATCH v3] " YuanZhe Liu
@ 2026-10-31 19:15 ` YuanZhe Liu
2026-11-01 15:33 ` Takashi Iwai
2 siblings, 1 reply; 10+ messages in thread
From: YuanZhe Liu @ 2026-10-31 19:15 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: Bin Yu, Cheng Wen, linux-sound, linux-kernel, stable
snd_usx2y_hwdep_dsp_load() sets up the asynchronous sequence URBs and
the interrupt URB when the FPGA firmware image with index 1 is loaded,
and then creates the ALSA devices. If usx2y_in04_init() or
usx2y_create_alsa_devices() fails, the URBs that were already set up
are left in place.
The core keeps the index unloaded when the callback fails, so user
space may issue the same request again. The second attempt then enters
usx2y_async_seq04_init() or usx2y_in04_init() with the URBs still
allocated and trips WARN_ON(usx2y->as04.buffer) or
WARN_ON(usx2y->in04_urb).
The URBs cannot be released at this point: the card may already have
registered PCM devices that user space can still open, and the
disconnect handler accesses the URBs without holding the DSP lock.
Mark the chip as hung instead, so that a retried request is refused
with -ENODEV and the assertions keep their meaning. The URBs are
released by snd_usx2y_card_private_free() when the card is freed.
A failing usx2y_async_seq04_init() still releases its own URBs, so that
path remains retryable.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Co-developed-by: Bin Yu <byu@xidian.edu.cn>
Signed-off-by: Bin Yu <byu@xidian.edu.cn>
Co-developed-by: Cheng Wen <wencheng@xidian.edu.cn>
Signed-off-by: Cheng Wen <wencheng@xidian.edu.cn>
Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn>
---
v4: drop the release of the URBs on the error paths. The card may already
have registered PCM devices, and the disconnect handler accesses the
URBs without the DSP lock; mark the chip as hung instead and let
snd_usx2y_card_private_free() release the URBs.
sound/usb/usx2y/usX2Yhwdep.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 7f153a2fcdd8..3800c5b5887c 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -179,6 +179,9 @@ static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw,
int lret, err;
char *buf;
+ if (priv->chip_status & USX2Y_STAT_CHIP_HUP)
+ return -ENODEV;
+
buf = memdup_user(dsp->image, dsp->length);
if (IS_ERR(buf))
return PTR_ERR(buf);
@@ -201,11 +204,13 @@ static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw,
err = usx2y_in04_init(priv);
if (err) {
dev_err(&dev->dev, "usx2y_in04_init error\n");
+ priv->chip_status |= USX2Y_STAT_CHIP_HUP;
return err;
}
err = usx2y_create_alsa_devices(hw->card);
if (err) {
dev_err(&dev->dev, "usx2y_create_alsa_devices error %i\n", err);
+ priv->chip_status |= USX2Y_STAT_CHIP_HUP;
return err;
}
priv->chip_status |= USX2Y_STAT_CHIP_INIT;
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v4] ALSA: usx2y: Refuse a retried DSP load after a failure
2026-10-31 19:15 ` [PATCH v4] ALSA: usx2y: Refuse a retried DSP load after a failure YuanZhe Liu
@ 2026-11-01 15:33 ` Takashi Iwai
0 siblings, 0 replies; 10+ messages in thread
From: Takashi Iwai @ 2026-11-01 15:33 UTC (permalink / raw)
To: YuanZhe Liu
Cc: Jaroslav Kysela, Takashi Iwai, Bin Yu, Cheng Wen, linux-sound,
linux-kernel, stable
On Sat, 31 Oct 2026 20:15:57 +0100,
YuanZhe Liu wrote:
>
> snd_usx2y_hwdep_dsp_load() sets up the asynchronous sequence URBs and
> the interrupt URB when the FPGA firmware image with index 1 is loaded,
> and then creates the ALSA devices. If usx2y_in04_init() or
> usx2y_create_alsa_devices() fails, the URBs that were already set up
> are left in place.
>
> The core keeps the index unloaded when the callback fails, so user
> space may issue the same request again. The second attempt then enters
> usx2y_async_seq04_init() or usx2y_in04_init() with the URBs still
> allocated and trips WARN_ON(usx2y->as04.buffer) or
> WARN_ON(usx2y->in04_urb).
>
> The URBs cannot be released at this point: the card may already have
> registered PCM devices that user space can still open, and the
> disconnect handler accesses the URBs without holding the DSP lock.
> Mark the chip as hung instead, so that a retried request is refused
> with -ENODEV and the assertions keep their meaning. The URBs are
> released by snd_usx2y_card_private_free() when the card is freed.
>
> A failing usx2y_async_seq04_init() still releases its own URBs, so that
> path remains retryable.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Co-developed-by: Bin Yu <byu@xidian.edu.cn>
> Signed-off-by: Bin Yu <byu@xidian.edu.cn>
> Co-developed-by: Cheng Wen <wencheng@xidian.edu.cn>
> Signed-off-by: Cheng Wen <wencheng@xidian.edu.cn>
> Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn>
Applied now. Thanks.
Takashi
^ permalink raw reply [flat|nested] 10+ messages in thread