X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=common%2Fusb.c;h=686f09a77d1ec7caf151b21dadaa17ec979f7f4e;hb=3988be5fd4369402c410336553bc0ca1920dbe6f;hp=d94640a99e866d168174be1f11e91428296ba196;hpb=db378d786df0675aa6fc795a2198d000fddd33cc;p=oweals%2Fu-boot.git diff --git a/common/usb.c b/common/usb.c index d94640a99e..686f09a77d 100644 --- a/common/usb.c +++ b/common/usb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Most of this source has been derived from the Linux USB * project: @@ -13,8 +14,6 @@ * * Adapted for U-Boot: * (C) Copyright 2001 Denis Peter, MPL AG Switzerland - * - * SPDX-License-Identifier: GPL-2.0+ */ /* @@ -28,6 +27,9 @@ */ #include #include +#include +#include +#include #include #include #include @@ -35,18 +37,16 @@ #include #include #include -#ifdef CONFIG_4xx -#include -#endif #define USB_BUFSIZ 512 -static struct usb_device usb_dev[USB_MAX_DEVICE]; -static int dev_index; static int asynch_allowed; - char usb_started; /* flag for the started/stopped USB status */ +#if !CONFIG_IS_ENABLED(DM_USB) +static struct usb_device usb_dev[USB_MAX_DEVICE]; +static int dev_index; + #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif @@ -94,8 +94,8 @@ int usb_init(void) controllers_initialized++; start_index = dev_index; printf("scanning bus %d for devices... ", i); - dev = usb_alloc_new_device(ctrl); - if (!dev) + ret = usb_alloc_new_device(ctrl, &dev); + if (ret) break; /* @@ -104,7 +104,7 @@ int usb_init(void) */ ret = usb_new_device(dev); if (ret) - usb_free_device(); + usb_free_device(dev->controller); if (start_index == dev_index) { puts("No USB Device found\n"); @@ -146,6 +146,38 @@ int usb_stop(void) return 0; } +/****************************************************************************** + * Detect if a USB device has been plugged or unplugged. + */ +int usb_detect_change(void) +{ + int i, j; + int change = 0; + + for (j = 0; j < USB_MAX_DEVICE; j++) { + for (i = 0; i < usb_dev[j].maxchild; i++) { + struct usb_port_status status; + + if (usb_get_port_status(&usb_dev[j], i + 1, + &status) < 0) + /* USB request failed */ + continue; + + if (le16_to_cpu(status.wPortChange) & + USB_PORT_STAT_C_CONNECTION) + change++; + } + } + + return change; +} + +/* Lock or unlock async schedule on the controller */ +__weak int usb_lock_async(struct usb_device *dev, int lock) +{ + return 0; +} + /* * disables the asynch behaviour of the control message. This is used for data * transfers that uses the exclusiv access to the control and bulk messages. @@ -158,6 +190,7 @@ int usb_disable_asynch(int disable) asynch_allowed = !disable; return old_value; } +#endif /* !CONFIG_IS_ENABLED(DM_USB) */ /*------------------------------------------------------------------- @@ -166,12 +199,15 @@ int usb_disable_asynch(int disable) */ /* - * submits an Interrupt Message + * submits an Interrupt Message. Some drivers may implement non-blocking + * polling: when non-block is true and the device is not responding return + * -EAGAIN instead of waiting for device to respond. */ -int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, int interval) +int usb_int_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, int interval, bool nonblock) { - return submit_int_msg(dev, pipe, buffer, transfer_len, interval); + return submit_int_msg(dev, pipe, buffer, transfer_len, interval, + nonblock); } /* @@ -180,7 +216,7 @@ int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, * clear keyboards LEDs). For data transfers, (storage transfers) we don't * allow control messages with 0 timeout, by previousely resetting the flag * asynch_allowed (usb_disable_asynch(1)). - * returns the transfered length if OK or -1 if error. The transfered length + * returns the transferred length if OK or -1 if error. The transferred length * and the current status are stored in the dev->act_len and dev->status. */ int usb_control_msg(struct usb_device *dev, unsigned int pipe, @@ -189,6 +225,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, void *data, unsigned short size, int timeout) { ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1); + int err; if ((timeout == 0) && (!asynch_allowed)) { /* request for a asynch control pipe is not allowed */ @@ -206,8 +243,9 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, request, requesttype, value, index, size); dev->status = USB_ST_NOT_PROC; /*not yet processed */ - if (submit_control_msg(dev, pipe, data, size, setup_packet) < 0) - return -EIO; + err = submit_control_msg(dev, pipe, data, size, setup_packet); + if (err < 0) + return err; if (timeout == 0) return (int)size; @@ -408,12 +446,13 @@ static int usb_parse_config(struct usb_device *dev, } break; case USB_DT_ENDPOINT: - if (head->bLength != USB_DT_ENDPOINT_SIZE) { + if (head->bLength != USB_DT_ENDPOINT_SIZE && + head->bLength != USB_DT_ENDPOINT_AUDIO_SIZE) { printf("ERROR: Invalid USB EP length (%d)\n", head->bLength); break; } - if (index + USB_DT_ENDPOINT_SIZE > + if (index + head->bLength > dev->config.desc.wTotalLength) { puts("USB EP descriptor overflowed buffer!\n"); break; @@ -424,7 +463,7 @@ static int usb_parse_config(struct usb_device *dev, } epno = dev->config.if_desc[ifno].no_of_ep; if_desc = &dev->config.if_desc[ifno]; - if (epno > USB_MAXENDPOINTS) { + if (epno >= USB_MAXENDPOINTS) { printf("Interface %d has too many endpoints!\n", if_desc->desc.bInterfaceNumber); return -EINVAL; @@ -525,22 +564,19 @@ int usb_clear_halt(struct usb_device *dev, int pipe) static int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) { - int res; - res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (type << 8) + index, 0, - buf, size, USB_CNTL_TIMEOUT); - return res; + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (type << 8) + index, 0, buf, size, + USB_CNTL_TIMEOUT); } /********************************************************************** - * gets configuration cfgno and store it in the buffer + * gets len of configuration cfgno */ -int usb_get_configuration_no(struct usb_device *dev, - unsigned char *buffer, int cfgno) +int usb_get_configuration_len(struct usb_device *dev, int cfgno) { int result; - unsigned int length; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 9); struct usb_config_descriptor *config; config = (struct usb_config_descriptor *)&buffer[0]; @@ -554,17 +590,23 @@ int usb_get_configuration_no(struct usb_device *dev, "(expected %i, got %i)\n", 9, result); return -EIO; } - length = le16_to_cpu(config->wTotalLength); + return le16_to_cpu(config->wTotalLength); +} - if (length > USB_BUFSIZ) { - printf("%s: failed to get descriptor - too long: %d\n", - __func__, length); - return -EIO; - } +/********************************************************************** + * gets configuration cfgno and store it in the buffer + */ +int usb_get_configuration_no(struct usb_device *dev, int cfgno, + unsigned char *buffer, int length) +{ + int result; + struct usb_config_descriptor *config; + config = (struct usb_config_descriptor *)&buffer[0]; result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, length); - debug("get_conf_no %d Result %d, wLength %d\n", cfgno, result, length); - config->wTotalLength = length; /* validated, with CPU byte order */ + debug("get_conf_no %d Result %d, wLength %d\n", cfgno, result, + le16_to_cpu(config->wTotalLength)); + config->wTotalLength = result; /* validated, with CPU byte order */ return result; } @@ -575,14 +617,10 @@ int usb_get_configuration_no(struct usb_device *dev, */ static int usb_set_address(struct usb_device *dev) { - int res; - debug("set address %d\n", dev->devnum); - res = usb_control_msg(dev, usb_snddefctrl(dev), - USB_REQ_SET_ADDRESS, 0, - (dev->devnum), 0, - NULL, 0, USB_CNTL_TIMEOUT); - return res; + + return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, + 0, (dev->devnum), 0, NULL, 0, USB_CNTL_TIMEOUT); } /******************************************************************** @@ -821,6 +859,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) * the USB device are static allocated [USB_MAX_DEVICE]. */ +#if !CONFIG_IS_ENABLED(DM_USB) /* returns a pointer to the device with the index [index]. * if the device is not assigned (dev->devnum==-1) returns NULL @@ -833,16 +872,13 @@ struct usb_device *usb_get_dev_index(int index) return &usb_dev[index]; } -/* returns a pointer of a new device structure or NULL, if - * no device struct is available - */ -struct usb_device *usb_alloc_new_device(void *controller) +int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp) { int i; debug("New Device %d\n", dev_index); if (dev_index == USB_MAX_DEVICE) { printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE); - return NULL; + return -ENOSPC; } /* default Address is 0, real addresses start with 1 */ usb_dev[dev_index].devnum = dev_index + 1; @@ -852,7 +888,9 @@ struct usb_device *usb_alloc_new_device(void *controller) usb_dev[dev_index].parent = NULL; usb_dev[dev_index].controller = controller; dev_index++; - return &usb_dev[dev_index - 1]; + *devp = &usb_dev[dev_index - 1]; + + return 0; } /* @@ -860,7 +898,7 @@ struct usb_device *usb_alloc_new_device(void *controller) * Called in error cases where configuring a newly attached * device fails for some reason. */ -void usb_free_device(void) +void usb_free_device(struct udevice *controller) { dev_index--; debug("Freeing device node: %d\n", dev_index); @@ -878,123 +916,92 @@ __weak int usb_alloc_device(struct usb_device *udev) { return 0; } -/* - * By the time we get here, the device has gotten a new device ID - * and is in the default state. We need to identify the thing and - * get the ball rolling.. - * - * Returns 0 for success, != 0 for error. - */ -int usb_new_device(struct usb_device *dev) +#endif /* !CONFIG_IS_ENABLED(DM_USB) */ + +static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub) { - int addr, err; - int tmp; + if (!hub) + usb_reset_root_port(dev); + + return 0; +} + +static int get_descriptor_len(struct usb_device *dev, int len, int expect_len) +{ + __maybe_unused struct usb_device_descriptor *desc; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ); + int err; - /* - * Allocate usb 3.0 device context. - * USB 3.0 (xHCI) protocol tries to allocate device slot - * and related data structures first. This call does that. - * Refer to sec 4.3.2 in xHCI spec rev1.0 - */ - if (usb_alloc_device(dev)) { - printf("Cannot allocate device context to get SLOT_ID\n"); - return -EINVAL; + desc = (struct usb_device_descriptor *)tmpbuf; + + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, len); + if (err < expect_len) { + if (err < 0) { + printf("unable to get device descriptor (error=%d)\n", + err); + return err; + } else { + printf("USB device descriptor short read (expected %i, got %i)\n", + expect_len, err); + return -EIO; + } } + memcpy(&dev->descriptor, tmpbuf, sizeof(dev->descriptor)); - /* We still haven't set the Address yet */ - addr = dev->devnum; - dev->devnum = 0; + return 0; +} -#ifdef CONFIG_LEGACY_USB_INIT_SEQ - /* this is the old and known way of initializing devices, it is - * different than what Windows and Linux are doing. Windows and Linux - * both retrieve 64 bytes while reading the device descriptor - * Several USB stick devices report ERR: CTL_TIMEOUT, caused by an - * invalid header while reading 8 bytes as device descriptor. */ - dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ - dev->maxpacketsize = PACKET_SIZE_8; - dev->epmaxpacketin[0] = 8; - dev->epmaxpacketout[0] = 8; - - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, tmpbuf, 8); - if (err < 8) { - printf("\n USB device not responding, " \ - "giving up (status=%lX)\n", dev->status); - return -EIO; - } - memcpy(&dev->descriptor, tmpbuf, 8); -#else - /* This is a Windows scheme of initialization sequence, with double +static int usb_setup_descriptor(struct usb_device *dev, bool do_read) +{ + /* + * This is a Windows scheme of initialization sequence, with double * reset of the device (Linux uses the same sequence) * Some equipment is said to work only with such init sequence; this * patch is based on the work by Alan Stern: * http://sourceforge.net/mailarchive/forum.php? * thread_id=5729457&forum_id=5398 */ - __maybe_unused struct usb_device_descriptor *desc; - struct usb_device *parent = dev->parent; - unsigned short portstatus; - /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is + /* + * send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is * only 18 bytes long, this will terminate with a short packet. But if * the maxpacket size is 8 or 16 the device may be waiting to transmit - * some more, or keeps on retransmitting the 8 byte header. */ - - desc = (struct usb_device_descriptor *)tmpbuf; - dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */ - /* Default to 64 byte max packet size */ - dev->maxpacketsize = PACKET_SIZE_64; - dev->epmaxpacketin[0] = 64; - dev->epmaxpacketout[0] = 64; - - /* - * XHCI needs to issue a Address device command to setup - * proper device context structures, before it can interact - * with the device. So a get_descriptor will fail before any - * of that is done for XHCI unlike EHCI. - */ -#ifndef CONFIG_USB_XHCI - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64); - /* - * Validate we've received only at least 8 bytes, not that we've - * received the entire descriptor. The reasoning is: - * - The code only uses fields in the first 8 bytes, so that's all we - * need to have fetched at this stage. - * - The smallest maxpacket size is 8 bytes. Before we know the actual - * maxpacket the device uses, the USB controller may only accept a - * single packet. Consequently we are only guaranteed to receive 1 - * packet (at least 8 bytes) even in a non-error case. - * - * At least the DWC2 controller needs to be programmed with the number - * of packets in addition to the number of bytes. A request for 64 - * bytes of data with the maxpacket guessed as 64 (above) yields a - * request for 1 packet. + * some more, or keeps on retransmitting the 8 byte header. */ - if (err < 8) { - debug("usb_new_device: usb_get_descriptor() failed\n"); - return -EIO; + + if (dev->speed == USB_SPEED_LOW) { + dev->descriptor.bMaxPacketSize0 = 8; + dev->maxpacketsize = PACKET_SIZE_8; + } else { + dev->descriptor.bMaxPacketSize0 = 64; + dev->maxpacketsize = PACKET_SIZE_64; } + dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; - dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0; - /* - * Fetch the device class, driver can use this info - * to differentiate between HUB and DEVICE. - */ - dev->descriptor.bDeviceClass = desc->bDeviceClass; -#endif + if (do_read && dev->speed == USB_SPEED_FULL) { + int err; - if (parent) { - /* reset the port for the second time */ - err = hub_port_reset(dev->parent, dev->portnr - 1, &portstatus); - if (err < 0) { - printf("\n Couldn't reset port %i\n", dev->portnr); - return -EIO; - } - } else { - usb_reset_root_port(); + /* + * Validate we've received only at least 8 bytes, not that + * we've received the entire descriptor. The reasoning is: + * - The code only uses fields in the first 8 bytes, so + * that's all we need to have fetched at this stage. + * - The smallest maxpacket size is 8 bytes. Before we know + * the actual maxpacket the device uses, the USB controller + * may only accept a single packet. Consequently we are only + * guaranteed to receive 1 packet (at least 8 bytes) even in + * a non-error case. + * + * At least the DWC2 controller needs to be programmed with + * the number of packets in addition to the number of bytes. + * A request for 64 bytes of data with the maxpacket guessed + * as 64 (above) yields a request for 1 packet. + */ + err = get_descriptor_len(dev, 64, 8); + if (err) + return err; } -#endif dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; @@ -1012,9 +1019,36 @@ int usb_new_device(struct usb_device *dev) dev->maxpacketsize = PACKET_SIZE_64; break; default: - printf("usb_new_device: invalid max packet size\n"); + printf("%s: invalid max packet size\n", __func__); return -EIO; } + + return 0; +} + +static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read, + struct usb_device *parent) +{ + int err; + + /* + * Allocate usb 3.0 device context. + * USB 3.0 (xHCI) protocol tries to allocate device slot + * and related data structures first. This call does that. + * Refer to sec 4.3.2 in xHCI spec rev1.0 + */ + err = usb_alloc_device(dev); + if (err) { + printf("Cannot allocate device context to get SLOT_ID\n"); + return err; + } + err = usb_setup_descriptor(dev, do_read); + if (err) + return err; + err = usb_hub_port_reset(dev, parent); + if (err) + return err; + dev->devnum = addr; err = usb_set_address(dev); /* set address */ @@ -1022,46 +1056,86 @@ int usb_new_device(struct usb_device *dev) if (err < 0) { printf("\n USB device not accepting new address " \ "(error=%lX)\n", dev->status); - return -EIO; + return err; } mdelay(10); /* Let the SET_ADDRESS settle */ - tmp = sizeof(dev->descriptor); - - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, - tmpbuf, sizeof(dev->descriptor)); - if (err < tmp) { - if (err < 0) - printf("unable to get device descriptor (error=%d)\n", - err); - else - printf("USB device descriptor short read " \ - "(expected %i, got %i)\n", tmp, err); - return -EIO; + /* + * If we haven't read device descriptor before, read it here + * after device is assigned an address. This is only applicable + * to xHCI so far. + */ + if (!do_read) { + err = usb_setup_descriptor(dev, true); + if (err) + return err; } - memcpy(&dev->descriptor, tmpbuf, sizeof(dev->descriptor)); + + return 0; +} + +int usb_select_config(struct usb_device *dev) +{ + unsigned char *tmpbuf = NULL; + int err; + + err = get_descriptor_len(dev, USB_DT_DEVICE_SIZE, USB_DT_DEVICE_SIZE); + if (err) + return err; + /* correct le values */ le16_to_cpus(&dev->descriptor.bcdUSB); le16_to_cpus(&dev->descriptor.idVendor); le16_to_cpus(&dev->descriptor.idProduct); le16_to_cpus(&dev->descriptor.bcdDevice); + + /* + * Kingston DT Ultimate 32GB USB 3.0 seems to be extremely sensitive + * about this first Get Descriptor request. If there are any other + * requests in the first microframe, the stick crashes. Wait about + * one microframe duration here (1mS for USB 1.x , 125uS for USB 2.0). + */ + mdelay(1); + /* only support for one config for now */ - err = usb_get_configuration_no(dev, tmpbuf, 0); + err = usb_get_configuration_len(dev, 0); + if (err >= 0) { + tmpbuf = (unsigned char *)malloc_cache_aligned(err); + if (!tmpbuf) + err = -ENOMEM; + else + err = usb_get_configuration_no(dev, 0, tmpbuf, err); + } if (err < 0) { printf("usb_new_device: Cannot read configuration, " \ "skipping device %04x:%04x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); - return -EIO; + free(tmpbuf); + return err; } usb_parse_config(dev, tmpbuf, 0); + free(tmpbuf); usb_set_maxpacket(dev); - /* we set the default configuration here */ - if (usb_set_configuration(dev, dev->config.desc.bConfigurationValue)) { + /* + * we set the default configuration here + * This seems premature. If the driver wants a different configuration + * it will need to select itself. + */ + err = usb_set_configuration(dev, dev->config.desc.bConfigurationValue); + if (err < 0) { printf("failed to set default configuration " \ "len %d, status %lX\n", dev->act_len, dev->status); - return -EIO; + return err; } + + /* + * Wait until the Set Configuration request gets processed by the + * device. This is required by at least SanDisk Cruzer Pop USB 2.0 + * and Kingston DT Ultimate 32GB USB 3.0 on DWC2 OTG controller. + */ + mdelay(10); + debug("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber); @@ -1080,10 +1154,62 @@ int usb_new_device(struct usb_device *dev) debug("Manufacturer %s\n", dev->mf); debug("Product %s\n", dev->prod); debug("SerialNumber %s\n", dev->serial); - /* now prode if the device is a hub */ - usb_hub_probe(dev, 0); + + return 0; +} + +int usb_setup_device(struct usb_device *dev, bool do_read, + struct usb_device *parent) +{ + int addr; + int ret; + + /* We still haven't set the Address yet */ + addr = dev->devnum; + dev->devnum = 0; + + ret = usb_prepare_device(dev, addr, do_read, parent); + if (ret) + return ret; + ret = usb_select_config(dev); + + return ret; +} + +#if !CONFIG_IS_ENABLED(DM_USB) +/* + * By the time we get here, the device has gotten a new device ID + * and is in the default state. We need to identify the thing and + * get the ball rolling.. + * + * Returns 0 for success, != 0 for error. + */ +int usb_new_device(struct usb_device *dev) +{ + bool do_read = true; + int err; + + /* + * XHCI needs to issue a Address device command to setup + * proper device context structures, before it can interact + * with the device. So a get_descriptor will fail before any + * of that is done for XHCI unlike EHCI. + */ +#ifdef CONFIG_USB_XHCI_HCD + do_read = false; +#endif + err = usb_setup_device(dev, do_read, dev->parent); + if (err) + return err; + + /* Now probe if the device is a hub */ + err = usb_hub_probe(dev, 0); + if (err < 0) + return err; + return 0; } +#endif __weak int board_usb_init(int index, enum usb_init_type init) @@ -1096,4 +1222,70 @@ int board_usb_cleanup(int index, enum usb_init_type init) { return 0; } + +bool usb_device_has_child_on_port(struct usb_device *parent, int port) +{ +#if CONFIG_IS_ENABLED(DM_USB) + return false; +#else + return parent->children[port] != NULL; +#endif +} + +#if CONFIG_IS_ENABLED(DM_USB) +void usb_find_usb2_hub_address_port(struct usb_device *udev, + uint8_t *hub_address, uint8_t *hub_port) +{ + struct udevice *parent; + struct usb_device *uparent, *ttdev; + + /* + * When called from usb-uclass.c: usb_scan_device() udev->dev points + * to the parent udevice, not the actual udevice belonging to the + * udev as the device is not instantiated yet. So when searching + * for the first usb-2 parent start with udev->dev not + * udev->dev->parent . + */ + ttdev = udev; + parent = udev->dev; + uparent = dev_get_parent_priv(parent); + + while (uparent->speed != USB_SPEED_HIGH) { + struct udevice *dev = parent; + + if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) { + printf("Error: Cannot find high speed parent of usb-1 device\n"); + *hub_address = 0; + *hub_port = 0; + return; + } + + ttdev = dev_get_parent_priv(dev); + parent = dev->parent; + uparent = dev_get_parent_priv(parent); + } + *hub_address = uparent->devnum; + *hub_port = ttdev->portnr; +} +#else +void usb_find_usb2_hub_address_port(struct usb_device *udev, + uint8_t *hub_address, uint8_t *hub_port) +{ + /* Find out the nearest parent which is high speed */ + while (udev->parent->parent != NULL) + if (udev->parent->speed != USB_SPEED_HIGH) { + udev = udev->parent; + } else { + *hub_address = udev->parent->devnum; + *hub_port = udev->portnr; + return; + } + + printf("Error: Cannot find high speed parent of usb-1 device\n"); + *hub_address = 0; + *hub_port = 0; +} +#endif + + /* EOF */