| From: Johan Hovold <johan@kernel.org> |
| Date: Mon, 3 Feb 2020 16:38:28 +0100 |
| Subject: USB: core: add endpoint-blacklist quirk |
| |
| 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 | 11 +++++++++++ |
| drivers/usb/core/quirks.c | 32 ++++++++++++++++++++++++++++++++ |
| drivers/usb/core/usb.h | 3 +++ |
| include/linux/usb/quirks.h | 3 +++ |
| 4 files changed, 49 insertions(+) |
| |
| --- a/drivers/usb/core/config.c |
| +++ b/drivers/usb/core/config.c |
| @@ -222,6 +222,7 @@ static int usb_parse_endpoint(struct dev |
| 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 dev |
| 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; |
| |
| --- a/drivers/usb/core/quirks.c |
| +++ b/drivers/usb/core/quirks.c |
| @@ -318,6 +318,38 @@ static const struct usb_device_id usb_am |
| { } /* 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) |
| { |
| --- a/drivers/usb/core/usb.h |
| +++ b/drivers/usb/core/usb.h |
| @@ -29,6 +29,9 @@ extern int usb_deauthorize_device(struct |
| 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, |
| --- a/include/linux/usb/quirks.h |
| +++ b/include/linux/usb/quirks.h |
| @@ -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 */ |