diff options
-rw-r--r-- | drivers/usb/core/usb.c | 112 | ||||
-rw-r--r-- | include/linux/usb.h | 35 |
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 |