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", ®))
+ continue;
+
+ if (reg == port)
+ return node;
+ }
+
+ return ofnode_null();
+}
+
/**
* usb_find_and_bind_driver() - Find and bind the right USB driver
*
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__);
* 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);
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;
}
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;