From c291f7748e1db8f8d3490393d3d5ca0a2f5722a7 Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Fri, 10 Jan 2025 10:30:18 +0100 Subject: [PATCH] usb: add port change detect workaround for L2 TTs JIRA: RTOS-937 --- usb/dev.c | 10 +++--- usb/dev.h | 5 ++- usb/hub.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++-------- usb/hub.h | 5 +++ 4 files changed, 93 insertions(+), 18 deletions(-) diff --git a/usb/dev.c b/usb/dev.c index 01b0476..d963e6b 100644 --- a/usb/dev.c +++ b/usb/dev.c @@ -210,7 +210,6 @@ static int usb_getConfiguration(usb_dev_t *dev) /* Get first nine bytes to get to know configuration len */ if (usb_getDescriptor(dev, USB_DESC_CONFIG, 0, (char *)&pre, sizeof(pre)) < 0) { - USB_LOG("usb: Fail to get configuration descriptor\n"); return -1; } @@ -224,7 +223,6 @@ static int usb_getConfiguration(usb_dev_t *dev) /* TODO: Handle multiple configuration devices */ if (usb_getDescriptor(dev, USB_DESC_CONFIG, 0, (char *)conf, pre.wTotalLength) < 0) { - USB_LOG("usb: Fail to get configuration descriptor\n"); free(conf); return -1; } @@ -420,7 +418,7 @@ static int usb_getAllStringDescs(usb_dev_t *dev) int usb_devEnumerate(usb_dev_t *dev) { - int addr; + int addr, ret; if (usb_genLocationID(dev) < 0) { USB_LOG("usb: Fail to generate location ID\n"); @@ -525,9 +523,11 @@ usb_dev_t *usb_devFind(usb_dev_t *hub, int locationID) } -void usb_devDisconnected(usb_dev_t *dev) +void usb_devDisconnected(usb_dev_t *dev, bool silent) { - printf("usb: Device disconnected addr %d locationID: %08x\n", dev->address, dev->locationID); + if (!silent) { + printf("usb: Device disconnected addr %d locationID: %08x\n", dev->address, dev->locationID); + } usb_devSetChild(dev->hub, dev->port, NULL); usb_devUnbind(dev); usb_devDestroy(dev); diff --git a/usb/dev.h b/usb/dev.h index 901f2d5..b74a6a1 100644 --- a/usb/dev.h +++ b/usb/dev.h @@ -16,6 +16,7 @@ #define _USB_DEV_H_ #include +#include #include "usbhost.h" @@ -33,6 +34,8 @@ typedef struct { typedef struct _usb_dev { + struct _usb_dev *next, *prev; + enum usb_speed speed; usb_device_desc_t desc; usb_configuration_desc_t *conf; @@ -71,7 +74,7 @@ usb_dev_t *usb_devAlloc(void); int usb_devEnumerate(usb_dev_t *dev); -void usb_devDisconnected(usb_dev_t *dev); +void usb_devDisconnected(usb_dev_t *dev, bool silent); int usb_devInit(void); diff --git a/usb/hub.c b/usb/hub.c index eb6d8df..5d11f7d 100644 --- a/usb/hub.c +++ b/usb/hub.c @@ -37,6 +37,7 @@ #define HUB_DEBOUNCE_STABLE 100000 #define HUB_DEBOUNCE_PERIOD 25000 #define HUB_DEBOUNCE_TIMEOUT 1500000 +#define HUB_TT_POLL_DELAY_MS 1000000 typedef struct _hub_event { @@ -50,6 +51,7 @@ struct { handle_t lock; handle_t cond; hub_event_t *events; + usb_dev_t *tts; } hub_common; @@ -170,7 +172,14 @@ static int hub_interruptInit(usb_dev_t *hub) } -static int hub_poll(usb_dev_t *hub) +static int hub_isTT(usb_dev_t *dev) +{ + /* TODO support MTTs */ + return dev->desc.bDeviceClass == USB_CLASS_HUB && dev->desc.bDeviceProtocol == USB_HUB_PROTO_SINGLE_TT; +} + + +static int hub_requestStatus(usb_dev_t *hub) { return usb_transferSubmit(hub->statusTransfer, hub->irqPipe, NULL); } @@ -248,6 +257,31 @@ static int hub_portDebounce(usb_dev_t *hub, int port) } +static void hub_ttAdd(usb_dev_t *hub) +{ + mutexLock(hub_common.lock); + LIST_ADD(&hub_common.tts, hub); + mutexUnlock(hub_common.lock); +} + + +static void hub_ttRemove(usb_dev_t *hub) +{ + mutexLock(hub_common.lock); + LIST_REMOVE(&hub_common.tts, hub); + mutexUnlock(hub_common.lock); +} + + +static void hub_devDisconnect(usb_dev_t *dev, bool silent) +{ + usb_devDisconnected(dev, silent); + if (hub_isTT(dev)) { + hub_ttRemove(dev); + } +} + + static void hub_devConnected(usb_dev_t *hub, int port) { usb_dev_t *dev; @@ -284,7 +318,6 @@ static void hub_devConnected(usb_dev_t *hub, int port) break; } else if (ret != 0) { - printf("usb: Enumeration failed retries left: %d\n", retries); dev->hcd->ops->pipeDestroy(dev->hcd, dev->ctrlPipe); if (dev->address != 0) hcd_addrFree(hub->hcd, dev->address); @@ -293,8 +326,10 @@ static void hub_devConnected(usb_dev_t *hub, int port) } } while (ret != 0 && retries > 0); - if (ret != 0) - usb_devDisconnected(dev); + if (ret != 0) { + printf("usb: Enumeration failed despite %d attempts\n", HUB_ENUM_RETRIES); + hub_devDisconnect(dev, true); + } } @@ -302,14 +337,18 @@ static void hub_connectstatus(usb_dev_t *hub, int port, usb_port_status_t *statu { int pstatus; - if (hub->devs[port - 1] != NULL) - usb_devDisconnected(hub->devs[port - 1]); + if (hub->devs[port - 1] != NULL) { + hub_devDisconnect(hub->devs[port - 1], false); + } - if ((pstatus = hub_portDebounce(hub, port)) < 0) + pstatus = hub_portDebounce(hub, port); + if (pstatus < 0) { return; + } - if (pstatus) + if (pstatus) { hub_devConnected(hub, port); + } } @@ -348,12 +387,29 @@ static uint32_t hub_getStatus(usb_dev_t *hub) if (hub->statusTransfer->error == 0 && hub->statusTransfer->transferred > 0) memcpy(&status, hub->statusTransfer->buffer, sizeof(status)); - hub_poll(hub); + hub_requestStatus(hub); } return status; } +static void hub_ttStatus(void) +{ + usb_dev_t *hub; + int i; + + hub = hub_common.tts; + if (hub == NULL) { + return; + } + + do { + for (i = 0; i < hub->nports; i++) { + hub_portstatus(hub, i + 1); + } + } while ((hub = hub->next) != hub_common.tts); +} + static void hub_thread(void *args) { @@ -363,8 +419,10 @@ static void hub_thread(void *args) for (;;) { mutexLock(hub_common.lock); - while (hub_common.events == NULL) - condWait(hub_common.cond, hub_common.lock, 0); + while (hub_common.events == NULL) { + condWait(hub_common.cond, hub_common.lock, HUB_TT_POLL_DELAY_MS); + hub_ttStatus(); + } ev = hub_common.events; LIST_REMOVE(&hub_common.events, ev); mutexUnlock(hub_common.lock); @@ -431,7 +489,16 @@ int hub_conf(usb_dev_t *hub) if (hub_interruptInit(hub) != 0) return -EINVAL; - return hub_poll(hub); + if (hub_isTT(hub)) { + // FIXME Interrupt pipe notifications from tier 2 TTs never come, which is + // either a quirk in currently tested hw or an issue in the hcd driver + + // In addition to request an interrupt request, actively poll the status as well + // for as a workaround + hub_ttAdd(hub); + } + + return hub_requestStatus(hub); } diff --git a/usb/hub.h b/usb/hub.h index 05143bf..fffc3b4 100644 --- a/usb/hub.h +++ b/usb/hub.h @@ -53,6 +53,11 @@ #define USB_HUB_MAX_PORTS 15 +/* hub-specific protocol codes */ +#define USB_HUB_PROTO_ROOT 0x0 +#define USB_HUB_PROTO_SINGLE_TT 0x1 + + typedef struct usb_port_status { uint16_t wPortStatus; uint16_t wPortChange;