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 Signed-off-by: Bin Yu Co-developed-by: Cheng Wen Signed-off-by: Cheng Wen 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