[PATCH] usb: gadget: u_audio: clean up capture endpoint on feedback failure

From: raoxu

Date: Thu Jun 11 2026 - 05:15:14 EST


From: Xu Rao <raoxu@xxxxxxxxxxxxx>

u_audio_start_capture() enables the capture OUT endpoint, queues capture
requests and marks the stream active before setting up the optional
feedback endpoint.

If feedback endpoint configuration or enablement fails, the function
returns an error while the capture endpoint remains enabled and its
requests may remain queued. The current code even leaves TODO comments
at these return paths.

Unwind the already started capture endpoint on these failures. Also set
fb_ep_enabled only after usb_ep_enable() succeeds, so the software state
matches the endpoint state.

Signed-off-by: Xu Rao <raoxu@xxxxxxxxxxxxx>
---
drivers/usb/gadget/function/u_audio.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index e53f2927b539..ca26bf9c8040 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -641,15 +641,15 @@ int u_audio_start_capture(struct g_audio *audio_dev)
ret = config_ep_by_speed(gadget, &audio_dev->func, ep_fback);
if (ret < 0) {
dev_err(dev, "config_ep_by_speed in_ep_fback failed (%d)\n", ret);
- return ret; // TODO: Clean up out_ep
+ goto err_out_ep;
}

- prm->fb_ep_enabled = true;
ret = usb_ep_enable(ep_fback);
if (ret < 0) {
dev_err(dev, "usb_ep_enable failed for in_ep_fback (%d)\n", ret);
- return ret; // TODO: Clean up out_ep
+ goto err_out_ep;
}
+ prm->fb_ep_enabled = true;
req_len = ep_fback->maxpacket;

req_fback = usb_ep_alloc_request(ep_fback, GFP_ATOMIC);
@@ -680,6 +680,12 @@ int u_audio_start_capture(struct g_audio *audio_dev)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);

return 0;
+
+err_out_ep:
+ set_active(prm, false);
+ free_ep(prm, ep);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(u_audio_start_capture);

--
2.50.1