]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
dm: usb: Add a uclass for USB controllers
authorSimon Glass <sjg@chromium.org>
Wed, 25 Mar 2015 18:21:59 +0000 (12:21 -0600)
committerSimon Glass <sjg@chromium.org>
Sat, 18 Apr 2015 17:11:20 +0000 (11:11 -0600)
Add a uclass that can represent a USB controller. For now we do not create
devices for things attached to the controller. This will be added later.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Marek Vasut <marex@denx.de>
drivers/usb/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/usb-uclass.c [new file with mode: 0644]
drivers/usb/musb-new/musb_uboot.c
include/dm/uclass-id.h
include/usb.h

index b4a94427034c2cdb03aadeb6aa8dcac1894528f8..a4414efab753fed89dd0b8f6b848d21656399da3 100644 (file)
@@ -35,6 +35,20 @@ config USB
 
 if USB
 
+config DM_USB
+       bool "Enable driver model for USB"
+       depends on USB && DM
+       help
+         Enable driver model for USB. The USB interface is then implemented
+         by the USB uclass. Multiple USB controllers of different types
+         (XHCI, EHCI) can be attached and used. The 'usb' command works as
+         normal. OCHI is not supported at present.
+
+         Much of the code is shared but with this option enabled the USB
+         uclass takes care of device enumeration. USB devices can be
+         declared with the USB_DEVICE() macro and will be automatically
+         probed when found on the bus.
+
 source "drivers/usb/host/Kconfig"
 
 config USB_STORAGE
index eb6f34b53cb686a6cbd093482661fb96c01ced6a..9419295d0dc96a836e8334639cc04e26c0cf58f4 100644 (file)
@@ -5,6 +5,10 @@
 # SPDX-License-Identifier:     GPL-2.0+
 #
 
