common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / usb / host / usb-uclass.c
index 50538e0bd760461342812df0a162d262e541e0a4..cb79dfbbd5b9aaedbfc49b217f0cab36dcb9e0b3 100644 (file)
@@ -1,24 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2015 Google, Inc
  * Written by Simon Glass <sjg@chromium.org>
  *
  * usb_match_device() modified from Linux kernel v4.0.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
+#include <log.h>
 #include <memalign.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;
 
@@ -26,6 +23,17 @@ struct usb_uclass_priv {
        int companion_device_count;
 };
 
+int usb_lock_async(struct usb_device *udev, int lock)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       if (!ops->lock_async)
+               return -ENOSYS;
+
+       return ops->lock_async(bus, lock);
+}
+
 int usb_disable_asynch(int disable)
 {
        int old_value = asynch_allowed;
@@ -35,7 +43,7 @@ int usb_disable_asynch(int disable)
 }
 
 int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
-                  int length, int interval)
+                  int length, int interval, bool nonblock)
 {
        struct udevice *bus = udev->controller_dev;
        struct dm_usb_ops *ops = usb_get_ops(bus);
@@ -43,7 +51,8 @@ int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
        if (!ops->interrupt)
                return -ENOSYS;
 
-       return ops->interrupt(bus, udev, pipe, buffer, length, interval);
+       return ops->interrupt(bus, udev, pipe, buffer, length, interval,
+                             nonblock);
 }
 
 int submit_control_msg(struct usb_device *udev, unsigned long pipe,
@@ -140,9 +149,32 @@ int usb_reset_root_port(struct usb_device *udev)
        return ops->reset_root_port(bus, udev);
 }
 
+int usb_update_hub_device(struct usb_device *udev)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       if (!ops->update_hub_device)
+               return -ENOSYS;
+
+       return ops->update_hub_device(bus, udev);
+}
+
+int usb_get_max_xfer_size(struct usb_device *udev, size_t *size)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       if (!ops->get_max_xfer_size)
+               return -ENOSYS;
+
+       return ops->get_max_xfer_size(bus, size);
+}
+
 int usb_stop(void)
 {
        struct udevice *bus;
+       struct udevice *rh;
        struct uclass *uc;
        struct usb_uclass_priv *uc_priv;
        int err = 0, ret;
@@ -155,26 +187,26 @@ int usb_stop(void)
        uc_priv = uc->priv;
 
        uclass_foreach_dev(bus, uc) {
-               ret = device_remove(bus);
+               ret = device_remove(bus, DM_REMOVE_NORMAL);
                if (ret && !err)
                        err = ret;
-       }
-
-#ifdef CONFIG_SANDBOX
-       struct udevice *dev;
 
-       /* Reset all enulation devices */
-       ret = uclass_get(UCLASS_USB_EMUL, &uc);
-       if (ret)
-               return ret;
+               /* Locate root hub device */
+               device_find_first_child(bus, &rh);
+               if (rh) {
+                       /*
+                        * All USB devices are children of root hub.
+                        * Unbinding root hub will unbind all of its children.
+                        */
+                       ret = device_unbind(rh);
+                       if (ret && !err)
+                               err = ret;
+               }
+       }
 
-       uclass_foreach_dev(dev, uc)
-               usb_emul_reset(dev);
-#endif
 #ifdef CONFIG_USB_STORAGE
        usb_stor_reset();
 #endif
-       usb_hub_reset();
        uc_priv->companion_device_count = 0;
        usb_started = 0;
 
@@ -191,7 +223,7 @@ static void usb_scan_bus(struct udevice *bus, bool recurse)
 
        assert(recurse);        /* TODO: Support non-recusive */
 
-       printf("scanning bus %d for devices... ", bus->seq);
+       printf("scanning bus %s for devices... ", bus->name);
        debug("\n");
        ret = usb_scan_device(bus, 0, USB_SPEED_FULL, &dev);
        if (ret)
@@ -223,11 +255,9 @@ int usb_init(void)
        struct usb_bus_priv *priv;
        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)
