diff options
author | Janne Grunau | 2024-04-04 08:25:52 +0200 |
---|---|---|
committer | Marek Vasut | 2024-04-12 14:53:13 +0200 |
commit | 18f288b8d48331d6d7391486d7fa355d3bfd2a9c (patch) | |
tree | 97250fae38b9587ada324c2f052a40b6ea3eddd5 /common | |
parent | 0b6775c40283dd645a28b30cafa9d8cc19dc34aa (diff) |
usb: Add environment based device ignorelist
Add the environment variable "usb_ignorelist" to prevent USB devices
listed in it from being bound to drivers. This allows to ignore devices
which are undesirable or trigger bugs in u-boot's USB stack.
Devices emulating keyboards are one example of undesirable devices as
u-boot currently supports only a single USB keyboard device. Most
commonly, people run into this with Yubikeys, so let's ignore those in
the default environment.
Based on previous USB keyboard specific patches for the same purpose.
Link: https://lore.kernel.org/u-boot/7ab604fb-0fec-4f5e-8708-7a3a7e2cb568@denx.de/
Reviewed-by: Neal Gompa <neal@gompa.dev>
Reviewed-by: Marek Vasut <marex@denx.de>
Signed-off-by: Janne Grunau <j@jannau.net>
Diffstat (limited to 'common')
-rw-r--r-- | common/usb.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/common/usb.c b/common/usb.c index 836506dcd9e..99e6b857c74 100644 --- a/common/usb.c +++ b/common/usb.c @@ -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> @@ -1084,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; @@ -1099,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 |