+ifdef CONFIG_DM_USB
+obj-$(CONFIG_CMD_USB) += usb-uclass.o
+endif
+
 # ohci
 obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
 obj-$(CONFIG_USB_ATMEL) += ohci-at91.o
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
new file mode 100644 (file)
index 0000000..22dcd14
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <usb.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern bool usb_started; /* flag for the started/stopped USB status */
+static bool asynch_allowed;
+
+int usb_disable_asynch(int disable)
+{
+       int old_value = asynch_allowed;
+
+       asynch_allowed = !disable;
+       return old_value;
+}
+
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+                  int length, int interval)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       if (!ops->interrupt)
+               return -ENOSYS;
+
+       return ops->interrupt(bus, udev, pipe, buffer, length, interval);
+}
+
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
+                      void *buffer, int length, struct devrequest *setup)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       if (!ops->control)
+               return -ENOSYS;
+
+       return ops->control(bus, udev, pipe, buffer, length, setup);
+}
+
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+                   int length)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       if (!ops->bulk)
+               return -ENOSYS;
+
+       return ops->bulk(bus, udev, pipe, buffer, length);
+}
+
+int usb_alloc_device(struct usb_device *udev)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       /* This is only requird by some controllers - current XHCI */
+       if (!ops->alloc_device)
+               return 0;
+
+       return ops->alloc_device(bus, udev);
+}
+
+int usb_stop(void)
+{
+       struct udevice *bus;
+       struct uclass *uc;
+       int err = 0, ret;
+
+       /* De-activate any devices that have been activated */
+       ret = uclass_get(UCLASS_USB, &uc);
+       if (ret)
+               return ret;
+       uclass_foreach_dev(bus, uc) {
+               ret = device_remove(bus);
+               if (ret && !err)
+                       err = ret;
+       }
+
+       usb_stor_reset();
+       usb_hub_reset();
+       usb_started = 0;
+
+       return err;
+}
+
+static int usb_scan_bus(struct udevice *bus, bool recurse)
+{
+       struct usb_bus_priv *priv;
+       struct udevice *dev;
+       int ret;
+
+       priv = dev_get_uclass_priv(bus);
+
+       assert(recurse);        /* TODO: Support non-recusive */
+
+       ret = usb_scan_device(bus, 0, USB_SPEED_FULL, &dev);
+       if (ret)
+               return ret;
+
+       return priv->next_addr;
+}
+
+int usb_init(void)
+{
+       int controllers_initialized = 0;
+       struct udevice *bus;
+       struct uclass *uc;
+       int count = 0;
+       int ret;
+
+       asynch_allowed = 1;
+       usb_hub_reset();
+
+       ret = uclass_get(UCLASS_USB, &uc);
+       if (ret)
+               return ret;
+
+       uclass_foreach_dev(bus, uc) {
+               /* init low_level USB */
+               count++;
+               printf("USB");
+               printf("%d:   ", bus->seq);
+               ret = device_probe(bus);
+               if (ret == -ENODEV) {   /* No such device. */
+                       puts("Port not available.\n");
+                       controllers_initialized++;
+                       continue;
+               }
+
+               if (ret) {              /* Other error. */
+                       printf("probe failed, error %d\n", ret);
+                       continue;
+               }
+               /*
+                * lowlevel init is OK, now scan the bus for devices
+                * i.e. search HUBs and configure them
+                */
+               controllers_initialized++;
+               printf("scanning bus %d for devices... ", bus->seq);
+               debug("\n");
+               ret = usb_scan_bus(bus, true);
+               if (ret < 0)
+                       printf("failed, error %d\n", ret);
+               else if (!ret)
+                       printf("No USB Device found\n");
+               else
+                       printf("%d USB Device(s) found\n", ret);
+               usb_started = true;
+       }
+
+       debug("scan end\n");
+       /* if we were not able to find at least one working bus, bail out */
+       if (!count)
+               printf("No controllers found\n");
+       else if (controllers_initialized == 0)
+               printf("USB error: all controllers failed lowlevel init\n");
+
+       return usb_started ? 0 : -1;
+}
+
+int usb_reset_root_port(void)
+{
+       return -ENOSYS;
+}
+
+static struct usb_device *find_child_devnum(struct udevice *parent, int devnum)
+{
+       struct usb_device *udev;
+       struct udevice *dev;
+
+       if (!device_active(parent))
+               return NULL;
+       udev = dev_get_parentdata(parent);
+       if (udev->devnum == devnum)
+               return udev;
+
+       for (device_find_first_child(parent, &dev);
+            dev;
+            device_find_next_child(&dev)) {
+               udev = find_child_devnum(dev, devnum);
+               if (udev)
+                       return udev;
+       }
+
+       return NULL;
+}
+
+struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
+{
+       struct udevice *hub;
+       int devnum = index + 1; /* Addresses are allocated from 1 on USB */
+
+       device_find_first_child(bus, &hub);
+       if (device_get_uclass_id(hub) == UCLASS_USB_HUB)
+               return find_child_devnum(hub, devnum);
+
+       return NULL;
+}
+
+int usb_post_bind(struct udevice *dev)
+{
+       /* Scan the bus for devices */
+       return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+int usb_port_reset(struct usb_device *parent, int portnr)
+{
+       unsigned short portstatus;
+       int ret;
+
+       debug("%s: start\n", __func__);
+
+       if (parent) {
+               /* reset the port for the second time */
+               assert(portnr > 0);
+               debug("%s: reset %d\n", __func__, portnr - 1);
+               ret = legacy_hub_port_reset(parent, portnr - 1, &portstatus);
+               if (ret < 0) {
+                       printf("\n     Couldn't reset port %i\n", portnr);
+                       return ret;
+               }
+       } else {
+               debug("%s: reset root\n", __func__);
+               usb_reset_root_port();
+       }
+
+       return 0;
+}
+
+int usb_legacy_port_reset(struct usb_device *parent, int portnr)
+{
+       return usb_port_reset(parent, portnr);
+}
+
+int usb_scan_device(struct udevice *parent, int port,
+                   enum usb_device_speed speed, struct udevice **devp)
+{
+       struct udevice *dev;
+       bool created = false;
+       struct usb_dev_platdata *plat;
+       struct usb_bus_priv *priv;
+       struct usb_device *parent_udev;
+       int ret;
+       ALLOC_CACHE_ALIGN_BUFFER(struct usb_device, udev, 1);
+       struct usb_interface_descriptor *iface = &udev->config.if_desc[0].desc;
+
+       *devp = NULL;
+       memset(udev, '\0', sizeof(*udev));
+       ret = usb_get_bus(parent, &udev->controller_dev);
+       if (ret)
+               return ret;
+       priv = dev_get_uclass_priv(udev->controller_dev);
+
+       /*
+        * Somewhat nasty, this. We create a local device and use the normal
+        * USB stack to read its descriptor. Then we know what type of device
+        * to create for real.
+        *
+        * udev->dev is set to the parent, since we don't have a real device
+        * yet. The USB stack should not access udev.dev anyway, except perhaps
+        * to find the controller, and the controller will either be @parent,
+        * or some parent of @parent.
+        *
+        * Another option might be to create the device as a generic USB
+        * device, then morph it into the correct one when we know what it
+        * should be. This means that a generic USB device would morph into
+        * a network controller, or a USB flash stick, for example. However,
+        * we don't support such morphing and it isn't clear that it would
+        * be easy to do.
+        *
+        * Yet another option is to split out the USB stack parts of udev
+        * into something like a 'struct urb' (as Linux does) which can exist
+        * independently of any device. This feels cleaner, but calls for quite
+        * a big change to the USB stack.
+        *
+        * For now, the approach is to set up an empty udev, read its
+        * descriptor and assign it an address, then bind a real device and
+        * stash the resulting information into the device's parent
+        * platform data. Then when we probe it, usb_child_pre_probe() is called
+        * and it will pull the information out of the stash.
+        */
+       udev->dev = parent;
+       udev->speed = speed;
+       udev->devnum = priv->next_addr + 1;
+       udev->portnr = port;
+       debug("Calling usb_setup_device(), portnr=%d\n", udev->portnr);
+       parent_udev = device_get_uclass_id(parent) == UCLASS_USB_HUB ?
+               dev_get_parentdata(parent) : NULL;
+       ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev, port);
+       debug("read_descriptor for '%s': ret=%d\n", parent->name, ret);
+       if (ret)
+               return ret;
+       ret = usb_find_child(parent, &udev->descriptor, iface, &dev);
+       debug("** usb_find_child returns %d\n", ret);
+
+       /* TODO: Find a suitable driver and create the device */
+       return -ENOENT;
+}
+
+int usb_child_post_bind(struct udevice *dev)
+{
+       struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+       const void *blob = gd->fdt_blob;
+       int val;
+
+       if (dev->of_offset == -1)
+               return 0;
+
+       /* We only support matching a few things */
+       val = fdtdec_get_int(blob, dev->of_offset, "usb,device-class", -1);
+       if (val != -1) {
+               plat->id.match_flags |= USB_DEVICE_ID_MATCH_DEV_CLASS;
+               plat->id.bDeviceClass = val;
+       }
+       val = fdtdec_get_int(blob, dev->of_offset, "usb,interface-class", -1);
+       if (val != -1) {
+               plat->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
+               plat->id.bInterfaceClass = val;
+       }
+
+       return 0;
+}
+
+int usb_get_bus(struct udevice *dev, struct udevice **busp)
+{
+       struct udevice *bus;
+
+       *busp = NULL;
+       for (bus = dev; bus && device_get_uclass_id(bus) != UCLASS_USB; )
+               bus = bus->parent;
+       if (!bus) {
+               /* By design this cannot happen */
+               assert(bus);
+               debug("USB HUB '%s' does not have a controller\n", dev->name);
+               return -EXDEV;
+       }
+       *busp = bus;
+
+       return 0;
+}
+
+int usb_child_pre_probe(struct udevice *dev)
+{
+       struct udevice *bus;
+       struct usb_device *udev = dev_get_parentdata(dev);
+       struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+       int ret;
+
+       ret = usb_get_bus(dev, &bus);
+       if (ret)
+               return ret;
+       udev->controller_dev = bus;
+       udev->dev = dev;
+       udev->devnum = plat->devnum;
+       udev->slot_id = plat->slot_id;
+       udev->portnr = plat->portnr;
+       udev->speed = plat->speed;
+       debug("** device '%s': getting slot_id=%d\n", dev->name, plat->slot_id);
+
+       ret = usb_select_config(udev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+UCLASS_DRIVER(usb) = {
+       .id             = UCLASS_USB,
+       .name           = "usb",
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
+       .post_bind      = usb_post_bind,
+       .per_child_auto_alloc_size = sizeof(struct usb_device),
+       .per_device_auto_alloc_size = sizeof(struct usb_bus_priv),
+       .child_post_bind = usb_child_post_bind,
+       .child_pre_probe = usb_child_pre_probe,
+       .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
+};
index 053d94560d4c443c5b68f515ddafa0afe614bba9..7d90ebc1f5cf9afeda08f5cdbd0fab7f1d751edf 100644 (file)
@@ -180,7 +180,7 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
        return NULL; /* URB still pending */
 }
 
-void usb_reset_root_port(void)
+int usb_reset_root_port(void)
 {
        void *mbase = host->mregs;
        u8 power;
@@ -208,6 +208,8 @@ void usb_reset_root_port(void)
                        (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
                        USB_SPEED_FULL : USB_SPEED_LOW;
        mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+
+       return 0;
 }
 
 int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
index 79b51d346afa77ed5a786a0010d6f631adcb24b5..95bd249956987a1a8e82b403a76b2dbbc08660d3 100644 (file)
@@ -40,6 +40,7 @@ enum uclass_id {
        UCLASS_PCH,             /* x86 platform controller hub */
        UCLASS_ETH,             /* Ethernet device */
        UCLASS_LPC,             /* x86 'low pin count' interface */
+       UCLASS_USB,             /* USB bus */
 
        UCLASS_COUNT,
        UCLASS_INVALID = -1,
index 2c3d5063455cd4174accee688f5ed4a5367ea32f..67615eaa2269c60f6bba4f3d019f5b2f2303c720 100644 (file)
@@ -2,6 +2,9 @@
  * (C) Copyright 2001
  * Denis Peter, MPL AG Switzerland
  *
+ * Adapted for U-Boot driver model
+ * (C) Copyright 2015 Google, Inc
+ *
  * SPDX-License-Identifier:    GPL-2.0+
  * Note: Part of this code has been derived from linux
  *
@@ -9,6 +12,7 @@
 #ifndef _USB_H_
 #define _USB_H_
 
+#include <fdtdec.h>
 #include <usb_defs.h>
 #include <linux/usb/ch9.h>
 #include <asm/cache.h>
@@ -85,6 +89,19 @@ enum {
        PACKET_SIZE_64  = 3,
 };
 
+/**
+ * struct usb_device - information about a USB device
+ *
+ * With driver model both UCLASS_USB (the USB controllers) and UCLASS_USB_HUB
+ * (the hubs) have this as parent data. Hubs are children of controllers or
+ * other hubs and there is always a single root hub for each controller.
+ * Therefore struct usb_device can always be accessed with
+ * dev_get_parentdata(dev), where dev is a USB device.
+ *
+ * Pointers exist for obtaining both the device (could be any uclass) and
+ * controller (UCLASS_USB) from this structure. The controller does not have
+ * a struct usb_device since it is not a device.
+ */
 struct usb_device {
        int     devnum;                 /* Device number on USB bus */
        int     speed;                  /* full/low/high */
@@ -123,13 +140,19 @@ struct usb_device {
        unsigned long int_pending;      /* 1 bit per ep, used by int_queue */
        int act_len;                    /* transfered bytes */
        int maxchild;                   /* Number of ports if hub */
-       int portnr;
+       int portnr;                     /* Port number, 1=first */
+#ifndef CONFIG_DM_USB
+       /* parent hub, or NULL if this is the root hub */
        struct usb_device *parent;
        struct usb_device *children[USB_MAXCHILDREN];
-
        void *controller;               /* hardware controller private data */
+#endif
        /* slot_id - for xHCI enabled devices */
        unsigned int slot_id;
+#ifdef CONFIG_DM_USB
+       struct udevice *dev;            /* Pointer to associated device */
+       struct udevice *controller_dev; /* Pointer to associated controller */
+#endif
 };
 
 struct int_queue;
@@ -160,8 +183,9 @@ enum usb_init_type {
 
 int usb_lowlevel_init(int index, enum usb_init_type init, void **controller);
 int usb_lowlevel_stop(int index);
-#ifdef CONFIG_MUSB_HOST
-void usb_reset_root_port(void);
+
+#if defined(CONFIG_MUSB_HOST) || defined(CONFIG_DM_USB)
+int usb_reset_root_port(void);
 #else
 #define usb_reset_root_port()
 #endif
@@ -245,7 +269,6 @@ int usb_stop(void); /* stop the USB Controller */
 int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol);
 int usb_set_idle(struct usb_device *dev, int ifnum, int duration,
                        int report_id);
-struct usb_device *usb_get_dev_index(int index);
 int usb_control_msg(struct usb_device *dev, unsigned int pipe,
                        unsigned char request, unsigned char requesttype,
                        unsigned short value, unsigned short index,
@@ -423,6 +446,258 @@ struct usb_hub_device {
        struct usb_hub_descriptor desc;
 };
 
+#ifdef CONFIG_DM_USB
+/**
+ * struct usb_platdata - Platform data about a USB controller
+ *
+ * Given a USB controller (UCLASS_USB) dev this is dev_get_platdata(dev)
+ */
+struct usb_platdata {
+       enum usb_init_type init_type;
+};
+
+/**
+ * struct usb_dev_platdata - Platform data about a USB device
+ *
+ * Given a USB device dev this structure is dev_get_parent_platdata(dev).
+ * This is used by sandbox to provide emulation data also.
+ *
+ * @id:                ID used to match this device
+ * @speed:     Stores the speed associated with a USB device
+ * @devnum:    Device address on the USB bus
+ * @slot_id:   USB3 slot ID, which is separate from the device address
+ * @portnr:    Port number of this device on its parent hub, numbered from 1
+ *             (0 mean this device is the root hub)
+ * @strings:   List of descriptor strings (for sandbox emulation purposes)
+ * @desc_list: List of descriptors (for sandbox emulation purposes)
+ */
+struct usb_dev_platdata {
+       struct usb_device_id id;
+       enum usb_device_speed speed;
+       int devnum;
+       int slot_id;
+       int portnr;     /* Hub port number, 1..n */
+#ifdef CONFIG_SANDBOX
+       struct usb_string *strings;
+       /* NULL-terminated list of descriptor pointers */
+       struct usb_generic_descriptor **desc_list;
+#endif
+       int configno;
+};
+
+/**
+ * struct usb_bus_priv - information about the USB controller
+ *
+ * Given a USB controller (UCLASS_USB) 'dev', this is
+ * dev_get_uclass_priv(dev).
+ *
+ * @next_addr: Next device address to allocate minus 1. Incremented by 1
+ *             each time a new device address is set, so this holds the
+ *             number of devices on the bus
+ * @desc_before_addr:  true if we can read a device descriptor before it
+ *             has been assigned an address. For XHCI this is not possible
+ *             so this will be false.
+ */
+struct usb_bus_priv {
+       int next_addr;
+       bool desc_before_addr;
+};
+
+/**
+ * struct dm_usb_ops - USB controller operations
+ *
+ * This defines the operations supoorted on a USB controller. Common
+ * arguments are:
+ *
+ * @bus:       USB bus (i.e. controller), which is in UCLASS_USB.
+ * @udev:      USB device parent data. Controllers are not expected to need
+ *             this, since the device address on the bus is encoded in @pipe.
+ *             It is used for sandbox, and can be handy for debugging and
+ *             logging.
+ * @pipe:      An assortment of bitfields which provide address and packet
+ *             type information. See create_pipe() above for encoding
+ *             details
+ * @buffer:    A buffer to use for sending/receiving. This should be
+ *             DMA-aligned.
+ * @length:    Buffer length in bytes
+ */
+struct dm_usb_ops {
+       /**
+        * control() - Send a control message
+        *
+        * Most parameters are as above.
+        *
+        * @setup: Additional setup information required by the message
+        */
+       int (*control)(struct udevice *bus, struct usb_device *udev,
+                      unsigned long pipe, void *buffer, int length,
+                      struct devrequest *setup);
+       /**
+        * bulk() - Send a bulk message
+        *
+        * Parameters are as above.
+        */
+       int (*bulk)(struct udevice *bus, struct usb_device *udev,
+                   unsigned long pipe, void *buffer, int length);
+       /**
+        * interrupt() - Send an interrupt message
+        *
+        * Most parameters are as above.
+        *
+        * @interval: Interrupt interval
+        */
+       int (*interrupt)(struct udevice *bus, struct usb_device *udev,
+                        unsigned long pipe, void *buffer, int length,
+                        int interval);
+       /**
+        * alloc_device() - Allocate a new device context (XHCI)
+        *
+        * Before sending packets to a new device on an XHCI bus, a device
+        * context must be created. If this method is not NULL it will be
+        * called before the device is enumerated (even before its descriptor
+        * is read). This should be NULL for EHCI, which does not need this.
+        */
+       int (*alloc_device)(struct udevice *bus, struct usb_device *udev);
+};
+
+#define usb_get_ops(dev)       ((struct dm_usb_ops *)(dev)->driver->ops)
+#define usb_get_emul_ops(dev)  ((struct dm_usb_ops *)(dev)->driver->ops)
+
+#ifdef CONFIG_MUSB_HOST
+int usb_reset_root_port(void);
+#endif
+
+/**
+ * usb_get_dev_index() - look up a device index number
+ *
+ * Look up devices using their index number (starting at 0). This works since
+ * in U-Boot device addresses are allocated starting at 1 with no gaps.
+ *
+ * TODO(sjg@chromium.org): Remove this function when usb_ether.c is modified
+ * to work better with driver model.
+ *
+ * @bus:       USB bus to check
+ * @index:     Index number of device to find (0=first). This is just the
+ *             device address less 1.
+ */
+struct usb_device *usb_get_dev_index(struct udevice *bus, int index);
+
+/**
+ * usb_legacy_port_reset() - Legacy function to reset a hub port
+ *
+ * @hub:       Hub device
+ * @portnr:    Port number (1=first)
+ */
+int usb_legacy_port_reset(struct usb_device *hub, int portnr);
+
+/**
+ * usb_setup_device() - set up a device ready for use
+ *
+ * @dev:       USB device pointer. This need not be a real device - it is
+ *             common for it to just be a local variable with its ->dev
+ *             member (i.e. @dev->dev) set to the parent device
+ * @do_read:   true to read the device descriptor before an address is set
+ *             (should be false for XHCI buses, true otherwise)
+ * @parent:    Parent device (either UCLASS_USB or UCLASS_USB_HUB)
+ * @portnr:    Port number on hub (1=first) or 0 for none
+ * @return 0 if OK, -ve on error */
+int usb_setup_device(struct usb_device *dev, bool do_read,
+                    struct usb_device *parent, int portnr);
+
+/**
+ * usb_hub_scan() - Scan a hub and find its devices
+ *
+ * @hub:       Hub device to scan
+ */
+int usb_hub_scan(struct udevice *hub);
+
+/**
+ * usb_scan_device() - Scan a device on a bus
+ *
+ * Scan a device on a bus. It has already been detected and is ready to
+ * be enumerated. This may be either the root hub (@parent is a bus) or a
+ * normal device (@parent is a hub)
+ *
+ * @parent:    Parent device
+ * @port:      Hub port number (numbered from 1)
+ * @speed:     USB speed to use for this device
+ * @devp:      Returns pointer to device if all is well
+ * @return 0 if OK, -ve on error
+ */
+int usb_scan_device(struct udevice *parent, int port,
+                   enum usb_device_speed speed, struct udevice **devp);
+
+/**
+ * usb_get_bus() - Find the bus for a device
+ *
+ * Search up through parents to find the bus this device is connected to. This
+ * will be a device with uclass UCLASS_USB.
+ *
+ * @dev:       Device to check
+ * @busp:      Returns bus, or NULL if not found
+ * @return 0 if OK, -EXDEV is somehow this bus does not have a controller (this
+ *     indicates a critical error in the USB stack
+ */
+int usb_get_bus(struct udevice *dev, struct udevice **busp);
+
+/**
+ * usb_select_config() - Set up a device ready for use
+ *
+ * This function assumes that the device already has an address and a driver
+ * bound, and is ready to be set up.
+ *
+ * This re-reads the device and configuration descriptors and sets the
+ * configuration
+ *
+ * @dev:       Device to set up
+ */
+int usb_select_config(struct usb_device *dev);
+
+/**
+ * usb_child_pre_probe() - Pre-probe function for USB devices
+ *
+ * This is called on all children of hubs and USB controllers (i.e. UCLASS_USB
+ * and UCLASS_USB_HUB) when a new device is about to be probed. It sets up the
+ * device from the saved platform data and calls usb_select_config() to
+ * finish set up.
+ *
+ * Once this is done, the device's normal driver can take over, knowing the
+ * device is accessible on the USB bus.
+ *
+ * This function is for use only by the internal USB stack.
+ *
+ * @dev:       Device to set up
+ */
+int usb_child_pre_probe(struct udevice *dev);
+
+struct ehci_ctrl;
+
+/**
+ * usb_setup_ehci_gadget() - Set up a USB device as a gadget
+ *
+ * TODO(sjg@chromium.org): Tidy this up when USB gadgets can use driver model
+ *
+ * This provides a way to tell a controller to start up as a USB device
+ * instead of as a host. It is untested.
+ */
+int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp);
+
+/**
+ * usb_stor_reset() - Prepare to scan USB storage devices
+ *
+ * Empty the list of USB storage devices in preparation for scanning them.
+ * This must be called before a USB scan.
+ */
+void usb_stor_reset(void);
+
+#else /* !CONFIG_DM_USB */
+
+struct usb_device *usb_get_dev_index(int index);
+
+#endif
+
+bool usb_device_has_child_on_port(struct usb_device *parent, int port);
+
 int usb_hub_probe(struct usb_device *dev, int ifnum);
 void usb_hub_reset(void);
 int hub_port_reset(struct usb_device *dev, int port,