X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fusb_hub.c;h=b5eeb62fbe55ecab41fe74abd3dea5209695a01f;hb=588a13f742b6d63ac7d5631af11baa01f3a9e80f;hp=f35ad95324a632bf337a11af4a800629de8611c4;hpb=f57661394a8b00029e37a5567a869e92bd13f3b8;p=u-boot diff --git a/common/usb_hub.c b/common/usb_hub.c index f35ad95324..b5eeb62fbe 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -243,7 +244,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) mdelay(200); /* Allocate a new device struct for it */ - usb = usb_alloc_new_device(); + usb = usb_alloc_new_device(dev->controller); if (portstatus & USB_PORT_STAT_HIGH_SPEED) usb->speed = USB_SPEED_HIGH; @@ -258,6 +259,8 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Run it through the hoops (find a driver, etc) */ if (usb_new_device(usb)) { /* Woops, disable the port */ + usb_free_device(); + dev->children[port] = NULL; USB_HUB_PRINTF("hub: disabling port %d\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); } @@ -269,6 +272,7 @@ static int usb_hub_configure(struct usb_device *dev) int i; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ); unsigned char *bitmap; + short hubCharacteristics; struct usb_hub_descriptor *descriptor; struct usb_hub_device *hub; #ifdef USB_HUB_DEBUG @@ -304,8 +308,9 @@ static int usb_hub_configure(struct usb_device *dev) } memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); /* adjust 16bit values */ - hub->desc.wHubCharacteristics = - le16_to_cpu(descriptor->wHubCharacteristics); + put_unaligned(le16_to_cpu(get_unaligned( + &descriptor->wHubCharacteristics)), + &hub->desc.wHubCharacteristics); /* set the bitmap */ bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; /* devices not removable by default */ @@ -322,7 +327,8 @@ static int usb_hub_configure(struct usb_device *dev) dev->maxchild = descriptor->bNbrPorts; USB_HUB_PRINTF("%d ports detected\n", dev->maxchild); - switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) { + hubCharacteristics = get_unaligned(&hub->desc.wHubCharacteristics); + switch (hubCharacteristics & HUB_CHAR_LPSM) { case 0x00: USB_HUB_PRINTF("ganged power switching\n"); break; @@ -335,12 +341,12 @@ static int usb_hub_configure(struct usb_device *dev) break; } - if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND) + if (hubCharacteristics & HUB_CHAR_COMPOUND) USB_HUB_PRINTF("part of a compound device\n"); else USB_HUB_PRINTF("standalone hub\n"); - switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) { + switch (hubCharacteristics & HUB_CHAR_OCPM) { case 0x00: USB_HUB_PRINTF("global over-current protection\n"); break; @@ -392,14 +398,37 @@ static int usb_hub_configure(struct usb_device *dev) for (i = 0; i < dev->maxchild; i++) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; + int ret; + ulong start = get_timer(0); + + /* + * Wait for (whichever finishes first) + * - A maximum of 10 seconds + * This is a purely observational value driven by connecting + * a few broken pen drives and taking the max * 1.5 approach + * - connection_change and connection state to report same + * state + */ + do { + ret = usb_get_port_status(dev, i + 1, portsts); + if (ret < 0) { + USB_HUB_PRINTF("get_port_status failed\n"); + break; + } + + portstatus = le16_to_cpu(portsts->wPortStatus); + portchange = le16_to_cpu(portsts->wPortChange); + + if ((portchange & USB_PORT_STAT_C_CONNECTION) == + (portstatus & USB_PORT_STAT_CONNECTION)) + break; - if (usb_get_port_status(dev, i + 1, portsts) < 0) { - USB_HUB_PRINTF("get_port_status failed\n"); + mdelay(100); + } while (get_timer(start) < CONFIG_SYS_HZ * 10); + + if (ret < 0) continue; - } - portstatus = le16_to_cpu(portsts->wPortStatus); - portchange = le16_to_cpu(portsts->wPortChange); USB_HUB_PRINTF("Port %d Status %X Change %X\n", i + 1, portstatus, portchange);