summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/usb.c112
-rw-r--r--include/linux/usb.h35
2 files changed, 111 insertions, 36 deletions
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 5d65504770f5..1ec9d248781e 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -74,6 +74,48 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
#define usb_autosuspend_delay 0
#endif
+static bool match_endpoint(struct usb_endpoint_descriptor *epd,
+ struct usb_endpoint_descriptor **bulk_in,
+ struct usb_endpoint_descriptor **bulk_out,
+ struct usb_endpoint_descriptor **int_in,
+ struct usb_endpoint_descriptor **int_out)
+{
+ 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;
+ }
+ }
+
+ return false;
+ 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;
+ }
+ }
+
+ return false;
+ default:
+ return false;
+ }
+
+ return (!bulk_in || *bulk_in) && (!bulk_out || *bulk_out) &&
+ (!int_in || *int_in) && (!int_out || *int_out);
+}
/**
* usb_find_common_endpoints() -- look up common endpoint descriptors
@@ -113,50 +155,48 @@ int usb_find_common_endpoints(struct usb_host_interface *alt,
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;
- }
- }
+ if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
+ return 0;
+ }
- 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;
- }
- }
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
- continue;
- default:
- continue;
- }
+/**
+ * usb_find_common_endpoints_reverse() -- look up common endpoint descriptors
+ *
+ * Same as usb_find_common_endpoints(), but the endpoint descriptors are
+ * searched in reverse order (see usb_find_common_endpoints() for details).
+ */
+int usb_find_common_endpoints_reverse(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 = alt->desc.bNumEndpoints - 1; i >= 0; --i) {
+ epd = &alt->endpoint[i].desc;
- if ((!bulk_in || *bulk_in) &&
- (!bulk_out || *bulk_out) &&
- (!int_in || *int_in) &&
- (!int_out || *int_out)) {
+ if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
return 0;
- }
}
return -ENXIO;
}
-EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
+EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
/**
* usb_find_alt_setting() - Given a configuration, find the alternate setting
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7041cc950737..226557362d36 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -106,6 +106,13 @@ usb_find_common_endpoints(struct usb_host_interface *alt,
struct usb_endpoint_descriptor **int_in,
struct usb_endpoint_descriptor **int_out);
+int __must_check
+usb_find_common_endpoints_reverse(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)
@@ -134,6 +141,34 @@ usb_find_int_out_endpoint(struct usb_host_interface *alt,
return usb_find_common_endpoints(alt, NULL, NULL, NULL, int_out);
}
+static inline int __must_check
+usb_find_last_bulk_in_endpoint(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **bulk_in)
+{
+ return usb_find_common_endpoints_reverse(alt, bulk_in, NULL, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_last_bulk_out_endpoint(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **bulk_out)
+{
+ return usb_find_common_endpoints_reverse(alt, NULL, bulk_out, NULL, NULL);
+}
+
+static inline int __must_check
+usb_find_last_int_in_endpoint(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **int_in)
+{
+ return usb_find_common_endpoints_reverse(alt, NULL, NULL, int_in, NULL);
+}
+
+static inline int __must_check
+usb_find_last_int_out_endpoint(struct usb_host_interface *alt,
+ struct usb_endpoint_descriptor **int_out)
+{
+ return usb_find_common_endpoints_reverse(alt, NULL, NULL, NULL, int_out);
+}
+
/**
* struct usb_interface - what usb device drivers talk to
* @altsetting: array of interface structures, one for each alternate