]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
USB: core: add helpers to retrieve endpoints
authorJohan Hovold <johan@kernel.org>
Fri, 17 Mar 2017 10:35:30 +0000 (11:35 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Mar 2017 12:53:16 +0000 (13:53 +0100)
Many USB drivers iterate over the available endpoints to find required
endpoints of a specific type and direction. Typically the endpoints are
required for proper function and a missing endpoint should abort probe.

To facilitate code reuse, add a helper to retrieve common endpoints
(bulk or interrupt, in or out) and four wrappers to find a single
endpoint.

Note that the helpers are marked as __must_check to serve as a reminder
to always verify that all expected endpoints are indeed present. This
also means that any optional endpoints, typically need to be looked up
through separate calls.

Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/usb.c
include/linux/usb.h

index 4cd6e0e4b66d9a20ecef24ec8442ed8df9125e1a..5d65504770f5c3d0e260e792cc1d6f77b4177025 100644 (file)
@@ -75,6 +75,89 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
 #endif
 
 
+/**
+ * usb_find_common_endpoints() -- look up common endpoint descriptors
+ * @alt:       alternate setting to search
+ * @bulk_in:   pointer to descriptor pointer, or NULL
+ * @bulk_out:  pointer to descriptor pointer, or NULL
+ * @int_in:    pointer to descriptor pointer, or NULL
+ * @int_out:   pointer to descriptor pointer, or NULL
+ *
+ * Search the alternate setting's endpoint descriptors for the first bulk-in,
+ * bulk-out, interrupt-in and interrupt-out endpoints and return them in the
+ * provided pointers (unless they are NULL).
+ *
+ * If a requested endpoint is not found, the corresponding pointer is set to
+ * NULL.
+ *
+ * Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
+ */
+int usb_find_common_endpoints(struct usb_host_interface *alt,
+               struct usb_endpoint_descriptor **bulk_in,
+               struct usb_endpoint_descriptor **bulk_out,
+               struct usb_endpoint_descriptor **int_in,
+               struct usb_endpoint_descriptor **int_out)
+{
+       struct usb_endpoint_descriptor *epd;
+       int i;
+
+       if (bulk_in)
+               *bulk_in = NULL;
+       if (bulk_out)
+               *bulk_out = NULL;
+       if (int_in)
+               *int_in = NULL;
+       if (int_out)
+               *int_out = NULL;
+
+       for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
+               epd = &alt->endpoint[i].desc;
+
+               switch (usb_endpoint_type(epd)) {
+               case USB_ENDPOINT_XFER_BULK:
+                       if (usb_endpoint_dir_in(epd)) {
+                               if (bulk_in && !*bulk_in) {
+                                       *bulk_in = epd;
+                                       break;
+                               }
+                       } else {
+                               if (bulk_out && !*bulk_out) {
+                                       *bulk_out = epd;
+                                       break;
+                               }
+                       }
+
+                       continue;
+               case USB_ENDPOINT_XFER_INT:
+                       if (usb_endpoint_dir_in(epd)) {
+                               if (int_in && !*int_in) {
+                                       *int_in = epd;
+                                       break;
+                               }
+                       } else {
+                               if (int_out && !*int_out) {
+                                       *int_out = epd;
+                                       break;
+                               }
+                       }
+
+                       continue;
+               default:
+                       continue;
+               }
+
+               if ((!bulk_in || *bulk_in) &&
+                               (!bulk_out || *bulk_out) &&
+                               (!int_in || *int_in) &&
+                               (!int_out || *int_out)) {
+                       return 0;
+               }
+       }
+
+       return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
+
 /**
  * usb_find_alt_setting() - Given a configuration, find the alternate setting
  * for the given interface.
index 14875264069392faf7884ac1d4a4ceb251ea713b..7041cc9507370a6934f5b3cbbab6619b76984120 100644 (file)
@@ -99,6 +99,41 @@ enum usb_interface_condition {
        USB_INTERFACE_UNBINDING,
 };
 
+int __must_check
+usb_find_common_endpoints(struct usb_host_interface *alt,
+               struct usb_endpoint_descriptor **bulk_in,
+               struct usb_endpoint_descriptor **bulk_out,
+               struct usb_endpoint_descriptor **int_in,
+               struct usb_endpoint_descriptor **int_out);
+
+static inline int __must_check
+usb_find_bulk_in_endpoint(struct usb_host_interface *alt,
+               struct usb_endpoint_descriptor **bulk_in)
+{
+       return usb_find_common_endpoints(alt, bulk_in, NULL, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_bulk_out_endpoint(struct usb_host_interface *alt,
+               struct usb_endpoint_descriptor **bulk_out)
+{
+       return usb_find_common_endpoints(alt, NULL, bulk_out, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_int_in_endpoint(struct usb_host_interface *alt,
+               struct usb_endpoint_descriptor **int_in)
+{
+       return usb_find_common_endpoints(alt, NULL, NULL, int_in, NULL);
+}
+
+static inline int __must_check
+usb_find_int_out_endpoint(struct usb_host_interface *alt,
+               struct usb_endpoint_descriptor **int_out)
+{
+       return usb_find_common_endpoints(alt, NULL, NULL, NULL, int_out);
+}
+
 /**
  * struct usb_interface - what usb device drivers talk to
  * @altsetting: array of interface structures, one for each alternate