summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sandbox/dts/test.dts9
-rw-r--r--drivers/usb/host/usb-uclass.c41
-rw-r--r--test/dm/usb.c22
3 files changed, 67 insertions, 5 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 5ce5e28476..b9255e4593 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -810,6 +810,8 @@
hub {
compatible = "usb-hub";
usb,device-class = <9>;
+ #address-cells = <1>;
+ #size-cells = <0>;
hub-emul {
compatible = "sandbox,usb-hub";
#address-cells = <1>;
@@ -838,6 +840,13 @@
};
};
+
+ usbstor@1 {
+ reg = <1>;
+ };
+ usbstor@3 {
+ reg = <3>;
+ };
};
};
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index cb79dfbbd5..f42c0625cb 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -494,6 +494,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
*
@@ -502,13 +531,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__);
@@ -533,8 +563,8 @@ static int usb_find_and_bind_driver(struct udevice *parent,
* 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,
- &dev);
+ ret = device_bind_ofnode(parent, drv, drv->name, NULL,
+ node, &dev);
if (ret)
goto error;
debug("%s: Match found: %s\n", __func__, drv->name);
@@ -651,9 +681,10 @@ 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;
diff --git a/test/dm/usb.c b/test/dm/usb.c
index a25c2c1482..b273a515ef 100644
--- a/test/dm/usb.c
+++ b/test/dm/usb.c
@@ -78,6 +78,28 @@ static int dm_test_usb_multi(struct unit_test_state *uts)
}
DM_TEST(dm_test_usb_multi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* test that we have an associated ofnode with the usb device */
+static int dm_test_usb_fdt_node(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ ofnode node;
+
+ state_set_skip_delays(true);
+ ut_assertok(usb_init());
+ ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &dev));
+ node = ofnode_path("/usb@1/hub/usbstor@1");
+ ut_asserteq(1, ofnode_equal(node, dev_ofnode(dev)));
+ ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 1, &dev));
+ ut_asserteq(1, ofnode_equal(ofnode_null(), dev_ofnode(dev)));
+ ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 2, &dev));
+ node = ofnode_path("/usb@1/hub/usbstor@3");
+ ut_asserteq(1, ofnode_equal(node, dev_ofnode(dev)));
+ ut_assertok(usb_stop());
+
+ return 0;
+}
+DM_TEST(dm_test_usb_fdt_node, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
static int count_usb_devices(void)
{
struct udevice *hub;