]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
USB: core: add endpoint-blacklist quirk
authorJohan Hovold <johan@kernel.org>
Mon, 3 Feb 2020 15:38:28 +0000 (16:38 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Tue, 28 Apr 2020 18:03:11 +0000 (19:03 +0100)
commit 73f8bda9b5dc1c69df2bc55c0cbb24461a6391a9 upstream.

Add a new device quirk that can be used to blacklist endpoints.

Since commit 3e4f8e21c4f2 ("USB: core: fix check for duplicate
endpoints") USB core ignores any duplicate endpoints found during
descriptor parsing.

In order to handle devices where the first interfaces with duplicate
endpoints are the ones that should have their endpoints ignored, we need
to add a blacklist.

Tested-by: edes <edes@gmx.net>
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://lore.kernel.org/r/20200203153830.26394-2-johan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/usb/core/config.c
drivers/usb/core/quirks.c
drivers/usb/core/usb.h
include/linux/usb/quirks.h

index 41ec4ecda179ca03896532ee39dcf800ced19d41..4722b6a93a89de5defd0eb3201acb2b6f53a82b1 100644 (file)
@@ -222,6 +222,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
                struct usb_host_interface *ifp, int num_ep,
                unsigned char *buffer, int size)
 {
+       struct usb_device *udev = to_usb_device(ddev);
        unsigned char *buffer0 = buffer;
        struct usb_endpoint_descriptor *d;
        struct usb_host_endpoint *endpoint;
@@ -263,6 +264,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
                goto skip_to_next_endpoint_or_interface_descriptor;
        }
 
+       /* Ignore blacklisted endpoints */
+       if (udev->quirks & USB_QUIRK_ENDPOINT_BLACKLIST) {
+               if (usb_endpoint_is_blacklisted(udev, ifp, d)) {
+                       dev_warn(ddev, "config %d interface %d altsetting %d has a blacklisted endpoint with address 0x%X, skipping\n",
+                                       cfgno, inum, asnum,
+                                       d->bEndpointAddress);
+                       goto skip_to_next_endpoint_or_interface_descriptor;
+               }
+       }
+
        endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
        ++ifp->desc.bNumEndpoints;
 
index 33772a954df676bd57b6b61d6d0351108b34dbda..46e7d548020fc76f1ba0723f31b2a517d493944e 100644 (file)
@@ -318,6 +318,38 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = {
        { }  /* terminating entry must be last */
 };
 
+/*
+ * Entries for blacklisted endpoints that should be ignored when parsing
+ * configuration descriptors.
+ *
+ * Matched for devices with USB_QUIRK_ENDPOINT_BLACKLIST.
+ */
+static const struct usb_device_id usb_endpoint_blacklist[] = {
+       { }
+};
+
+bool usb_endpoint_is_blacklisted(struct usb_device *udev,
+               struct usb_host_interface *intf,
+               struct usb_endpoint_descriptor *epd)
+{
+       const struct usb_device_id *id;
+       unsigned int address;
+
+       for (id = usb_endpoint_blacklist; id->match_flags; ++id) {
+               if (!usb_match_device(udev, id))
+                       continue;
+
+               if (!usb_match_one_id_intf(udev, intf, id))
+                       continue;
+
+               address = id->driver_info;
+               if (address == epd->bEndpointAddress)
+                       return true;
+       }
+
+       return false;
+}
+
 static bool usb_match_any_interface(struct usb_device *udev,
                                    const struct usb_device_id *id)
 {
index d7ac1603826b8f24030efb60d32413056f51d71a..283de7f3840ee52d97d0dac035bc3d1b40b94ab7 100644 (file)
@@ -29,6 +29,9 @@ extern int usb_deauthorize_device(struct usb_device *);
 extern int usb_authorize_device(struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 extern void usb_detect_interface_quirks(struct usb_device *udev);
+extern bool usb_endpoint_is_blacklisted(struct usb_device *udev,
+               struct usb_host_interface *intf,
+               struct usb_endpoint_descriptor *epd);
 extern int usb_remove_device(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
index efc4e51c425a4ce271bcc9fe4b2134b17d490db2..b0a25fdfb1bedbf0b6eea75b1c95e8cacfe6d447 100644 (file)
@@ -62,4 +62,7 @@
 /* Hub needs extra delay after resetting its port. */
 #define USB_QUIRK_HUB_SLOW_RESET               BIT(14)
 
+/* device has blacklisted endpoints */
+#define USB_QUIRK_ENDPOINT_BLACKLIST           BIT(15)
+
 #endif /* __LINUX_USB_QUIRKS_H */