]> Git Repo - J-u-boot.git/blobdiff - drivers/usb/host/usb-uclass.c
dm: treewide: Rename ..._platdata variables to just ..._plat
[J-u-boot.git] / drivers / usb / host / usb-uclass.c
index d8d74bd04bb4c1d5ada5aaf7981328c020260a77..decee61d96b970ea72bd0ff75ce0fe64ff9416c5 100644 (file)
@@ -1,23 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2015 Google, Inc
  * Written by Simon Glass <[email protected]>
  *
  * 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/uclass-internal.h>
 
-DECLARE_GLOBAL_DATA_PTR;
-
 extern bool usb_started; /* flag for the started/stopped USB status */
 static bool asynch_allowed;
 
@@ -25,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;
@@ -34,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);
@@ -42,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,
@@ -139,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;
@@ -157,23 +190,20 @@ int usb_stop(void)
                ret = device_remove(bus, DM_REMOVE_NORMAL);
                if (ret && !err)
                        err = ret;
-       }
-#ifdef CONFIG_BLK
-       ret = blk_unbind_all(IF_TYPE_USB);
-       if (ret && !err)
-               err = ret;
-#endif
-#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
@@ -193,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)
@@ -225,7 +255,6 @@ int usb_init(void)
        struct usb_bus_priv *priv;
        struct udevice *bus;
        struct uclass *uc;
-       int count = 0;
        int ret;
 
        asynch_allowed = 1;
@@ -238,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");
@@ -295,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;
 }
@@ -348,7 +389,7 @@ struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
 
 int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
 {
-       struct usb_platdata *plat;
+       struct usb_plat *plat;
        struct udevice *dev;
        int ret;
 
@@ -360,7 +401,7 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
        if (ret)
                return ret;
 
-       plat = dev_get_platdata(dev);
+       plat = dev_get_plat(dev);
        plat->init_type = USB_INIT_DEVICE;
        ret = device_probe(dev);
        if (ret)
@@ -370,26 +411,44 @@ int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
        return 0;
 }
 
+int usb_remove_ehci_gadget(struct ehci_ctrl **ctlrp)
+{
+       struct udevice *dev;
+       int ret;
+
+       /* Find the old device and remove it */
+       ret = uclass_find_device_by_seq(UCLASS_USB, 0, true, &dev);
+       if (ret)
+               return ret;
+       ret = device_remove(dev, DM_REMOVE_NORMAL);
+       if (ret)
+               return ret;
+
+       *ctlrp = NULL;
+
+       return 0;
+}
+
 /* returns 0 if no match, 1 if match */
 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))
+           id->idVendor != desc->idVendor)
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
-           id->idProduct != le16_to_cpu(desc->idProduct))
+           id->idProduct != desc->idProduct)
                return 0;
 
        /* No need to test id->bcdDevice_lo != 0, since 0 is never
           greater than any unsigned number. */
        if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
-           (id->bcdDevice_lo > le16_to_cpu(desc->bcdDevice)))
+           (id->bcdDevice_lo > desc->bcdDevice))
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
-           (id->bcdDevice_hi < le16_to_cpu(desc->bcdDevice)))
+           (id->bcdDevice_hi < desc->bcdDevice))
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
@@ -453,6 +512,35 @@ static int usb_match_one_id(struct usb_device_descriptor *desc,
        return usb_match_one_id_intf(desc, int_desc, id);
 }
 
