]> git.ipfire.org Git - thirdparty/u-boot.git/blobdiff - common/usb.c
Merge tag 'video-20240421' of https://source.denx.de/u-boot/custodians/u-boot-video
[thirdparty/u-boot.git] / common / usb.c
index aad13fd9c5574343ea69dc95e50a7a42ea081574..99e6b857c74ce281431995f2fd41a4328ed9e6b4 100644 (file)
@@ -28,6 +28,7 @@
 #include <common.h>
 #include <command.h>
 #include <dm.h>
+#include <dm/device_compat.h>
 #include <log.h>
 #include <malloc.h>
 #include <memalign.h>
 #define USB_BUFSIZ     512
 
 static int asynch_allowed;
-char usb_started; /* flag for the started/stopped USB status */
+bool usb_started; /* flag for the started/stopped USB status */
 
 #if !CONFIG_IS_ENABLED(DM_USB)
 static struct usb_device usb_dev[USB_MAX_DEVICE];
 static int dev_index;
 
-#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
-#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
-#endif
-
 /***************************************************************************
  * Init USB Device
  */
@@ -1003,6 +1000,17 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
                err = get_descriptor_len(dev, 64, 8);
                if (err)
                        return err;
+
+               /*
+                * Logitech Unifying Receiver 046d:c52b bcdDevice 12.10 seems
+                * sensitive about the first Get Descriptor request. If there
+                * are any other requests in the same microframe, the device
+                * reports bogus data, first of the descriptor parts is not
+                * sent to the host. Wait over one microframe duration here
+                * (1mS for USB 1.x , 125uS for USB 2.0) to avoid triggering
+                * the issue.
+                */
+               mdelay(1);
        }
 
        dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
@@ -1077,6 +1085,54 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
        return 0;
 }
 
+static int usb_device_is_ignored(u16 id_vendor, u16 id_product)
+{
+       ulong vid, pid;
+       char *end;
+       const char *cur = NULL;
+
+       /* ignore list depends on env support */
+       if (!CONFIG_IS_ENABLED(ENV_SUPPORT))
+               return 0;
+
+       cur = env_get("usb_ignorelist");
+
+       /* parse "usb_ignorelist" strictly */
+       while (cur && cur[0] != '\0') {
+               vid = simple_strtoul(cur, &end, 0);
+               /*
+                * If strtoul did not parse a single digit or the next char is
+                * not ':' the ignore list is malformed.
+                */
+               if (cur == end || end[0] != ':')
+                       return -EINVAL;
+
+               cur = end + 1;
+               pid = simple_strtoul(cur, &end, 0);
+               /* Consider '*' as wildcard for the product ID */
+               if (cur == end && end[0] == '*') {
+                       pid = U16_MAX + 1;
+                       end++;
+               }
+               /*
+                * The ignore list is malformed if no product ID / wildcard was
+                * parsed or entries are not separated by ',' or terminated with
+                * '\0'.
+                */
+               if (cur == end || (end[0] != ',' && end[0] != '\0'))
+                       return -EINVAL;
+
+               if (id_vendor == vid && (pid > U16_MAX || id_product == pid))
+                       return -ENODEV;
+
+               if (end[0] == '\0')
+                       break;
+               cur = end + 1;
+       }
+
+       return 0;
+}
+
 int usb_select_config(struct usb_device *dev)
 {
        unsigned char *tmpbuf = NULL;
@@ -1092,6 +1148,27 @@ int usb_select_config(struct usb_device *dev)
        le16_to_cpus(&dev->descriptor.idProduct);
        le16_to_cpus(&dev->descriptor.bcdDevice);
 
+       /* ignore devices from usb_ignorelist */
+       err = usb_device_is_ignored(dev->descriptor.idVendor,
+                                   dev->descriptor.idProduct);
+       if (err == -ENODEV) {
+               debug("Ignoring USB device 0x%x:0x%x\n",
+                       dev->descriptor.idVendor, dev->descriptor.idProduct);
+               return err;
+       } else if (err == -EINVAL) {
+               /*
+                * Continue on "usb_ignorelist" parsing errors. The list is
+                * parsed for each device returning the error would result in
+                * ignoring all USB devices.
+                * Since the parsing error is independent of the probed device
+                * report errors with printf instead of dev_err.
+                */
+               printf("usb_ignorelist parse error in \"%s\"\n",
+                      env_get("usb_ignorelist"));
+       } else if (err < 0) {
+               return err;
+       }
+
        /*
         * Kingston DT Ultimate 32GB USB 3.0 seems to be extremely sensitive
         * about this first Get Descriptor request. If there are any other