+ /* 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)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+ (id->bcdDevice_hi < le16_to_cpu(desc->bcdDevice)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+ (id->bDeviceClass != desc->bDeviceClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+ (id->bDeviceSubClass != desc->bDeviceSubClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+ (id->bDeviceProtocol != desc->bDeviceProtocol))
+ return 0;
+
+ return 1;
+}
+
+/* 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)
+{
+ /* The interface class, subclass, protocol and number should never be
+ * checked for a match if the device class is Vendor Specific,
+ * unless the match record specifies the Vendor ID. */
+ if (desc->bDeviceClass == USB_CLASS_VENDOR_SPEC &&
+ !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+ USB_DEVICE_ID_MATCH_INT_NUMBER)))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+ (id->bInterfaceClass != int_desc->bInterfaceClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
+ (id->bInterfaceSubClass != int_desc->bInterfaceSubClass))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
+ (id->bInterfaceProtocol != int_desc->bInterfaceProtocol))
+ return 0;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+ (id->bInterfaceNumber != int_desc->bInterfaceNumber))
+ return 0;
+
+ return 1;
+}
+
+/* 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)
+{
+ if (!usb_match_device(desc, id))
+ return 0;
+
+ return usb_match_one_id_intf(desc, int_desc, id);
+}
+
+/**
+ * usb_find_and_bind_driver() - Find and bind the right USB driver
+ *
+ * This only looks at certain fields in the descriptor.
+ */
+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,
+ struct udevice **devp)
+{
+ struct usb_driver_entry *start, *entry;
+ int n_ents;
+ int ret;
+ char name[30], *str;
+
+ *devp = NULL;
+ debug("%s: Searching for driver\n", __func__);
+ start = ll_entry_start(struct usb_driver_entry, usb_driver_entry);
+ n_ents = ll_entry_count(struct usb_driver_entry, usb_driver_entry);
+ for (entry = start; entry != start + n_ents; entry++) {
+ const struct usb_device_id *id;
+ struct udevice *dev;
+ const struct driver *drv;
+ struct usb_dev_platdata *plat;
+
+ for (id = entry->match; id->match_flags; id++) {
+ if (!usb_match_one_id(desc, iface, id))
+ continue;
+
+ drv = entry->driver;
+ /*
+ * We could pass the descriptor to the driver as
+ * platdata (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,
+ &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->id = *id;
+ *devp = dev;
+ return 0;