mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
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: Johan Hovold <johan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
96cfcc9c46
commit
66a359390e
2 changed files with 118 additions and 0 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue