Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66a35939 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

USB: core: add helpers to retrieve endpoints



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: default avatarJohan Hovold <johan@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 96cfcc9c
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -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.
+35 −0
Original line number Diff line number Diff line
@@ -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