@@ -237,8 +267,22 @@ int usb_init(void)
 
        uclass_foreach_dev(bus, uc) {
                /* init low_level USB */
-               printf("USB%d:   ", count);
-               count++;
+               printf("Bus %s: ", bus->name);
+
+#ifdef CONFIG_SANDBOX
+               /*
+                * For Sandbox, we need scan the device tree each time when we
+                * start the USB stack, in order to re-create the emulated USB
+                * devices and bind drivers for them before we actually do the
+                * driver probe.
+                */
+               ret = dm_scan_fdt_dev(bus);
+               if (ret) {
+                       printf("Sandbox USB device scan failed (%d)\n", ret);
+                       continue;
+               }
+#endif
+
                ret = device_probe(bus);
                if (ret == -ENODEV) {   /* No such device. */
                        puts("Port not available.\n");
@@ -294,10 +338,8 @@ int usb_init(void)
        remove_inactive_children(uc, bus);
 
        /* 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");
+       if (controllers_initialized == 0)
+               printf("No working controllers found\n");
 
        return usb_started ? 0 : -1;
 }
@@ -345,12 +387,6 @@ struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
 }
 #endif
 
-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_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
 {
        struct usb_platdata *plat;
@@ -361,7 +397,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
        ret = uclass_find_device_by_seq(UCLASS_USB, 0, true, &dev);
        if (ret)
                return ret;
-       ret = device_remove(dev);
+       ret = device_remove(dev, DM_REMOVE_NORMAL);
        if (ret)
                return ret;
 
@@ -376,8 +412,8 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
 }
 
 /* returns 0 if no match, 1 if match */
-int usb_match_device(const struct usb_device_descriptor *desc,
-                    const struct usb_device_id *id)
+static int usb_match_device(const struct usb_device_descriptor *desc,
+                           const struct usb_device_id *id)
 {
        if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
            id->idVendor != le16_to_cpu(desc->idVendor))
@@ -413,9 +449,9 @@ int usb_match_device(const struct usb_device_descriptor *desc,
 }
 
 /* returns 0 if no match, 1 if match */
-int usb_match_one_id_intf(const struct usb_device_descriptor *desc,
-                         const struct usb_interface_descriptor *int_desc,
-                         const struct usb_device_id *id)
+static int usb_match_one_id_intf(const struct usb_device_descriptor *desc,
+                       const struct usb_interface_descriptor *int_desc,
+                       const struct usb_device_id *id)
 {
        /* The interface class, subclass, protocol and number should never be
         * checked for a match if the device class is Vendor Specific,
@@ -448,9 +484,9 @@ int usb_match_one_id_intf(const struct usb_device_descriptor *desc,
 }
 
 /* returns 0 if no match, 1 if match */
-int usb_match_one_id(struct usb_device_descriptor *desc,
-                    struct usb_interface_descriptor *int_desc,
-                    const struct usb_device_id *id)
+static int usb_match_one_id(struct usb_device_descriptor *desc,
+                           struct usb_interface_descriptor *int_desc,
+                           const struct usb_device_id *id)
 {
        if (!usb_match_device(desc, id))
                return 0;
@@ -683,22 +719,21 @@ int usb_detect_change(void)
        return change;
 }
 
-int usb_child_post_bind(struct udevice *dev)
+static 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)
+       if (!dev_of_valid(dev))
                return 0;
 
        /* We only support matching a few things */
-       val = fdtdec_get_int(blob, dev->of_offset, "usb,device-class", -1);
+       val = dev_read_u32_default(dev, "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);
+       val = dev_read_u32_default(dev, "usb,interface-class", -1);
        if (val != -1) {
                plat->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
                plat->id.bInterfaceClass = val;
@@ -764,7 +799,7 @@ UCLASS_DRIVER(usb) = {
        .id             = UCLASS_USB,
        .name           = "usb",
        .flags          = DM_UC_FLAG_SEQ_ALIAS,
-       .post_bind      = usb_post_bind,
+       .post_bind      = dm_scan_fdt_dev,
        .priv_auto_alloc_size = sizeof(struct usb_uclass_priv),
        .per_child_auto_alloc_size = sizeof(struct usb_device),
        .per_device_auto_alloc_size = sizeof(struct usb_bus_priv),