diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a428aa080a3..98801cf4c18 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -30,6 +30,12 @@ #include "usb.h" +#ifdef CONFIG_ARCH_U8500 +#define MAX_TOPO_LEVEL_U8500 2 +#define MAX_USB_DEVICE_U8500 8 +int usb_device_count; +#endif + /* if we are in debug mode, always announce new devices */ #ifdef DEBUG #ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES @@ -1292,11 +1298,20 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!hub_is_superspeed(hdev) || !hdev->parent) usb_enable_autosuspend(hdev); +#ifdef CONFIG_ARCH_U8500 + if (hdev->level > MAX_TOPO_LEVEL_U8500) { + dev_err(&intf->dev, + "Unsupported bus topology: > %d " + " hub nesting\n", MAX_TOPO_LEVEL_U8500); + return -E2BIG; + } +#else if (hdev->level == MAX_TOPO_LEVEL) { dev_err(&intf->dev, "Unsupported bus topology: hub nested too deep\n"); return -E2BIG; } +#endif #ifdef CONFIG_USB_OTG_BLACKLIST_HUB if (hdev->parent) { @@ -1579,12 +1594,14 @@ static void choose_devnum(struct usb_device *udev) * bus->devnum_next. */ devnum = find_next_zero_bit(bus->devmap.devicemap, 128, bus->devnum_next); - if (devnum >= 128) + /* Due to Hardware bugs we need to reserve a device address + * for flushing of endpoints. */ + if (devnum >= 127) devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1); - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + bus->devnum_next = devnum >= 126 ? 1 : devnum + 1; } - if (devnum < 128) { + if (devnum < 127) { set_bit(devnum, bus->devmap.devicemap); udev->devnum = devnum; } @@ -3258,6 +3275,22 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, goto loop; } +#ifdef CONFIG_ARCH_U8500 + if (hdev->parent == NULL) + usb_device_count = 1; + + if (usb_device_count > MAX_USB_DEVICE_U8500) { + + dev_err(&udev->dev, + "device connected is more than %d\n", + MAX_USB_DEVICE_U8500); + + status = -ENOTCONN; /* Don't retry */ + goto loop; + } +#endif + + /* reset (non-USB 3.0 devices) and get descriptor */ status = hub_port_init(hub, udev, port1, i); if (status < 0) |