+static ofnode usb_get_ofnode(struct udevice *hub, int port)
+{
+       ofnode node;
+       u32 reg;
+
+       if (!dev_has_of_node(hub))
+               return ofnode_null();
+
+       /*
+        * The USB controller and its USB hub are two different udevices,
+        * but the device tree has only one node for both. Thus we are
+        * assigning this node to both udevices.
+        * If port is zero, the controller scans its root hub, thus we
+        * are using the same ofnode as the controller here.
+        */
+       if (!port)
+               return dev_ofnode(hub);
+
+       ofnode_for_each_subnode(node, dev_ofnode(hub)) {
+               if (ofnode_read_u32(node, "reg", &reg))
+                       continue;
+
+               if (reg == port)
+                       return node;
+       }
+
+       return ofnode_null();
+}
+
 /**
  * usb_find_and_bind_driver() - Find and bind the right USB driver
  *
@@ -461,13 +549,14 @@ static int usb_match_one_id(struct usb_device_descriptor *desc,
 static int usb_find_and_bind_driver(struct udevice *parent,
                                    struct usb_device_descriptor *desc,
                                    struct usb_interface_descriptor *iface,
-                                   int bus_seq, int devnum,
+                                   int bus_seq, int devnum, int port,
                                    struct udevice **devp)
 {
        struct usb_driver_entry *start, *entry;
        int n_ents;
        int ret;
        char name[30], *str;
+       ofnode node = usb_get_ofnode(parent, port);
 
        *devp = NULL;
        debug("%s: Searching for driver\n", __func__);
@@ -477,7 +566,7 @@ static int usb_find_and_bind_driver(struct udevice *parent,
                const struct usb_device_id *id;
                struct udevice *dev;
                const struct driver *drv;
-               struct usb_dev_platdata *plat;
+               struct usb_dev_plat *plat;
 
                for (id = entry->match; id->match_flags; id++) {
                        if (!usb_match_one_id(desc, iface, id))
@@ -486,19 +575,19 @@ static int usb_find_and_bind_driver(struct udevice *parent,
                        drv = entry->driver;
                        /*
                         * We could pass the descriptor to the driver as
-                        * platdata (instead of NULL) and allow its bind()
+                        * plat (instead of NULL) and allow its bind()
                         * method to return -ENOENT if it doesn't support this
                         * device. That way we could continue the search to
                         * find another driver. For now this doesn't seem
                         * necesssary, so just bind the first match.
                         */
-                       ret = device_bind(parent, drv, drv->name, NULL, -1,
+                       ret = device_bind(parent, drv, drv->name, NULL, node,
                                          &dev);
                        if (ret)
                                goto error;
                        debug("%s: Match found: %s\n", __func__, drv->name);
                        dev->driver_data = id->driver_info;
-                       plat = dev_get_parent_platdata(dev);
+                       plat = dev_get_parent_plat(dev);
                        plat->id = *id;
                        *devp = dev;
                        return 0;
@@ -533,7 +622,7 @@ static int usb_find_child(struct udevice *parent,
        for (device_find_first_child(parent, &dev);
             dev;
             device_find_next_child(&dev)) {
-               struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+               struct usb_dev_plat *plat = dev_get_parent_plat(dev);
 
                /* If this device is already in use, skip it */
                if (device_active(dev))
@@ -554,7 +643,7 @@ int usb_scan_device(struct udevice *parent, int port,
 {
        struct udevice *dev;
        bool created = false;
-       struct usb_dev_platdata *plat;
+       struct usb_dev_plat *plat;
        struct usb_bus_priv *priv;
        struct usb_device *parent_udev;
        int ret;
@@ -610,14 +699,15 @@ int usb_scan_device(struct udevice *parent, int port,
        if (ret) {
                if (ret != -ENOENT)
                        return ret;
-               ret = usb_find_and_bind_driver(parent, &udev->descriptor, iface,
+               ret = usb_find_and_bind_driver(parent, &udev->descriptor,
+                                              iface,
                                               udev->controller_dev->seq,
-                                              udev->devnum, &dev);
+                                              udev->devnum, port, &dev);
                if (ret)
                        return ret;
                created = true;
        }
-       plat = dev_get_parent_platdata(dev);
+       plat = dev_get_parent_plat(dev);
        debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat);
        plat->devnum = udev->devnum;
        plat->udev = udev;
@@ -680,7 +770,7 @@ int usb_detect_change(void)
 
 static int usb_child_post_bind(struct udevice *dev)
 {
-       struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+       struct usb_dev_plat *plat = dev_get_parent_plat(dev);
        int val;
 
        if (!dev_of_valid(dev))
@@ -719,7 +809,7 @@ struct udevice *usb_get_bus(struct udevice *dev)
 int usb_child_pre_probe(struct udevice *dev)
 {
        struct usb_device *udev = dev_get_parent_priv(dev);
-       struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+       struct usb_dev_plat *plat = dev_get_parent_plat(dev);
        int ret;
 
        if (plat->udev) {
@@ -759,12 +849,12 @@ UCLASS_DRIVER(usb) = {
        .name           = "usb",
        .flags          = DM_UC_FLAG_SEQ_ALIAS,
        .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),
+       .priv_auto      = sizeof(struct usb_uclass_priv),
+       .per_child_auto = sizeof(struct usb_device),
+       .per_device_auto        = 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),
+       .per_child_plat_auto    = sizeof(struct usb_dev_plat),
 };
 
 UCLASS_DRIVER(usb_dev_generic) = {
This page took 0.040484 seconds and 4 git commands to generate.