A little bit improved version ....
But definitely someone with more knowledge and experience can advice on
this matter.
Index: dev/usb/xhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/xhci.c,v
diff -u -p -r1.136 xhci.c
--- dev/usb/xhci.c 1 Mar 2025 14:43:03 -0000 1.136
+++ dev/usb/xhci.c 26 Nov 2025 09:56:52 -0000
@@ -54,6 +54,72 @@ int xhcidebug = 3;
#define TRBOFF(r, trb) ((char *)(trb) - (char *)((r)->trbs))
#define DEQPTR(r) ((r).dma.paddr + (sizeof(struct xhci_trb) *
(r).index))
+#define XHCI_PORT_DEBOUNCE_MS 300
+
+void
+xhci_rh_task(void *arg)
+{
+ struct xhci_softc *sc = arg;
+ struct usbd_xfer *xfer = sc->sc_intrxfer;
+ uint8_t *p;
+ int i, s;
+ uint32_t portsc;
+ int delay_needed = 0;
+
+ if (xfer == NULL)
+ return;
+
+ /* * Scan ALL ports for new connections.
+ * If we find any port with a Connect Status Change (CSC)
+ * that is currently Connected (CCS), we need to debounce.
+ */
+ for (i = 1; i <= sc->sc_noport; i++) {
+ portsc = XOREAD4(sc, XHCI_PORTSC(i));
+
+ if ((portsc & XHCI_PS_CSC) && (portsc & XHCI_PS_CCS)) {
+ delay_needed = 1;
+ /* One event is enough to trigger the global wait */
+ break;
+ }
+ }
+
+ if (delay_needed) {
+#ifdef XHCI_DEBUG
+ printf("%s: New connection detected - debouncing for %dms\n",
+ DEVNAME(sc), XHCI_PORT_DEBOUNCE_MS);
+#endif
+ usb_delay_ms(&sc->sc_bus, XHCI_PORT_DEBOUNCE_MS);
+ }
+
+ s = splusb();
+ p = KERNADDR(&xfer->dmabuf, 0);
+ memset(p, 0, xfer->length);
+
+ int has_events = 0;
+ for (i = 1; i <= sc->sc_noport; i++) {
+ portsc = XOREAD4(sc, XHCI_PORTSC(i));
+
+ /* Check for any status change bits */
+ if (portsc & (XHCI_PS_CSC | XHCI_PS_PEC | XHCI_PS_OCC |
+ XHCI_PS_WRC | XHCI_PS_PRC | XHCI_PS_PLC | XHCI_PS_CEC))
{
+
+ /* Mark the bit in the bitmap */
+ p[i/8] |= 1 << (i%8);
+ has_events = 1;
+
+ DPRINTF(("%s: port %d status change: 0x%08x\n",
+ DEVNAME(sc), i, portsc));
+ }
+ }
+
+ if (has_events) {
+ xfer->actlen = xfer->length;
+ xfer->status = USBD_NORMAL_COMPLETION;
+ usb_transfer_complete(xfer);
+ }
+ splx(s);
+}
+
struct pool *xhcixfer;
struct xhci_pipe {
@@ -295,6 +361,9 @@ xhci_init(struct xhci_softc *sc)
uint32_t hcr;
int npage, error;
+ /* Initialize the generic Root Hub task */
+ usb_init_task(&sc->sc_rh_task, xhci_rh_task, sc,
USB_TASK_TYPE_GENERIC);
+
sc->sc_bus.usbrev = USBREV_3_0;
sc->sc_bus.methods = &xhci_bus_methods;
sc->sc_bus.pipe_size = sizeof(struct xhci_pipe);
@@ -1180,8 +1249,6 @@ void
xhci_event_port_change(struct xhci_softc *sc, uint64_t paddr, uint32_t
status)
{
struct usbd_xfer *xfer = sc->sc_intrxfer;
- uint32_t port = XHCI_TRB_PORTID(paddr);
- uint8_t *p;
if (XHCI_TRB_GET_CODE(status) != XHCI_CODE_SUCCESS) {
DPRINTF(("%s: failed port status event\n", DEVNAME(sc)));
@@ -1191,16 +1258,7 @@ xhci_event_port_change(struct xhci_softc
if (xfer == NULL)
return;
- p = KERNADDR(&xfer->dmabuf, 0);
- memset(p, 0, xfer->length);
-
- p[port/8] |= 1 << (port%8);
- DPRINTF(("%s: port=%d change=0x%02x\n", DEVNAME(sc), port, *p));
-
- xfer->actlen = xfer->length;
- xfer->status = USBD_NORMAL_COMPLETION;
-
- usb_transfer_complete(xfer);
+ usb_add_task(xfer->device, &sc->sc_rh_task);
}
void
Index: dev/usb/xhcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/xhcivar.h,v
diff -u -p -r1.17 xhcivar.h
--- dev/usb/xhcivar.h 1 Feb 2025 22:46:34 -0000 1.17
+++ dev/usb/xhcivar.h 26 Nov 2025 09:56:52 -0000
@@ -124,6 +124,8 @@ struct xhci_softc {
int sc_flags;
#define XHCI_NOCSS 0x01
+
+ struct usb_task sc_rh_task;
};
int xhci_init(struct xhci_softc *);