|
@@ -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
|