[PATCH v2 1/4] usb: gadget: udc: Clear a pending connection when starting the UDC
From: Alexey Charkov
Date: Fri Nov 13 2026 - 07:33:33 EST
Since commit 62911bc82b03 ("usb: gadget: udc: skip pullup() if already
connected"), usb_gadget_connect_locked() returns early when
gadget->connected is set. A connection requested while the UDC is
stopped sets that flag too, without enabling the pullup. A later
gadget_bind_driver() or soft_connect "connect" then finds it set and
never enables the pullup, so the host doesn't see the gadget until it is
unbound and bound again.
This happens whenever a UDC driver reports VBUS through
usb_udc_vbus_handler() while no gadget driver is bound, e.g. when a
Type-C port controller switches the controller to the device role at
boot, seconds before userspace binds a configfs gadget.
The pullup is never enabled while the UDC is stopped, so clear
gadget->connected once it starts. The bind connects according to the
VBUS state that the core tracks anyway, and a function that deactivates
the gadget during bind still has the connection recorded for
usb_gadget_activate().
Fixes: 62911bc82b03 ("usb: gadget: udc: skip pullup() if already connected")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Alexey Charkov <alchark@xxxxxxxxxxx>
---
drivers/usb/gadget/udc/core.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index d5844384c368..577bc15f61a1 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -1236,8 +1236,16 @@ static inline int usb_gadget_udc_start_locked(struct usb_udc *udc)
}
ret = udc->gadget->ops->udc_start(udc->gadget, udc->driver);
- if (!ret)
+ if (!ret) {
udc->started = true;
+ /*
+ * The pullup is never enabled while the UDC is stopped, so any
+ * connection recorded meanwhile was only a request. Forget it,
+ * so that the next usb_gadget_connect_locked() enables the
+ * pullup rather than returning early.
+ */
+ udc->gadget->connected = false;
+ }
return ret;
}
--
2.56.0