Skip to content

Commit

Permalink
usb: add port change detect workaround for L2 TTs
Browse files Browse the repository at this point in the history
JIRA: RTOS-937
  • Loading branch information
adamgreloch committed Jan 10, 2025
1 parent fe82740 commit c291f77
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 18 deletions.
10 changes: 5 additions & 5 deletions usb/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion usb/dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define _USB_DEV_H_

#include <usb.h>
#include <stdbool.h>

#include "usbhost.h"

Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
91 changes: 79 additions & 12 deletions usb/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -50,6 +51,7 @@ struct {
handle_t lock;
handle_t cond;
hub_event_t *events;
usb_dev_t *tts;
} hub_common;


Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -293,23 +326,29 @@ 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);
}
}


static void hub_connectstatus(usb_dev_t *hub, int port, usb_port_status_t *status)
{
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);
}
}


Expand Down Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}


Expand Down
5 changes: 5 additions & 0 deletions usb/hub.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit c291f77

Please sign in to comment.